#include "lstxtwrd.h" #include "lstxtmap.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)) #define SqueezingFactorShift 2 static long GetNumberOfSpaces(const LSGRCHNK* plsgrchnk, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast); static void DistributeInDobjsSpaces(const LSGRCHNK* plsgrchnk, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, long* rgdu, long* rgduGind, long duAdd, long wDuBound); static void GetSqueezingInfo(const LSGRCHNK* plsgrchnk, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, long* rgdu, long* rgduGind, long* pNumOfSpaces, long* pduForSqueezing); static void SqueezeInDobjs(const LSGRCHNK* plsgrchnk, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, long* rgdu, long* rgduGind, long duSubstr, long wDuBound); /* F U L L P O S I T I V E J U S T I F I C A T I O N */ /*---------------------------------------------------------------------------- %%Function: FullPositiveJustification %%Contact: sergeyge Performs positive distribution in spaces. Since amount to distribute is not nesessary divisible by number of spaces, additional pixels (wDupBound, wDurBound) are distributed among first wDupBound/wDurBound spaces. Leading spaces do not participate. ----------------------------------------------------------------------------*/ void FullPositiveSpaceJustification(const LSGRCHNK* plsgrchnk, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, long* rgdu, long* rgduGind, long duToDistribute, BOOL* pfSpacesFound) { long NumOfSpaces; long duAdd; long wDuBound; Assert(duToDistribute > 0); NumOfSpaces = GetNumberOfSpaces(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast); if (NumOfSpaces > 0) { duAdd = duToDistribute / NumOfSpaces; wDuBound = duToDistribute - (duAdd * NumOfSpaces); DistributeInDobjsSpaces(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, rgdu, rgduGind, duAdd, wDuBound); } *pfSpacesFound = (NumOfSpaces > 0); } /* N E G A T I V E S P A C E J U S T I F I C A T I O N */ /*---------------------------------------------------------------------------- %%Function: NegativeSpaceJustification %%Contact: sergeyge Performs squeezing into spaces if it is possible. If it is impossible squeezes in as much as it can ----------------------------------------------------------------------------*/ void NegativeSpaceJustification(const LSGRCHNK* plsgrchnk, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, long* rgdu, long* rgduGind, long duToSqueeze) { long NumOfSpaces; long duForSqueezing; long duSubstr; long wDuBound; Assert(duToSqueeze > 0); GetSqueezingInfo(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, rgdu, rgduGind, &NumOfSpaces, &duForSqueezing); /* We cannot squeeze more tha we can */ if (duForSqueezing < duToSqueeze) duToSqueeze = duForSqueezing; /* dupSubstr shows how much should be subtracted from maximum squeezing each space provides. wDupBound--from how many spaces additional pixel should be subtracted */ if (NumOfSpaces > 0) { duSubstr = (duForSqueezing - duToSqueeze) / NumOfSpaces; wDuBound = (duForSqueezing - duToSqueeze) - duSubstr * NumOfSpaces; Assert(duSubstr >= 0); Assert(wDuBound >= 0); SqueezeInDobjs(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, rgdu, rgduGind, duSubstr, wDuBound); } return; } /* Internal Functions Implementation */ /* G E T N U M B E R O F S P A C E S */ /*---------------------------------------------------------------------------- %%Function: GetNumberOfSpaces %%Contact: sergeyge Reports amount of spaces for distribution. ----------------------------------------------------------------------------*/ static long GetNumberOfSpaces(const LSGRCHNK* plsgrchnk, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast) { long NumOfSpaces; PTXTOBJ ptxtobj; PILSOBJ pilsobj; long* rgwSpaces; long iwSpacesFirst; long iwSpacesLim; long iwSpaces; long iwchFirst; long iwchLim; long itxtobj; ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[0].pdobj; pilsobj = ptxtobj->plnobj->pilsobj; rgwSpaces = pilsobj->pwSpaces; NumOfSpaces = 0; for (itxtobj = itxtobjAfterStartSpaces; itxtobj <= itxtobjLast; itxtobj++) { ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj; if (ptxtobj->txtkind == txtkindRegular) { iwSpacesFirst = ptxtobj->u.reg.iwSpacesFirst; iwSpacesLim = ptxtobj->u.reg.iwSpacesLim; iwchFirst = iwchAfterStartSpaces; if (itxtobj > itxtobjAfterStartSpaces) iwchFirst = ptxtobj->iwchFirst; iwchLim = iwchLast + 1; if (itxtobj < itxtobjLast) iwchLim = ptxtobj->iwchLim; while (iwSpacesFirst < iwSpacesLim && rgwSpaces[iwSpacesFirst] < iwchFirst) { iwSpacesFirst++; } while (iwSpacesLim > iwSpacesFirst && rgwSpaces[iwSpacesLim-1] >= iwchLim) { iwSpacesLim--; } if (ptxtobj->txtf & txtfGlyphBased) { for (iwSpaces = iwSpacesFirst; iwSpaces < iwSpacesLim; iwSpaces++) if (FIwchOneToOne(pilsobj, rgwSpaces[iwSpaces])) NumOfSpaces++; } else NumOfSpaces += (iwSpacesLim - iwSpacesFirst); } } return NumOfSpaces; } /* D I S T R I B U T E I N D O B J S */ /*---------------------------------------------------------------------------- %%Function: DistributeInDobjs %%Contact: sergeyge Performs distribution in dobjs, based on precalculated information. ----------------------------------------------------------------------------*/ static void DistributeInDobjsSpaces(const LSGRCHNK* plsgrchnk, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, long* rgdu, long* rgduGind, long duAdd, long wDuBound) { PTXTOBJ ptxtobj; PILSOBJ pilsobj; PLNOBJ plnobj; long* rgwSpaces; long iwSpacesFirst; long iwSpacesLim; long iwchFirst; long iwchLim; long CurSpace; long itxtobj; long iwSpaces; long igind; long CurSpaceForSecondLoop; plnobj = ((PTXTOBJ)(plsgrchnk->plschnk[0].pdobj))->plnobj; pilsobj = plnobj->pilsobj; rgwSpaces = pilsobj->pwSpaces; CurSpace = 0; for (itxtobj = itxtobjAfterStartSpaces; itxtobj <= itxtobjLast ; itxtobj++) { ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj; if (ptxtobj->txtkind == txtkindRegular) { iwSpacesFirst = ptxtobj->u.reg.iwSpacesFirst; iwSpacesLim = ptxtobj->u.reg.iwSpacesLim; iwchFirst = iwchAfterStartSpaces; if (itxtobj > itxtobjAfterStartSpaces) iwchFirst = ptxtobj->iwchFirst; iwchLim = iwchLast + 1; if (itxtobj < itxtobjLast) iwchLim = ptxtobj->iwchLim; while (iwSpacesFirst < iwSpacesLim && rgwSpaces[iwSpacesFirst] < iwchFirst) { iwSpacesFirst++; } while (iwSpacesLim > iwSpacesFirst && rgwSpaces[iwSpacesLim-1] >= iwchLim) { iwSpacesLim--; } if (ptxtobj->txtf & txtfGlyphBased) { Assert(rgduGind != NULL); for(iwSpaces = iwSpacesFirst; iwSpaces < iwSpacesLim; iwSpaces++) { if (FIwchOneToOne(pilsobj, rgwSpaces[iwSpaces])) { igind = IgindFirstFromIwch(ptxtobj, rgwSpaces[iwSpaces]); if (CurSpace < wDuBound) { rgduGind[igind] += (duAdd + 1); pilsobj->pduGright[igind] += (duAdd + 1); } else { rgduGind[igind] += duAdd; pilsobj->pduGright[igind] += duAdd; } CurSpace++; } } } else { CurSpaceForSecondLoop = CurSpace; for(iwSpaces = iwSpacesFirst; iwSpaces < iwSpacesLim; iwSpaces++) { if (CurSpace < wDuBound) { rgdu[rgwSpaces[iwSpaces]] += (duAdd + 1); } else { rgdu[rgwSpaces[iwSpaces]] += duAdd; } CurSpace++; } if (pilsobj->fNotSimpleText) { for(iwSpaces = iwSpacesFirst; iwSpaces < iwSpacesLim; iwSpaces++) { if (CurSpaceForSecondLoop < wDuBound) { pilsobj->pdurRight[rgwSpaces[iwSpaces]] += (duAdd + 1); } else { pilsobj->pdurRight[rgwSpaces[iwSpaces]] += duAdd; } CurSpaceForSecondLoop++; } } } } } } /* G E T S Q U E E Z I N G I N F O */ /*---------------------------------------------------------------------------- %%Function: GetSqueezingInfo %%Contact: sergeyge Calculates maximum amount of pixels to squeeze into spaces. Leading spaces are used for squeezing. ----------------------------------------------------------------------------*/ static void GetSqueezingInfo(const LSGRCHNK* plsgrchnk, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, long* rgdu, long* rgduGind, long* pNumOfSpaces, long* pduForSqueezing) { PTXTOBJ ptxtobj; PLNOBJ plnobj; PILSOBJ pilsobj; long* rgwSpaces; long iwSpacesFirst; long iwSpacesLim; long iwchFirst; long iwchLim; long itxtobj; long iwSpaces; ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[0].pdobj; plnobj = ptxtobj->plnobj; pilsobj = plnobj->pilsobj; rgwSpaces = pilsobj->pwSpaces; *pNumOfSpaces = 0; *pduForSqueezing = 0; for (itxtobj = itxtobjAfterStartSpaces; itxtobj <= itxtobjLast ; itxtobj++) { ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj; if (! (ptxtobj->txtf & txtfMonospaced) ) { if (ptxtobj->txtkind == txtkindRegular) { iwSpacesFirst = ptxtobj->u.reg.iwSpacesFirst; iwSpacesLim = ptxtobj->u.reg.iwSpacesLim; iwchFirst = iwchAfterStartSpaces; if (itxtobj > itxtobjAfterStartSpaces) iwchFirst = ptxtobj->iwchFirst; iwchLim = iwchLast + 1; if (itxtobj < itxtobjLast) iwchLim = ptxtobj->iwchLim; while (iwSpacesFirst < iwSpacesLim && rgwSpaces[iwSpacesFirst] < iwchFirst) { iwSpacesFirst++; } while (iwSpacesLim > iwSpacesFirst && rgwSpaces[iwSpacesLim-1] >= iwchLim) { iwSpacesLim--; } if (ptxtobj->txtf & txtfGlyphBased) { for (iwSpaces = iwSpacesFirst; iwSpaces < iwSpacesLim; iwSpaces++) { if (FIwchOneToOne(pilsobj, rgwSpaces[iwSpaces])) { (*pduForSqueezing) += rgduGind[IgindFirstFromIwch(ptxtobj,rgwSpaces[iwSpaces])] >> SqueezingFactorShift; (*pNumOfSpaces)++; } } } else { for (iwSpaces = iwSpacesFirst; iwSpaces < iwSpacesLim; iwSpaces++) { (*pduForSqueezing) += rgdu[rgwSpaces[iwSpaces]] >> SqueezingFactorShift; } (*pNumOfSpaces) += (iwSpacesLim - iwSpacesFirst); } } } } } /* S Q U E E Z E I N D O B J S */ /*---------------------------------------------------------------------------- %%Function: SqueezeInDobjs %%Contact: sergeyge Performs squeezing in dobjs, based on precalculated information ----------------------------------------------------------------------------*/ static void SqueezeInDobjs(const LSGRCHNK* plsgrchnk, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, long* rgdu, long* rgduGind, long duSubstr, long wDuBound) { PTXTOBJ ptxtobj; PLNOBJ plnobj; PILSOBJ pilsobj; long* rgwSpaces; long iwSpacesFirst; long iwSpacesLim; long iwchFirst; long iwchLim; long duChange; long CurSpace; long itxtobj; long iwSpaces; long igind; long CurSpaceForSecondLoop; ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[0].pdobj; plnobj = ptxtobj->plnobj; pilsobj = plnobj->pilsobj; rgwSpaces = pilsobj->pwSpaces; CurSpace = 0; for (itxtobj = itxtobjAfterStartSpaces; itxtobj <= itxtobjLast; itxtobj++) { ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj; if (! (ptxtobj->txtf & txtfMonospaced) ) { if (ptxtobj->txtkind == txtkindRegular) { iwSpacesFirst = ptxtobj->u.reg.iwSpacesFirst; iwSpacesLim = ptxtobj->u.reg.iwSpacesLim; iwchFirst = iwchAfterStartSpaces; if (itxtobj > itxtobjAfterStartSpaces) iwchFirst = ptxtobj->iwchFirst; iwchLim = iwchLast + 1; if (itxtobj < itxtobjLast) iwchLim = ptxtobj->iwchLim; while (iwSpacesFirst < iwSpacesLim && rgwSpaces[iwSpacesFirst] < iwchFirst) { iwSpacesFirst++; } while (iwSpacesLim > iwSpacesFirst && rgwSpaces[iwSpacesLim-1] >= iwchLim) { iwSpacesLim--; } if (ptxtobj->txtf & txtfGlyphBased) { for(iwSpaces = iwSpacesFirst; iwSpaces < iwSpacesLim; iwSpaces++) { if (FIwchOneToOne(pilsobj, rgwSpaces[iwSpaces])) { igind = IgindFirstFromIwch(ptxtobj, rgwSpaces[iwSpaces]); duChange = -(rgduGind[igind] >> SqueezingFactorShift) + duSubstr; if (CurSpace < wDuBound) { duChange += 1; } rgduGind[igind] += duChange; pilsobj->pduGright[igind] += duChange; CurSpace++; } } } else { CurSpaceForSecondLoop = CurSpace; for(iwSpaces = iwSpacesFirst; iwSpaces < iwSpacesLim; iwSpaces++) { duChange = -(rgdu[rgwSpaces[iwSpaces]] >> SqueezingFactorShift) + duSubstr; if (CurSpace < wDuBound) { duChange += 1; } rgdu[rgwSpaces[iwSpaces]] += duChange; CurSpace++; } if (pilsobj->fNotSimpleText) { for(iwSpaces = iwSpacesFirst; iwSpaces < iwSpacesLim; iwSpaces++) { duChange = -(rgdu[rgwSpaces[iwSpaces]] >> SqueezingFactorShift) + duSubstr; if (CurSpaceForSecondLoop < wDuBound) { duChange += 1; } pilsobj->pdurRight[rgwSpaces[iwSpaces]] += duChange; CurSpaceForSecondLoop++; } } } } } } }