windows-nt/Source/XPSP1/NT/windows/richedit/lssrc/lstxtcmp.c
2020-09-26 16:20:57 +08:00

1298 lines
36 KiB
C

#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);
}
}
}
}
}