#include "lsmem.h" #include "lstxtcmp.h" #include "lstxtmod.h" #include "lstxtmap.h" #include "lschp.h" #include "lspract.h" #include "lsems.h" #include "txtils.h" #include "txtln.h" #include "txtobj.h" #define min(a,b) ((a) > (b) ? (b) : (a)) #define max(a,b) ((a) < (b) ? (b) : (a)) typedef struct { long rgdurPrior[2]; long rgcExpPrior[2]; long cExpOppr; } EXPINFO; typedef struct { long durComp; long cCompOppr; } COMPINFO; static LSERR GetExpandInfo(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, BOOL fScaled, long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLim, EXPINFO* pexpinfo); static void GetCompressInfo(const LSGRCHNK* plsgrchnk, long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLim, COMPINFO* pcompinfo); static LSERR CheckExpandSpace(PILSOBJ pilsobj, LSEMS* plsems, long iwchPrev, long iwch, long iwchNext, PTXTOBJ ptxtobjCur, PLSRUN plsrunPrev, PLSRUN plsrunCur, PLSRUN plsrunNext, BOOL* pfExpandOpp, long* pdurChange); static LSERR CheckExpandOnRun(PILSOBJ pilsobj, LSEMS* plsems, long iwch, long iwchNext, PTXTOBJ ptxtobjCur, PLSRUN plsrunCur, PLSRUN plsrunNext, BOOL* pfExpandOpp, long* pdurChange); static void ApplyPriorCompression(const LSGRCHNK* plsgrchnk, long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLim, BYTE prior, long durToCompress, long durAvailable, long cExpOppr); static void ApplyPriorExpansion(const LSGRCHNK* plsgrchnk, long itxtobjFirst, long iwchFirst, long txtobjLast, long iwchLim, BYTE prior, long durToExpand, long durAvailable, long cExpOppr); static void ApplyFullExpansion(const LSGRCHNK* plsgrchnk, long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLim, long durToExpand, long cExpOppr, long cNonText, long* pdurNonText); static LSERR CheckCompSpace(PILSOBJ pilsobj, LSEMS* plsems, long iwchPrev, long iwch, long iwchNext, PTXTOBJ ptxtobjCur, PLSRUN plsrunPrev, PLSRUN plsrunCur, PLSRUN plsrunNext, long* pdurChange); static LSERR CheckCompOnRun(PILSOBJ pilsobj, LSEMS* plsems, long iwch, long iwchNext, PTXTOBJ ptxtobjCur, PLSRUN plsrunCur, PLSRUN plsrunNext, long* pdurChange); static void SetComp(PILSOBJ pilsobj, long iwch, BYTE prior, BYTE side, long durChange); static BOOL GetNextRun(const LSGRCHNK* plsgrchnk, long itxtobj, long* pitxtobjNext); static void GetPrevCharRun(const LSGRCHNK* plsgrchnk, long itxtobj, long iwch, long* piwchPrev, PLSRUN* pplsrunPrev); /* F E T C H C O M P R E S S I N F O */ /*---------------------------------------------------------------------------- %%Function: FetchCompressInfo %%Contact: sergeyge Fetches compression information until durCompressMaxStop exceeded ---------------------------------------------------------------------------*/ LSERR FetchCompressInfo(const LSGRCHNK* plsgrchnk, BOOL fFirstOnLine, LSTFLOW lstflow, long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLim, long durCompressMaxStop, long* pdurCompressTotal) { LSERR lserr; PILSOBJ pilsobj; TXTINF* rgtxtinf; WCHAR* rgwchOrig; PTXTOBJ ptxtobj; PLSRUN plsrunCur; PLSRUN plsrunPrev; PLSRUN plsrunNext = NULL; PCLSCHP plschp; LSPRACT lspract; BYTE side; BYTE sideFinal; long durChange; long durTemp; LSEMS lsems; BOOL fNextAdjacentFound; long itxtobj; long itxtobjNext; long itxtobjLastProcessed; long itxtobjCompressFetchedLim; long iwchCompressFetchedLim; long iwchLimDobj; long iwch; long iwchPrev; long iwchNext; BOOL fGlyphBased; *pdurCompressTotal = 0; pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pilsobj; rgtxtinf = pilsobj->ptxtinf; /* rgtxtinf == NULL means that there were no runs which possibly could introduce compress opportunity */ if (rgtxtinf == NULL) return lserrNone; iwch = iwchFirst; rgwchOrig = pilsobj->pwchOrig; itxtobjCompressFetchedLim = 0; iwchCompressFetchedLim = 0; if (pilsobj->iwchCompressFetchedFirst == iwchFirst) { itxtobjCompressFetchedLim = pilsobj->itxtobjCompressFetchedLim; iwchCompressFetchedLim = pilsobj->iwchCompressFetchedLim; } itxtobj = itxtobjFirst; itxtobjLastProcessed = itxtobj-1; if (itxtobj < (long)plsgrchnk->clsgrchnk) GetNextRun(plsgrchnk, itxtobj, &itxtobj); Assert( itxtobj == (long)plsgrchnk->clsgrchnk || ((PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj)->iwchLim > ((PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj)->iwchFirst); while(itxtobj <= itxtobjLast && *pdurCompressTotal < durCompressMaxStop) { itxtobjLastProcessed = itxtobj; fNextAdjacentFound = GetNextRun(plsgrchnk, itxtobj + 1, &itxtobjNext); ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj; plsrunCur = plsgrchnk->plschnk[itxtobj].plsrun; plschp = plsgrchnk->plschnk[itxtobj].plschp; iwchLimDobj = iwchLim; if (itxtobj < itxtobjLast) iwchLimDobj = ptxtobj->iwchLim; if (itxtobj > itxtobjCompressFetchedLim - 1 || itxtobj == itxtobjCompressFetchedLim - 1 && iwchLimDobj > iwchCompressFetchedLim) { lserr = (*pilsobj->plscbk->pfnGetEms)(pilsobj->pols, plsrunCur, lstflow, &lsems); if (lserr != lserrNone) return lserr; } iwch = iwchFirst; if (itxtobj > itxtobjFirst) iwch = ptxtobj->iwchFirst; for (; iwch < iwchLimDobj && *pdurCompressTotal < durCompressMaxStop; iwch++) { if (itxtobj < itxtobjCompressFetchedLim - 1 || itxtobj == itxtobjCompressFetchedLim - 1 && iwch < iwchCompressFetchedLim) { if (rgtxtinf[iwch].prior != prior0) *pdurCompressTotal -= pilsobj->pduAdjust[iwch]; } else { fGlyphBased = (ptxtobj->txtf & txtfGlyphBased); rgtxtinf[iwch].prior = prior0; if (!fGlyphBased && plschp->fCompressTable && !rgtxtinf[iwch].fModWidthOnRun && !rgtxtinf[iwch].fModWidthSpace) { lspract = pilsobj->plspract[pilsobj->pilspract[rgtxtinf[iwch].mwcls]]; Assert(lspract.prior <= pilsobj->cCompPrior); if (lspract.prior != prior0) { GetChanges(lspract.lsact, &lsems, pilsobj->pdur[iwch] - pilsobj->pdurRight[iwch] - pilsobj->pdurLeft[iwch], fFalse, &side, &durTemp); TranslateChanges(side, durTemp, pilsobj->pdur[iwch], pilsobj->pdurRight[iwch], pilsobj->pdurLeft[iwch], &sideFinal, &durChange); if (sideFinal != sideNone && durChange < 0) { if (itxtobj > itxtobjFirst || itxtobj == itxtobjFirst && iwch > iwchFirst || !fFirstOnLine || sideFinal != sideLeft) { SetComp(pilsobj, iwch, lspract.prior, sideFinal, durChange); *pdurCompressTotal -= durChange; } } } } if (rgwchOrig[iwch] == pilsobj->wchSpace && plschp->fCompressSpace && rgtxtinf[iwch].prior == prior0 && (!fGlyphBased || FIwchOneToOne(pilsobj, iwch))) { plsrunNext = NULL; iwchNext = 0; /* we take ptxtobj->iwchLim instead of iwchLimDobj because iwchLimDobj char(last char before spaces on the line must be used for context considerations */ if (iwch < ptxtobj->iwchLim - 1) { plsrunNext = plsrunCur; iwchNext = iwch + 1; } else if (fNextAdjacentFound) { plsrunNext = plsgrchnk->plschnk[itxtobjNext].plsrun; iwchNext = ((PTXTOBJ)plsgrchnk->plschnk[itxtobjNext].pdobj)->iwchFirst; } GetPrevCharRun(plsgrchnk, itxtobj, iwch, &iwchPrev, &plsrunPrev); lserr = CheckCompSpace(pilsobj, &lsems, iwchPrev, iwch, iwchNext, ptxtobj, plsrunPrev, plsrunCur, plsrunNext, &durChange); if (lserr != lserrNone) return lserr; *pdurCompressTotal -= durChange; } if (iwch == ptxtobj->iwchLim - 1 && plschp->fCompressOnRun && fNextAdjacentFound && rgtxtinf[iwch].prior == prior0) { plsrunNext = plsgrchnk->plschnk[itxtobjNext].plsrun; iwchNext = ((PTXTOBJ)plsgrchnk->plschnk[itxtobjNext].pdobj)->iwchFirst; lserr = CheckCompOnRun(pilsobj, &lsems, iwch, iwchNext, ptxtobj, plsrunCur, plsrunNext, &durChange); if (lserr != lserrNone) return lserr; *pdurCompressTotal -= durChange; } } } itxtobj = itxtobjNext; } pilsobj->iwchCompressFetchedFirst = iwchFirst; pilsobj->itxtobjCompressFetchedLim = itxtobjLastProcessed + 1; pilsobj->iwchCompressFetchedLim = min(iwch, iwchLim); return lserrNone; } /* G E T C O M P L A S T C H A R I N F O */ /*---------------------------------------------------------------------------- %%Function: GetCompLastCharInfo %%Contact: sergeyge ---------------------------------------------------------------------------*/ void GetCompLastCharInfo(PILSOBJ pilsobj, long iwchLast, MWCLS* pmwcls, long* pdurCompRight, long* pdurCompLeft) { /* Strong assumption for this function is that it is not called on GlyphBased run */ TXTINF txtinf; *pdurCompRight = 0; *pdurCompLeft = 0; /* ptxtinf == NULL means that there were no runs which possibly can introduce compress opportunity */ if (pilsobj->ptxtinf == NULL) return; txtinf = pilsobj->ptxtinf[iwchLast]; *pmwcls = (MWCLS)txtinf.mwcls; if (txtinf.prior != prior0) { InterpretChanges(pilsobj, iwchLast, (BYTE)txtinf.side, pilsobj->pduAdjust[iwchLast], pdurCompLeft, pdurCompRight); Assert(pilsobj->pduAdjust[iwchLast] == *pdurCompLeft + *pdurCompRight); } *pdurCompLeft = - *pdurCompLeft; *pdurCompRight = - *pdurCompRight; } /* C O M P R E S S L A S T C H A R R I G H T */ /*---------------------------------------------------------------------------- %%Function: CompressLastCharRight %%Contact: sergeyge ---------------------------------------------------------------------------*/ void CompressLastCharRight(PILSOBJ pilsobj, long iwchLast, long durToAdjustRight) { /* Strong assumption for this function is that it is not called on GlyphBased run */ pilsobj->pdur[iwchLast] -= durToAdjustRight; Assert(pilsobj->pdurRight != NULL); Assert(pilsobj->pdurLeft != NULL); Assert(pilsobj->ptxtinf != NULL); pilsobj->pdurRight[iwchLast] -= durToAdjustRight; if (durToAdjustRight > 0 && pilsobj->ptxtinf[iwchLast].prior != prior0) { if (pilsobj->ptxtinf[iwchLast].side == sideRight) { pilsobj->ptxtinf[iwchLast].prior = prior0; pilsobj->pduAdjust[iwchLast] = 0; } else if (pilsobj->ptxtinf[iwchLast].side == sideLeftRight) { pilsobj->ptxtinf[iwchLast].side = sideLeft; pilsobj->pduAdjust[iwchLast] += durToAdjustRight; } else { Assert(fFalse); } } } /* A P P L Y C O M P R E S S */ /*---------------------------------------------------------------------------- %%Function: ApplyCompress %%Contact: sergeyge Applies prioratized compression ---------------------------------------------------------------------------*/ LSERR ApplyCompress(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLim, long durToCompress) { PILSOBJ pilsobj; COMPINFO rgcompinfo[5]; COMPINFO* pcompinfo; BOOL fReleasePcompinfo; long i; Unreferenced(lstflow); pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pilsobj; fReleasePcompinfo = fFalse; pcompinfo = rgcompinfo; if (pilsobj->cCompPrior > 5) { pcompinfo = (*pilsobj->plscbk->pfnNewPtr)(pilsobj->pols, sizeof(COMPINFO) * pilsobj->cCompPrior); if (pcompinfo == NULL) return lserrOutOfMemory; else fReleasePcompinfo = fTrue; } GetCompressInfo(plsgrchnk, itxtobjFirst, iwchFirst, itxtobjLast, iwchLim, pcompinfo); for (i = 0; i < (long)pilsobj->cCompPrior && durToCompress > 0; i++) { if (pcompinfo[i].cCompOppr > 0) { ApplyPriorCompression(plsgrchnk, itxtobjFirst, iwchFirst, itxtobjLast, iwchLim, (BYTE)(i+1), durToCompress, pcompinfo[i].durComp, pcompinfo[i].cCompOppr); durToCompress -= pcompinfo[i].durComp; } } /* Following Assert is not compatible with the squeezing mode */ /*Assert(durToCompress <= 0);*/ if (fReleasePcompinfo) (*pilsobj->plscbk->pfnDisposePtr)(pilsobj->pols, pcompinfo); return lserrNone; } /* A P P L Y E X P A N D */ /*---------------------------------------------------------------------------- %%Function: ApplyExpand %%Contact: sergeyge Applies prioratized expansion ---------------------------------------------------------------------------*/ LSERR ApplyExpand(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, BOOL fScaled, long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLim, DWORD cNonTextObjects, long durToExpand, long* pdurExtNonText, BOOL* pfFinalAdjustNeeded) { LSERR lserr; PILSOBJ pilsobj; EXPINFO expinfo; long i; pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pilsobj; *pdurExtNonText = 0; lserr = GetExpandInfo(plsgrchnk, lstflow, fScaled, itxtobjFirst, iwchFirst, itxtobjLast, iwchLim, &expinfo); if (lserr != lserrNone) return lserr; for (i = 0; i < 2 && durToExpand > 0; i++) { if (expinfo.rgcExpPrior[i]) { ApplyPriorExpansion(plsgrchnk, itxtobjFirst, iwchFirst, itxtobjLast, iwchLim, (BYTE)(i+1), durToExpand, expinfo.rgdurPrior[i], expinfo.rgcExpPrior[i]); durToExpand -= expinfo.rgdurPrior[i]; } } if (durToExpand > 0) { ApplyFullExpansion(plsgrchnk, itxtobjFirst, iwchFirst, itxtobjLast, iwchLim, durToExpand, expinfo.cExpOppr, cNonTextObjects, pdurExtNonText); } *pfFinalAdjustNeeded = (expinfo.cExpOppr + cNonTextObjects > 0); return lserrNone; } /* A P P L Y D I S T R I B U T I O N */ /*---------------------------------------------------------------------------- %%Function: ApplyDistribution %%Contact: sergeyge Applies equal distribution to text chunk ---------------------------------------------------------------------------*/ void ApplyDistribution(const LSGRCHNK* plsgrchnk, DWORD cNonText, long durToDistribute, long* pdurNonTextObjects) { PILSOBJ pilsobj; long clschnk; PTXTOBJ ptxtobj; long itxtobj; long iwchFirst; long iwchLim; long iwch; long igind; long durToAdd; long cwchToDistribute; long cwchToDistributeAll; long wdurBound; long iwchUsed; clschnk = (long)plsgrchnk->clsgrchnk; Assert(clschnk > 0); pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pilsobj; cwchToDistribute = 0; for (itxtobj = 0; itxtobj < clschnk; itxtobj++) { ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj; iwchFirst = ptxtobj->iwchFirst; iwchLim = iwchFirst + plsgrchnk->plschnk[itxtobj].dcp; if (itxtobj == clschnk - 1) iwchLim--; if (ptxtobj->txtf & txtfGlyphBased) { for (iwch = iwchFirst; iwch < iwchLim; iwch++) { if (FIwchLastInContext(pilsobj, iwch)) cwchToDistribute++; } } else cwchToDistribute += (iwchLim - iwchFirst); } cwchToDistributeAll = cwchToDistribute + cNonText; *pdurNonTextObjects = 0; if (cwchToDistributeAll == 0) return; *pdurNonTextObjects = durToDistribute * cNonText / cwchToDistributeAll; durToDistribute -= *pdurNonTextObjects; if (cwchToDistribute == 0) return; durToAdd = durToDistribute / cwchToDistribute; wdurBound = durToDistribute - durToAdd * cwchToDistribute; iwchUsed = 0; for (itxtobj = 0; itxtobj < clschnk; itxtobj++) { ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj; iwchFirst = ptxtobj->iwchFirst; iwchLim = iwchFirst + plsgrchnk->plschnk[itxtobj].dcp; if (itxtobj == clschnk - 1) iwchLim--; if (ptxtobj->txtf & txtfGlyphBased) { for (iwch = iwchFirst; iwch < iwchLim; iwch++) { if (FIwchLastInContext(pilsobj, iwch)) { igind = IgindLastFromIwch(ptxtobj, iwch); igind = IgindBaseFromIgind(pilsobj, igind); if (iwchUsed < wdurBound) { ApplyGlyphChanges(pilsobj, igind, durToAdd + 1); } else { ApplyGlyphChanges(pilsobj, igind, durToAdd); } iwchUsed++; } } } else { for (iwch = iwchFirst; iwch < iwchLim; iwch++) { if (iwchUsed < wdurBound) { ApplyChanges(pilsobj, iwch, sideRight, durToAdd + 1); } else { ApplyChanges(pilsobj, iwch, sideRight, durToAdd); } iwchUsed++; } } } } /* Internal functions implementation */ /* G E T E X P A N D I N F O */ /*---------------------------------------------------------------------------- %%Function: GetExpandInfo %%Contact: sergeyge Collects expansion information ---------------------------------------------------------------------------*/ static LSERR GetExpandInfo(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, BOOL fScaled, long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLim, EXPINFO* pexpinfo) { LSERR lserr; PILSOBJ pilsobj; TXTINF* rgtxtinf; WCHAR* rgwchOrig; PTXTOBJ ptxtobj; PLSRUN plsrunCur; PLSRUN plsrunPrev; PLSRUN plsrunNext; PCLSCHP plschp; long durChange; LSEMS lsems; BOOL fNextAdjacentFound; long itxtobj; long itxtobjNext; long iwchLimDobj; LSEXPAN lsexpan; long iwch; long iwchPrev; long iwchNext; BOOL fExpandOpp; BOOL fGlyphBased; memset(pexpinfo, 0, sizeof(EXPINFO)); pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pilsobj; rgtxtinf = pilsobj->ptxtinf; /* rgtxtinf == NULL means that there were no runs which possibly can introduce expansion opportunity */ if (rgtxtinf == NULL) return lserrNone; rgwchOrig = pilsobj->pwchOrig; itxtobj = itxtobjFirst; if (itxtobj < (long)plsgrchnk->clsgrchnk) GetNextRun(plsgrchnk, itxtobj, &itxtobj); Assert(itxtobj == (long)plsgrchnk->clsgrchnk || ((PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj)->iwchLim > ((PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj)->iwchFirst); while(itxtobj <= itxtobjLast) { fNextAdjacentFound = GetNextRun(plsgrchnk, itxtobj + 1, &itxtobjNext); ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj; fGlyphBased = (ptxtobj->txtf & txtfGlyphBased); plsrunCur = plsgrchnk->plschnk[itxtobj].plsrun; plschp = plsgrchnk->plschnk[itxtobj].plschp; lserr = (*pilsobj->plscbk->pfnGetEms)(pilsobj->pols, plsrunCur, lstflow, &lsems); if (lserr != lserrNone) return lserr; iwchLimDobj = iwchLim; if (itxtobj < itxtobjLast) iwchLimDobj = ptxtobj->iwchLim; iwch = iwchFirst; if (itxtobj > itxtobjFirst) iwch = ptxtobj->iwchFirst; for (; iwch < iwchLimDobj; iwch++) { rgtxtinf[iwch].prior = prior0; if (rgwchOrig[iwch] == pilsobj->wchSpace && plschp->fExpandSpace && (!fGlyphBased || FIwchOneToOne(pilsobj, iwch))) { plsrunNext = NULL; iwchNext = 0; /* we take ptxtobj->iwchLim instead of iwchLimDobj because iwchLimInDobj char(last char before spaces on the line must be used for context considerations */ if (iwch < ptxtobj->iwchLim - 1) { plsrunNext = plsrunCur; iwchNext = iwch + 1; } else if (fNextAdjacentFound) { plsrunNext = plsgrchnk->plschnk[itxtobjNext].plsrun; iwchNext = ((PTXTOBJ)plsgrchnk->plschnk[itxtobjNext].pdobj)->iwchFirst; } GetPrevCharRun(plsgrchnk, itxtobj, iwch, &iwchPrev, &plsrunPrev); lserr = CheckExpandSpace(pilsobj, &lsems, iwchPrev, iwch, iwchNext, ptxtobj, plsrunPrev, plsrunCur, plsrunNext, &fExpandOpp, &durChange); if (lserr != lserrNone) return lserr; if (fExpandOpp) { pexpinfo->cExpOppr++; rgtxtinf[iwch].fExpand = fTrue; if (durChange > 0) { pexpinfo->rgdurPrior[0] += durChange; pexpinfo->rgcExpPrior[0]++; rgtxtinf[iwch].prior = 1; pilsobj->pduAdjust[iwch] = durChange; } } } if (!rgtxtinf[iwch].fExpand && iwch == ptxtobj->iwchLim - 1 && plschp->fExpandOnRun && fNextAdjacentFound) { plsrunNext = plsgrchnk->plschnk[itxtobjNext].plsrun; iwchNext = ((PTXTOBJ)plsgrchnk->plschnk[itxtobjNext].pdobj)->iwchFirst; lserr = CheckExpandOnRun(pilsobj, &lsems, iwch, iwchNext, ptxtobj, plsrunCur, plsrunNext, &fExpandOpp, &durChange); if (lserr != lserrNone) return lserr; if (fExpandOpp) { pexpinfo->cExpOppr++; rgtxtinf[iwch].fExpand = fTrue; if (durChange > 0) { pexpinfo->rgdurPrior[1] += durChange; pexpinfo->rgcExpPrior[1]++; rgtxtinf[iwch].prior = 2; pilsobj->pduAdjust[iwch] = durChange; } } } else if (!rgtxtinf[iwch].fExpand && iwch == ptxtobj->iwchLim - 1 && !fNextAdjacentFound && (plsgrchnk->pcont[itxtobj] & fcontExpandAfter)) { /* Character before foreign object */ pexpinfo->cExpOppr++; rgtxtinf[iwch].fExpand = fTrue; } if (!rgtxtinf[iwch].fExpand && plschp->fExpandTable) { Assert(!fGlyphBased); if (iwch < ptxtobj->iwchLim - 1) { lsexpan = pilsobj->plsexpan[pilsobj->pilsexpan[ pilsobj->cModWidthClasses * rgtxtinf[iwch].mwcls + rgtxtinf[iwch+1].mwcls ] ]; if (fScaled && lsexpan.fFullScaled || !fScaled && lsexpan.fFullInterletter) { pexpinfo->cExpOppr++; rgtxtinf[iwch].fExpand = fTrue; } } else if (fNextAdjacentFound && plsgrchnk->plschnk[itxtobjNext].plschp->fExpandTable) { Assert(!(((PTXTOBJ)plsgrchnk->plschnk[itxtobjNext].pdobj)->txtf & txtfGlyphBased)); iwchNext = ((PTXTOBJ)plsgrchnk->plschnk[itxtobjNext].pdobj)->iwchFirst; lsexpan = pilsobj->plsexpan[pilsobj->pilsexpan[ pilsobj->cModWidthClasses * rgtxtinf[iwch].mwcls + rgtxtinf[iwchNext].mwcls ] ]; if (fScaled && lsexpan.fFullScaled || !fScaled && lsexpan.fFullInterletter) { pexpinfo->cExpOppr++; rgtxtinf[iwch].fExpand = fTrue; } } } } itxtobj = itxtobjNext; } return lserrNone; } /* C H E C K E X P A N D S P A C E */ /*---------------------------------------------------------------------------- %%Function: CheckExpandSpace %%Contact: sergeyge Reports if there is expansion opportunity on space and amount of expansion ---------------------------------------------------------------------------*/ static LSERR CheckExpandSpace(PILSOBJ pilsobj, LSEMS* plsems, long iwchPrev, long iwch, long iwchNext, PTXTOBJ ptxtobjCur, PLSRUN plsrunPrev, PLSRUN plsrunCur, PLSRUN plsrunNext, BOOL* pfExpandOpp, long* pdurChange) { LSERR lserr; BYTE side; LSACT lsact; long igind; *pfExpandOpp = fFalse; *pdurChange = 0; lserr = (*pilsobj->plscbk->pfnExpWidthSpace)(pilsobj->pols, plsrunCur, plsrunPrev, pilsobj->pwchOrig[iwchPrev], plsrunNext, pilsobj->pwchOrig[iwchNext], &lsact); if (lserr != lserrNone) return lserr; if (lsact.side != sideNone) { *pfExpandOpp = fTrue; if (ptxtobjCur->txtf & txtfGlyphBased) { igind = IgindLastFromIwch(ptxtobjCur, iwch); GetChanges(lsact, plsems, pilsobj->pdurGind[igind], fTrue, &side, pdurChange); } else { GetChanges(lsact, plsems, pilsobj->pdur[iwch], fTrue, &side, pdurChange); } Assert(side == sideRight); if (*pdurChange < 0) *pdurChange = 0; } return lserrNone; } /* C H E C K E X P A N D O N R U N */ /*---------------------------------------------------------------------------- %%Function: CheckExpandOnRun %%Contact: sergeyge Reports if there is expansion opportunity between runs and amount of expansion ---------------------------------------------------------------------------*/ static LSERR CheckExpandOnRun(PILSOBJ pilsobj, LSEMS* plsems, long iwch, long iwchNext, PTXTOBJ ptxtobjCur, PLSRUN plsrunCur, PLSRUN plsrunNext, BOOL* pfExpandOpp, long* pdurChange) { LSERR lserr; BYTE side; LSACT lsact; long igind; *pfExpandOpp = fFalse; *pdurChange = 0; lserr = (*pilsobj->plscbk->pfnExpOnRun)(pilsobj->pols, plsrunCur, pilsobj->pwchOrig[iwch], plsrunNext, pilsobj->pwchOrig[iwchNext], &lsact); if (lserr != lserrNone) return lserr; if (lsact.side != sideNone) { *pfExpandOpp = fTrue; if (ptxtobjCur->txtf & txtfGlyphBased) { igind = IgindLastFromIwch(ptxtobjCur, iwch); igind = IgindBaseFromIgind(pilsobj, igind); GetChanges(lsact, plsems, pilsobj->pdurGind[igind], fTrue, &side, pdurChange); } else { GetChanges(lsact, plsems, pilsobj->pdur[iwch], fTrue, &side, pdurChange); } Assert(side == sideRight); if (*pdurChange < 0) *pdurChange = 0; } return lserrNone; } /* C H E C K C O M P S P A C E */ /*---------------------------------------------------------------------------- %%Function: CheckCompSpace %%Contact: sergeyge Reports if there is compression opportunity on space and amount of compression ---------------------------------------------------------------------------*/ static LSERR CheckCompSpace(PILSOBJ pilsobj, LSEMS* plsems, long iwchPrev, long iwch, long iwchNext, PTXTOBJ ptxtobjCur, PLSRUN plsrunPrev, PLSRUN plsrunCur, PLSRUN plsrunNext, long* pdurChange) { LSERR lserr; BYTE side; LSPRACT lspract; long igind; *pdurChange = 0; lserr = (*pilsobj->plscbk->pfnCompWidthSpace)(pilsobj->pols, plsrunCur, plsrunPrev, pilsobj->pwchOrig[iwchPrev], plsrunNext, pilsobj->pwchOrig[iwchNext], &lspract); if (lserr != lserrNone) return lserr; if (lspract.prior != prior0) { if (ptxtobjCur->txtf & txtfGlyphBased) { igind = IgindLastFromIwch(ptxtobjCur, iwch); GetChanges(lspract.lsact, plsems, pilsobj->pdurGind[igind], fFalse, &side, pdurChange); } else { GetChanges(lspract.lsact, plsems, pilsobj->pdur[iwch], fFalse, &side, pdurChange); } Assert(side == sideRight); if (*pdurChange < 0) SetComp(pilsobj, iwch, lspract.prior, side, *pdurChange); else *pdurChange = 0; } return lserrNone; } /* C H E C K C O M P O N R U N */ /*---------------------------------------------------------------------------- %%Function: CheckCompOnRun %%Contact: sergeyge Reports if there is compression opportunity between runs and amount of compression ---------------------------------------------------------------------------*/ static LSERR CheckCompOnRun(PILSOBJ pilsobj, LSEMS* plsems, long iwch, long iwchNext, PTXTOBJ ptxtobjCur, PLSRUN plsrunCur, PLSRUN plsrunNext, long* pdurChange) { LSERR lserr; BYTE side; LSPRACT lspract; long igind; *pdurChange = 0; lserr = (*pilsobj->plscbk->pfnCompOnRun)(pilsobj->pols, plsrunCur, pilsobj->pwchOrig[iwch], plsrunNext, pilsobj->pwchOrig[iwchNext], &lspract); if (lserr != lserrNone) return lserr; if (lspract.prior != prior0) { if (ptxtobjCur->txtf & txtfGlyphBased) { igind = IgindLastFromIwch(ptxtobjCur, iwch); igind = IgindBaseFromIgind(pilsobj, igind); GetChanges(lspract.lsact, plsems, pilsobj->pdurGind[igind], fFalse, &side, pdurChange); } else { GetChanges(lspract.lsact, plsems, pilsobj->pdur[iwch], fFalse, &side, pdurChange); } Assert(side == sideRight); if (*pdurChange < 0) SetComp(pilsobj, iwch, lspract.prior, side, *pdurChange); else *pdurChange = 0; } return lserrNone; } /* S E T C O M P */ /*---------------------------------------------------------------------------- %%Function: SetComp %%Contact: sergeyge ---------------------------------------------------------------------------*/ static void SetComp(PILSOBJ pilsobj, long iwch, BYTE prior, BYTE side, long durChange) { pilsobj->ptxtinf[iwch].prior = prior; pilsobj->ptxtinf[iwch].side = side; pilsobj->pduAdjust[iwch] = durChange; } /* G E T N E X T R U N */ /*---------------------------------------------------------------------------- %%Function: GetNextRun %%Contact: sergeyge ---------------------------------------------------------------------------*/ static BOOL GetNextRun(const LSGRCHNK* plsgrchnk, long itxtobj, long* pitxtobjNext) { long clschnk; PTXTOBJ ptxtobj; BOOL fFound; BOOL fContiguous; clschnk = (long)plsgrchnk->clsgrchnk; *pitxtobjNext = clschnk; fFound = fFalse; fContiguous = fTrue; while (!fFound && itxtobj < clschnk) { ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj; fFound = !(ptxtobj->txtf & txtfSkipAtNti); fContiguous = fContiguous && !(plsgrchnk->pcont[itxtobj] & fcontNonTextBefore); itxtobj++; } if (fFound) *pitxtobjNext = itxtobj - 1; return fFound && fContiguous; } /* G E T P R E V C H A R R U N */ /*---------------------------------------------------------------------------- %%Function: GetPrevCharRun %%Contact: sergeyge ---------------------------------------------------------------------------*/ static void GetPrevCharRun(const LSGRCHNK* plsgrchnk, long itxtobj, long iwch, long* piwchPrev, PLSRUN* pplsrunPrev) { BOOL fFound; PTXTOBJ ptxtobj; fFound = fFalse; Assert(itxtobj < (long)plsgrchnk->clsgrchnk); ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj; Assert(iwch >= ptxtobj->iwchFirst && iwch < ptxtobj->iwchLim); *piwchPrev = 0; *pplsrunPrev = NULL; if (iwch > ptxtobj->iwchFirst) { fFound = fTrue; *piwchPrev = iwch - 1; *pplsrunPrev = plsgrchnk->plschnk[itxtobj].plsrun; } else { while (!fFound && itxtobj > 0 && !(plsgrchnk->pcont[itxtobj] & fcontNonTextBefore)) { itxtobj--; Assert(itxtobj >= 0); ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj; fFound = !(ptxtobj->txtf & txtfSkipAtNti); if (fFound) { *piwchPrev = ((PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj)->iwchLim - 1; *pplsrunPrev = plsgrchnk->plschnk[itxtobj].plsrun; } } } } /* A P P L Y P R I O R E X P A N S I O N */ /*---------------------------------------------------------------------------- %%Function: ApplyPriorExpansion %%Contact: sergeyge Applies expansion on one priority level ---------------------------------------------------------------------------*/ static void ApplyPriorExpansion(const LSGRCHNK* plsgrchnk, long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLim, BYTE prior, long durToExpand, long durAvailable, long cExpOppr) { PILSOBJ pilsobj; PTXTOBJ ptxtobj; TXTINF* rgtxtinf; long* rgdurAdjust; long durSubstr; long durChange; long cBound; long cOpprCur; long itxtobj; long iwch; long iwchFirstInDobj; long iwchLimInDobj; long igind; BOOL fGlyphBased; pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pilsobj; rgtxtinf = pilsobj->ptxtinf; rgdurAdjust = pilsobj->pduAdjust; Assert(durToExpand > 0); if (durAvailable == 0) return; if (durAvailable < durToExpand) durToExpand = durAvailable; Assert(cExpOppr > 0); durSubstr = (durAvailable - durToExpand) / cExpOppr; cBound = (durAvailable - durToExpand) - durSubstr * cExpOppr; cOpprCur = 0; for (itxtobj = itxtobjFirst; itxtobj <= itxtobjLast; itxtobj++) { ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj; fGlyphBased = (ptxtobj->txtf & txtfGlyphBased); iwchFirstInDobj = iwchFirst; if (itxtobj > itxtobjFirst) iwchFirstInDobj = ptxtobj->iwchFirst; iwchLimInDobj = iwchLim; if (itxtobj < itxtobjLast) iwchLimInDobj = ptxtobj->iwchLim; for (iwch = iwchFirstInDobj; iwch < iwchLimInDobj; iwch++) { if (rgtxtinf[iwch].prior == prior) { cOpprCur++; durChange = rgdurAdjust[iwch] - durSubstr; if (cOpprCur <= cBound) durChange--; if (durChange >= 0) { if (fGlyphBased) { igind = IgindLastFromIwch(ptxtobj, iwch); igind = IgindBaseFromIgind(pilsobj, igind); ApplyGlyphChanges(pilsobj, igind, durChange); } else ApplyChanges(pilsobj, iwch, sideRight, durChange); } } } } } /* A P P L Y F U L L E X P A N S I O N */ /*---------------------------------------------------------------------------- %%Function: ApplyFullExpansion %%Contact: sergeyge Applies risidual unlimited expansion ---------------------------------------------------------------------------*/ static void ApplyFullExpansion(const LSGRCHNK* plsgrchnk, long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLim, long durToExpand, long cExpOppr, long cNonText, long* pdurNonText) { PILSOBJ pilsobj; PTXTOBJ ptxtobj; TXTINF* rgtxtinf; long* rgdurAdjust; long cBound; long cOpprCur; long cExpOpprTotal; long durChange; long durAdd; long itxtobj; long iwch; long iwchFirstInDobj; long iwchLimInDobj; long igind; BOOL fGlyphBased; pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pilsobj; rgtxtinf = pilsobj->ptxtinf; rgdurAdjust = pilsobj->pduAdjust; *pdurNonText = 0; cExpOpprTotal = cExpOppr + cNonText; if (cExpOpprTotal > 0) { *pdurNonText = durToExpand * cNonText / cExpOpprTotal; durToExpand -= *pdurNonText; if (cExpOppr > 0) { durAdd = durToExpand / cExpOppr; cBound = durToExpand - durAdd * cExpOppr; cOpprCur = 0; for (itxtobj = itxtobjFirst; itxtobj <= itxtobjLast; itxtobj++) { ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj; fGlyphBased = (ptxtobj->txtf & txtfGlyphBased); iwchFirstInDobj = iwchFirst; if (itxtobj > itxtobjFirst) iwchFirstInDobj = ptxtobj->iwchFirst; iwchLimInDobj = iwchLim; if (itxtobj < itxtobjLast) iwchLimInDobj = ptxtobj->iwchLim; for (iwch = iwchFirstInDobj; iwch < iwchLimInDobj; iwch++) { if (rgtxtinf[iwch].fExpand) { cOpprCur++; durChange = durAdd; if (cOpprCur <= cBound) durChange++; if (fGlyphBased) { igind = IgindLastFromIwch(ptxtobj, iwch); igind = IgindBaseFromIgind(pilsobj, igind); ApplyGlyphChanges(pilsobj, igind, durChange); } else ApplyChanges(pilsobj, iwch, sideRight, durChange); } } } } } } /* G E T C O M P R E S S I N F O */ /*---------------------------------------------------------------------------- %%Function: GetCompressInfo %%Contact: sergeyge Agregates compression information accross for priorities ---------------------------------------------------------------------------*/ static void GetCompressInfo(const LSGRCHNK* plsgrchnk, long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLim, COMPINFO* pcompinfo) { PILSOBJ pilsobj; PTXTOBJ ptxtobj; TXTINF* rgtxtinf; long* rgdurAdjust; UINT prior; long cCompPrior; long itxtobj; long iwch; long iwchFirstInDobj; long iwchLimInDobj; pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pilsobj; cCompPrior = pilsobj->cCompPrior; memset(pcompinfo, 0, sizeof(COMPINFO) * cCompPrior); rgtxtinf = pilsobj->ptxtinf; rgdurAdjust = pilsobj->pduAdjust; /* rgtxtinf == NULL means that there were no runs which possibly can introduce compress opportunity */ if (rgtxtinf == NULL) return; for (itxtobj = itxtobjFirst; itxtobj <= itxtobjLast ; itxtobj++) { ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj; iwchFirstInDobj = iwchFirst; if (itxtobj > itxtobjFirst) iwchFirstInDobj = ptxtobj->iwchFirst; iwchLimInDobj = iwchLim; if (itxtobj < itxtobjLast) iwchLimInDobj = ptxtobj->iwchLim; for (iwch = iwchFirstInDobj; iwch < iwchLimInDobj; iwch++) { prior = rgtxtinf[iwch].prior; Assert(prior <= (BYTE)cCompPrior); if (prior > 0) { pcompinfo[prior - 1].cCompOppr++; pcompinfo[prior - 1].durComp -= rgdurAdjust[iwch]; } } } } /* A P P L Y P R I O R C O M P R E S S I O N */ /*---------------------------------------------------------------------------- %%Function: ApplyPriorCompression %%Contact: sergeyge Applies compression for one priority level ---------------------------------------------------------------------------*/ static void ApplyPriorCompression(const LSGRCHNK* plsgrchnk, long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLim, BYTE prior, long durToCompress, long durAvailable, long cExpOppr) { PILSOBJ pilsobj; PTXTOBJ ptxtobj; TXTINF* rgtxtinf; long* rgdurAdjust; long durSubstr; long cBound; long cOpprCur; long durChange; long iwch; long itxtobj; long igind; BOOL fGlyphBased; long iwchFirstInDobj; long iwchLimInDobj; pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pilsobj; rgtxtinf = pilsobj->ptxtinf; rgdurAdjust = pilsobj->pduAdjust; Assert(durToCompress > 0); if (durAvailable == 0) return; if (durAvailable < durToCompress) durToCompress = durAvailable; Assert(cExpOppr > 0); durSubstr = (durAvailable - durToCompress) / cExpOppr; cBound = (durAvailable - durToCompress) - durSubstr * cExpOppr; cOpprCur = 0; for (itxtobj = itxtobjFirst; itxtobj <= itxtobjLast; itxtobj++) { ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj; fGlyphBased = (ptxtobj->txtf & txtfGlyphBased); iwchFirstInDobj = iwchFirst; if (itxtobj > itxtobjFirst) iwchFirstInDobj = ptxtobj->iwchFirst; iwchLimInDobj = iwchLim; if (itxtobj < itxtobjLast) iwchLimInDobj = ptxtobj->iwchLim; for (iwch = iwchFirstInDobj; iwch < iwchLimInDobj; iwch++) { if (rgtxtinf[iwch].prior == prior) { cOpprCur++; durChange = rgdurAdjust[iwch] + durSubstr; if (cExpOppr - cBound < cOpprCur) durChange++; if (durChange < 0) { if (fGlyphBased) { igind = IgindLastFromIwch(ptxtobj, iwch); igind = IgindBaseFromIgind(pilsobj, igind); ApplyGlyphChanges(pilsobj, igind, durChange); } else ApplyChanges(pilsobj, iwch, (BYTE)rgtxtinf[iwch].side, durChange); } } } } }