#include "lsmem.h" #include #include "lstxtjst.h" #include "lstxtwrd.h" #include "lstxtcmp.h" #include "lstxtglf.h" #include "lstxtscl.h" #include "lstxtmap.h" #include "lsdnset.h" #include "lsdntext.h" #include "locchnk.h" #include "posichnk.h" #include "objdim.h" #include "lstxtffi.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)) static void GetFirstPosAfterStartSpaces(const LSGRCHNK* plsgrchnk, long itxtobjLast, long iwchLim, long* pitxtobjAfterStartSpaces, long* piwchAfterStartSpaces, BOOL* pfFirstOnLineAfter); static LSERR HandleSimpleTextWysi(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long durToDistribute, long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, BOOL fExactSync, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces, long* pdupText, long* pdupTail); static LSERR HandleSimpleTextPres(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long dupAvailable, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces, long* pdupText, long* pdupTail); static LSERR HandleGeneralSpacesExactSync(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long durToDistribute, long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces, long* pdupText, long* pdupTail); static LSERR HandleGeneralSpacesPres(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces, long* pdupText, long* pdupTail); static LSERR HandleTablesBased(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long durToDistribute, long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, BOOL fFirstOnLineAfter, long itxtobjLast, long iwchLast, long cNonText, BOOL fLastObjectIsText, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces, long* pdupText, long* pdupTail, long* pdupExtNonText); static LSERR HandleFullGlyphsExactSync(const LSGRCHNK* plsgrchnk, long durToDistribute, long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces, long* pdupText, long* pdupTail); static LSERR HandleFullGlyphsPres(const LSGRCHNK* plsgrchnk, long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces, long* pdupText, long* pdupTail); /* A D J U S T T E X T */ /*---------------------------------------------------------------------------- %%Function: AdjustText %%Contact: sergeyge The top-level text handler function of the PrepLineForDisplay time---calculation of the presentation widths It calculates justification area (from first non-space to last non-space), checks for the type of justification and WYSIWYG algorythm and redirects the program flow accordingly. ----------------------------------------------------------------------------*/ LSERR AdjustText(LSKJUST lskjust, long durColumnMax, long durTotal, long dupAvailable, const LSGRCHNK* plsgrchnk, PCPOSICHNK pposichnkBeforeTrailing, LSTFLOW lstflow, BOOL fCompress, DWORD cNonText, BOOL fSuppressWiggle, BOOL fExactSync, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces, long* pdupText, long* pdupTail,long* pdupExtNonTextObjects, DWORD* pcExtNonTextObjects) { PILSOBJ pilsobj; long itxtobjAfterStartSpaces; long itxtobjLast; PTXTOBJ ptxtobjLast; long iwchAfterStartSpaces; long iwchLast; long clsgrchnk; long durToDistribute; BOOL fFirstOnLineAfter; BOOL fLastObjectIsText; LSDCP dcp; *pdupText = 0; *pdupTail = 0; *pdupExtNonTextObjects = 0; *pcExtNonTextObjects = 0; clsgrchnk = (long)plsgrchnk->clsgrchnk; if (clsgrchnk == 0) { Assert(cNonText > 0); if (lskjust == lskjFullScaled || lskjust == lskjFullInterLetterAligned) { *pcExtNonTextObjects = cNonText - 1; *pdupExtNonTextObjects = dupAvailable; } return lserrNone; } pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pilsobj; Assert (pilsobj->fDisplay); if (pilsobj->fPresEqualRef) { fExactSync = fFalse; fSuppressWiggle = fFalse; } itxtobjLast = pposichnkBeforeTrailing->ichnk; dcp = pposichnkBeforeTrailing->dcp; Assert(itxtobjLast >= 0); Assert(itxtobjLast < clsgrchnk || (itxtobjLast == clsgrchnk && dcp == 0)); if (dcp == 0 && itxtobjLast > 0) { itxtobjLast--; dcp = plsgrchnk->plschnk[itxtobjLast].dcp; } ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[itxtobjLast].pdobj; if (ptxtobjLast->iwchLim > ptxtobjLast->iwchFirst) iwchLast = ptxtobjLast->iwchFirst + dcp - 1; else iwchLast = ptxtobjLast->iwchLim - 1; /* In the case of AutoHyphenation, dcp reported by manager is not equal to the real number of characters--- it should be fixed. Notice that in the case of "delete before" hyphenation type, situation is totally wrong because deleted character was replaced by space and collected by manager as trailing space. */ if (ptxtobjLast == ptxtobjLast->plnobj->pdobjHyphen) { iwchLast = ptxtobjLast->iwchLim - 1; } Assert(iwchLast >= ptxtobjLast->iwchFirst - 1); Assert(iwchLast <= ptxtobjLast->iwchLim - 1); GetFirstPosAfterStartSpaces(plsgrchnk, itxtobjLast, iwchLast + 1, &itxtobjAfterStartSpaces, &iwchAfterStartSpaces, &fFirstOnLineAfter); durToDistribute = durColumnMax - durTotal; if (!pilsobj->fNotSimpleText) { if (durToDistribute < 0) fSuppressWiggle = fFalse; if (fExactSync || fSuppressWiggle) { return HandleSimpleTextWysi(lskjust, plsgrchnk, durToDistribute, dupAvailable, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, fExactSync, fForcedBreak, fSuppressTrailingSpaces, pdupText, pdupTail); } // else if (fSupressWiggle) /* add later */ else { return HandleSimpleTextPres(lskjust, plsgrchnk, dupAvailable, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, fForcedBreak, fSuppressTrailingSpaces, pdupText, pdupTail); } } else { long itxtobjFirstInLastTextChunk; for(itxtobjFirstInLastTextChunk = clsgrchnk; itxtobjFirstInLastTextChunk > 0 && !(plsgrchnk->pcont[itxtobjFirstInLastTextChunk - 1] & fcontNonTextAfter); itxtobjFirstInLastTextChunk--); fLastObjectIsText = fTrue; if (itxtobjLast < itxtobjFirstInLastTextChunk || itxtobjLast == itxtobjFirstInLastTextChunk && iwchLast < ((PTXTOBJ)plsgrchnk->plschnk[itxtobjFirstInLastTextChunk].pdobj)->iwchFirst ) { /* REVIEW sergeyge: check this logic */ if (cNonText > 0) cNonText--; fLastObjectIsText = fFalse; } *pcExtNonTextObjects = cNonText; if (fCompress || lskjust == lskjFullInterLetterAligned || lskjust == lskjFullScaled || pilsobj->fSnapGrid) { return HandleTablesBased(lskjust, plsgrchnk, durToDistribute, dupAvailable, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces, fFirstOnLineAfter, itxtobjLast, iwchLast, cNonText, fLastObjectIsText, fForcedBreak, fSuppressTrailingSpaces, pdupText, pdupTail, pdupExtNonTextObjects); } else if (lskjust == lskjFullGlyphs) { if (fExactSync || fSuppressWiggle) { return HandleFullGlyphsExactSync(plsgrchnk, durToDistribute, dupAvailable, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, fForcedBreak, fSuppressTrailingSpaces, pdupText, pdupTail); } else { return HandleFullGlyphsPres(plsgrchnk, dupAvailable, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, fForcedBreak, fSuppressTrailingSpaces, pdupText, pdupTail); } } else { if (plsgrchnk->clsgrchnk == 0) return lserrNone; Assert(fCompress == fFalse); Assert(lskjust == lskjNone || lskjust == lskjFullInterWord); if (fExactSync || fSuppressWiggle) { return HandleGeneralSpacesExactSync(lskjust, plsgrchnk, durToDistribute, dupAvailable, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, fForcedBreak, fSuppressTrailingSpaces, pdupText, pdupTail); } else { return HandleGeneralSpacesPres(lskjust, plsgrchnk, dupAvailable, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, fForcedBreak, fSuppressTrailingSpaces, pdupText, pdupTail); } } } } /* C A N C O M P R E S S T E X T */ /*---------------------------------------------------------------------------- %%Function: CanCompressText %%Contact: sergeyge Procedure checks if there is enough compression opportunities on the line to squeeze in needed amount (durToCompress). Trailing spaces are already subtracted by the manager. This procedure takes care of the hanging punctuation and possible changes if this break opportunity will be realized At the end it helps Word to solve backward compatibility issues ----------------------------------------------------------------------------*/ LSERR CanCompressText(const LSGRCHNK* plsgrchnk, PCPOSICHNK pposichnkBeforeTrailing, LSTFLOW lstflow, long durToCompress, BOOL* pfCanCompress, BOOL* pfActualCompress, long* pdurNonSufficient) { LSERR lserr; PILSOBJ pilsobj; long clschnk; long itxtobjFirstInLastTextChunk; /* if GroupChunk ends with foreign object it is equal to cchnk */ long itxtobjLast; PTXTOBJ ptxtobjLast; long iwchLast; long iwchLastTemp; long iwchAfterStartSpaces; long itxtobjAfterStartSpaces; long durCompressTotal; BOOL fHangingPunct; BOOL fChangeBackLastChar; long ibrkinf; BREAKINFO* pbrkinf = NULL; BOOL fFirstOnLineAfter; long durCompLastRight; long durCompLastLeft; long durChangeComp; BOOL fCancelHangingPunct; MWCLS mwclsLast; LSCP cpLim; LSCP cpLastAdjustable; LSDCP dcp; *pfCanCompress = fFalse; *pfActualCompress = fTrue; clschnk = (long)plsgrchnk->clsgrchnk; if (clschnk == 0) { *pfCanCompress = (durToCompress <=0 ); *pfActualCompress = fFalse; return lserrNone; } Assert(clschnk > 0); pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[clschnk-1].pdobj)->plnobj->pilsobj; itxtobjLast = pposichnkBeforeTrailing->ichnk; dcp = pposichnkBeforeTrailing->dcp; Assert(itxtobjLast >= 0); Assert(itxtobjLast < clschnk || (itxtobjLast == clschnk && dcp == 0)); if (dcp == 0 && itxtobjLast > 0) { itxtobjLast--; dcp = plsgrchnk->plschnk[itxtobjLast].dcp; } ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[itxtobjLast].pdobj; if (ptxtobjLast->iwchLim > ptxtobjLast->iwchFirst) iwchLast = ptxtobjLast->iwchFirst + dcp - 1; else iwchLast = ptxtobjLast->iwchLim - 1; Assert(iwchLast <= ptxtobjLast->iwchLim - 1); Assert(iwchLast >= ptxtobjLast->iwchFirst - 1); GetFirstPosAfterStartSpaces(plsgrchnk, itxtobjLast, iwchLast + 1, &itxtobjAfterStartSpaces, &iwchAfterStartSpaces, &fFirstOnLineAfter); if (iwchAfterStartSpaces > iwchLast) { *pfCanCompress = (durToCompress <=0 ); *pfActualCompress = fFalse; return lserrNone; } for(itxtobjFirstInLastTextChunk = clschnk; itxtobjFirstInLastTextChunk > 0 && !(plsgrchnk->pcont[itxtobjFirstInLastTextChunk - 1] & fcontNonTextAfter); itxtobjFirstInLastTextChunk--); fHangingPunct = fFalse; if ((pilsobj->grpf & fTxtHangingPunct) && (itxtobjLast > itxtobjFirstInLastTextChunk || itxtobjLast == itxtobjFirstInLastTextChunk && iwchLast >= ((PTXTOBJ)plsgrchnk->plschnk[itxtobjFirstInLastTextChunk].pdobj)->iwchFirst) && !(ptxtobjLast->txtf & txtfGlyphBased)) { lserr = (*pilsobj->plscbk->pfnFHangingPunct)(pilsobj->pols, plsgrchnk->plschnk[itxtobjLast].plsrun, (BYTE)pilsobj->ptxtinf[iwchLast].mwcls, pilsobj->pwchOrig[iwchLast], &fHangingPunct); if (lserr != lserrNone) return lserr; } /* Compression information should be collected under assumption that all chars have correct widths; Correct width of HangingPunct should be subtructed as well */ iwchLastTemp = iwchLast; fChangeBackLastChar = fFalse; for (ibrkinf = 0; ibrkinf < (long)pilsobj->breakinfMac && (pilsobj->pbreakinf[ibrkinf].pdobj != (PDOBJ)ptxtobjLast || ((long)pilsobj->pbreakinf[ibrkinf].dcp != iwchLast + 1 - ptxtobjLast->iwchFirst && ptxtobjLast->txtkind != txtkindNonReqHyphen && ptxtobjLast->txtkind != txtkindOptBreak)); ibrkinf++); if (ibrkinf < (long)pilsobj->breakinfMac) { pbrkinf = &pilsobj->pbreakinf[ibrkinf]; Assert(pbrkinf->brkt != brktHyphen); if (pbrkinf->brkt == brktNormal && pbrkinf->u.normal.durFix != 0) { /* Now manager makes correct calculation */ // durToCompress += pbrkinf->u.normal.durFix; Assert(pilsobj->pdurRight[iwchLast] == - pbrkinf->u.normal.durFix); pilsobj->pdur[iwchLast] += pbrkinf->u.normal.durFix; pilsobj->pdurRight[iwchLast] = 0; fChangeBackLastChar = fTrue; } else if (pbrkinf->brkt == brktNonReq) { Assert(iwchLast + 1 == ptxtobjLast->iwchLim); /* Now manager makes correct calculation */ // durToCompress += pbrkinf->u.nonreq.ddurTotal; fHangingPunct = fFalse; /* hanging punct does not make sence in this case */ if (pbrkinf->u.nonreq.dwchYsr >= 1) { if (pbrkinf->u.nonreq.wchPrev != 0) { iwchLastTemp--; if (pbrkinf->u.nonreq.wchPrevPrev != 0) { iwchLastTemp--; } } } } } *pfActualCompress = (durToCompress > 0); if (fHangingPunct) { pilsobj->ptxtinf[iwchLast].fHangingPunct = fTrue; durToCompress -= pilsobj->pdur[iwchLast]; iwchLastTemp--; } durCompressTotal = 0; if (!pilsobj->fSnapGrid) { lserr = FetchCompressInfo(plsgrchnk, fFirstOnLineAfter, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLastTemp + 1, durToCompress, &durCompressTotal); if (lserr != lserrNone) return lserr; } /* Next piece is added to provide mechanism for the backword compatibility with Word */ durCompLastRight = 0; durCompLastLeft = 0; if (!(((PTXTOBJ)(plsgrchnk->plschnk[itxtobjLast].pdobj))->txtf & txtfGlyphBased) && !pilsobj->fSnapGrid) { GetCompLastCharInfo(pilsobj, iwchLast, &mwclsLast, &durCompLastRight, &durCompLastLeft); /* First 3 lines of the following condition mean: Is Last Significant Character On The Line Text? */ if (itxtobjFirstInLastTextChunk < (long)clschnk && (itxtobjLast > itxtobjFirstInLastTextChunk || itxtobjLast == itxtobjFirstInLastTextChunk && iwchLast >= ((PTXTOBJ)plsgrchnk->plschnk[itxtobjFirstInLastTextChunk].pdobj)->iwchFirst) && (durCompLastRight > 0 || durCompLastLeft > 0 || fHangingPunct)) { cpLim = plsgrchnk->plschnk[clschnk-1].cpFirst + plsgrchnk->plschnk[clschnk-1].dcp; cpLastAdjustable = plsgrchnk->plschnk[itxtobjLast].cpFirst + iwchLast - ((PTXTOBJ)plsgrchnk->plschnk[itxtobjLast].pdobj)->iwchFirst; durChangeComp = 0; if (fHangingPunct) { lserr = (*pilsobj->plscbk->pfnFCancelHangingPunct)(pilsobj->pols, cpLim, cpLastAdjustable, pilsobj->pwchOrig[iwchLast], mwclsLast, &fCancelHangingPunct); if (lserr != lserrNone) return lserr; if (fCancelHangingPunct) { lserr = FetchCompressInfo(plsgrchnk, fFirstOnLineAfter, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast + 1, LONG_MAX, &durCompressTotal); if (lserr != lserrNone) return lserr; durToCompress += pilsobj->pdur[iwchLast]; GetCompLastCharInfo(pilsobj, iwchLast, &mwclsLast, &durCompLastRight, &durCompLastLeft); if ((durCompLastRight + durCompLastLeft) > 0) { lserr = (*pilsobj->plscbk->pfnModifyCompAtLastChar)(pilsobj->pols, cpLim, cpLastAdjustable, pilsobj->pwchOrig[iwchLast], mwclsLast, durCompLastRight, durCompLastLeft, &durChangeComp); if (lserr != lserrNone) return lserr; } Assert(durChangeComp >= 0); Assert(durChangeComp == 0 || (durCompLastRight + durCompLastLeft) > 0); } } else { lserr = (*pilsobj->plscbk->pfnModifyCompAtLastChar)(pilsobj->pols, cpLim, cpLastAdjustable, pilsobj->pwchOrig[iwchLast], mwclsLast, durCompLastRight, durCompLastLeft, &durChangeComp); if (lserr != lserrNone) return lserr; Assert(durChangeComp >= 0); Assert(durChangeComp == 0 || (durCompLastRight + durCompLastLeft) > 0); } durCompressTotal -= durChangeComp; } /* End of the piece is added to provide mechanizm for the backword compatibility with Word */ } /* Restore width changed before the call to FetchCompressInfo */ if (fChangeBackLastChar) { pilsobj->pdur[iwchLast] -= pbrkinf->u.normal.durFix; pilsobj->pdurRight[iwchLast] = - pbrkinf->u.normal.durFix; } if (!pilsobj->fSnapGrid) *pfCanCompress = (durToCompress <= durCompressTotal); else *pfCanCompress = (fHangingPunct && durToCompress <= 0); *pdurNonSufficient = durToCompress - durCompressTotal; return lserrNone; } /* D I S T R I B U T E I N T E X T */ /*---------------------------------------------------------------------------- %%Function: DistributeInText %%Contact: sergeyge Distributes given amount in text chunk equally between all participating characters ----------------------------------------------------------------------------*/ LSERR DistributeInText(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, DWORD cNonText, long durToDistribute, long* pdurNonTextObjects) { LSERR lserr; PILSOBJ pilsobj; DWORD clschnk; long* rgdur; long iFirst; long iLim; PTXTOBJ ptxtobj; long itxtobj; long i; long durTxtobj; OBJDIM objdim; Unreferenced(lstflow); clschnk = plsgrchnk->clsgrchnk; Assert(clschnk + cNonText > 0); if (clschnk == 0) { *pdurNonTextObjects = durToDistribute; return lserrNone; } pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pilsobj; /* REVIEW sergeyge:Very ugly but still better than anything else? Problem case is latin Rubi---NTI was not called and so additional arrays were not allocated Original solution---scaling everything down---is not an option becuse than we lose all left sided changes in the Rubi subline for Japanese case */ pilsobj->fNotSimpleText = fTrue; if (pilsobj->pdurRight == NULL) { pilsobj->pdurRight = (*pilsobj->plscbk->pfnNewPtr)(pilsobj->pols, sizeof(long) * pilsobj->wchMax ); Assert (pilsobj->pdurLeft == NULL); Assert (pilsobj->ptxtinf == NULL); pilsobj->pdurLeft = (*pilsobj->plscbk->pfnNewPtr)(pilsobj->pols, sizeof(long) * pilsobj->wchMax ); pilsobj->ptxtinf = (*pilsobj->plscbk->pfnNewPtr)(pilsobj->pols, sizeof(TXTINF) * pilsobj->wchMax ); if (pilsobj->pdurRight == NULL || pilsobj->pdurLeft == NULL || pilsobj->ptxtinf == NULL) { return lserrOutOfMemory; } memset(pilsobj->pdurRight, 0, sizeof(long) * pilsobj->wchMax ); memset(pilsobj->pdurLeft, 0, sizeof(long) * pilsobj->wchMax ); memset(pilsobj->ptxtinf, 0, sizeof(TXTINF) * pilsobj->wchMax); } ApplyDistribution(plsgrchnk, cNonText, durToDistribute, pdurNonTextObjects); for (itxtobj = 0; itxtobj < (long)clschnk; itxtobj++) { ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj; if (ptxtobj->txtf & txtfGlyphBased) { iFirst = ptxtobj->igindFirst; iLim = ptxtobj->igindLim; rgdur = pilsobj->pdurGind; } else { iFirst = ptxtobj->iwchFirst; iLim = ptxtobj->iwchLim; rgdur = pilsobj->pdur; } durTxtobj = 0; for (i = iFirst; i < iLim; i++) { durTxtobj += rgdur[i]; } lserr = LsdnGetObjDim(pilsobj->plsc, ptxtobj->plsdnUpNode, &objdim); if (lserr != lserrNone) return lserr; objdim.dur = durTxtobj; lserr = LsdnResetObjDim(pilsobj->plsc, ptxtobj->plsdnUpNode, &objdim); if (lserr != lserrNone) return lserr; } return lserrNone; } /* G E T T R A I L I N F O T E X T */ /*---------------------------------------------------------------------------- %%Function: GetTrailInfoText %%Contact: sergeyge Calculates number of spaces at the end of dobj (assuming that it ends at dcp) and the width of the trailing area ----------------------------------------------------------------------------*/ void GetTrailInfoText(PDOBJ pdobj, LSDCP dcp, DWORD* pcNumOfTrailSpaces, long* pdurTrailing) { PILSOBJ pilsobj; PTXTOBJ ptxtobj; long iwch; Assert(dcp > 0); ptxtobj = (PTXTOBJ)pdobj; pilsobj = ptxtobj->plnobj->pilsobj; *pcNumOfTrailSpaces = 0; *pdurTrailing = 0; if (ptxtobj->txtkind == txtkindEOL) { Assert(dcp == 1); *pcNumOfTrailSpaces = 1; *pdurTrailing = ptxtobj->plnobj->pilsobj->pdur[ptxtobj->iwchFirst]; } else if (!(pilsobj->grpf & fTxtWrapAllSpaces)) { if (ptxtobj->txtkind == txtkindRegular) { Assert(ptxtobj->iwchLim >= ptxtobj->iwchFirst + (long)dcp); if (!(ptxtobj->txtf & txtfGlyphBased)) { for (iwch = ptxtobj->iwchFirst + dcp - 1; iwch >= ptxtobj->iwchFirst && pilsobj->pwchOrig[iwch] == pilsobj->wchSpace; iwch--) { (*pcNumOfTrailSpaces)++; *pdurTrailing += pilsobj->pdur[iwch]; } } else { long igindFirst = 0; long iwchFirst = 0; long igindLast; long igind; Assert(FIwchLastInContext(pilsobj, ptxtobj->iwchFirst + dcp - 1)); igindLast = IgindLastFromIwch(ptxtobj, ptxtobj->iwchFirst + dcp - 1); for (iwch = ptxtobj->iwchFirst + dcp - 1; iwch >= ptxtobj->iwchFirst && pilsobj->pwchOrig[iwch] == pilsobj->wchSpace; iwch--); if (iwch < ptxtobj->iwchFirst) { iwchFirst = ptxtobj->iwchFirst; igindFirst = ptxtobj->igindFirst; } else { iwchFirst = IwchLastFromIwch(ptxtobj, iwch) + 1; igindFirst = IgindLastFromIwch(ptxtobj, iwch) + 1; } *pcNumOfTrailSpaces = ptxtobj->iwchFirst + dcp - iwchFirst; Assert(igindLast < ptxtobj->igindLim); for (igind = igindFirst; igind <= igindLast; igind++) *pdurTrailing += pilsobj->pdurGind[igind]; } } else if (ptxtobj->txtkind == txtkindSpecSpace) { *pcNumOfTrailSpaces = dcp; *pdurTrailing = 0; for (iwch = ptxtobj->iwchFirst + dcp - 1; iwch >= ptxtobj->iwchFirst; iwch--) *pdurTrailing += pilsobj->pdur[iwch]; } } } /* F S U S P E C T D E V I C E D I F F E R E N T */ /*---------------------------------------------------------------------------- %%Function: FSuspectDeviceDifferent %%Contact: sergeyge Returns TRUE if Visi character or NonReqHyphen-like character might be present on the line, and therefore fast prep-for-displaying is impossible in the case when fPresEqualRef is TRUE ----------------------------------------------------------------------------*/ BOOL FSuspectDeviceDifferent(PLNOBJ plnobj) { return (plnobj->pilsobj->fDifficultForAdjust); } /* F Q U I C K S C A L I N G */ /*---------------------------------------------------------------------------- %%Function: FQuickScaling %%Contact: sergeyge Checks if fast scaling is possible in the case when fPresEqualRef is FALSE ----------------------------------------------------------------------------*/ BOOL FQuickScaling(PLNOBJ plnobj, BOOL fVertical, long durTotal) { PILSOBJ pilsobj; long durMax; pilsobj = plnobj->pilsobj; durMax = pilsobj->durRightMaxX; if (fVertical) durMax = pilsobj->durRightMaxY; return (durTotal < durMax && !pilsobj->fDifficultForAdjust && plnobj->ptxtobjFirst == plnobj->ptxtobj); } #define UpFromUrFast(ur) ( ((ur) * MagicConstant + (1 << 20)) >> 21) /* Q U I C K A D J U S T E X A C T */ /*---------------------------------------------------------------------------- %%Function: AdjustText %%Contact: sergeyge Fast scaling: does not check for width restrictions and for Visi situations, assumes that there is only text on the line. ----------------------------------------------------------------------------*/ void QuickAdjustExact(PDOBJ* rgpdobj, DWORD cdobj, DWORD cNumOfTrailSpaces, BOOL fVertical, long* pdupText, long* pdupTrail) { LSERR lserr; PILSOBJ pilsobj; PLNOBJ plnobj; PTXTOBJ ptxtobj; long* rgdur; long* rgdup; long durSum; long dupSum; long dupErrLast; long dupPrevChar; long MagicConstant; long dupIdeal; long dupReal; long dupErrNew; long dupAdjust; long wCarry; long iwchPrev; long iwch; long itxtobj; long dupTotal; Assert(cdobj > 0); plnobj = ((PTXTOBJ)rgpdobj[0])->plnobj; pilsobj = plnobj->pilsobj; Assert(!pilsobj->fDifficultForAdjust); rgdur = pilsobj->pdur; rgdup = plnobj->pdup; if (fVertical) MagicConstant = pilsobj->MagicConstantY; else MagicConstant = pilsobj->MagicConstantX; itxtobj = 0; durSum = 0; dupPrevChar = 0; /* Pretty dirty; we make sure that for the first iteration dupAdjust will be 0 */ iwchPrev = ((PTXTOBJ)rgpdobj[0])->iwchFirst; dupErrLast = rgdup[iwchPrev] - UpFromUrFast(rgdur[iwchPrev]); dupSum = 0; for(itxtobj = 0; itxtobj < (long)cdobj; itxtobj++) { ptxtobj = (PTXTOBJ) rgpdobj[itxtobj]; Assert(ptxtobj->txtkind != txtkindTab); Assert(!(ptxtobj->txtf & txtfGlyphBased)); for(iwch = ptxtobj->iwchFirst; iwch < ptxtobj->iwchLim; iwch++) { durSum += rgdur[iwch]; /* here David Bangs algorithm starts */ dupIdeal = UpFromUrFast(durSum) - dupSum; Assert(dupIdeal >= 0); dupReal = rgdup[iwch]; dupErrNew = dupReal - dupIdeal; dupAdjust = dupErrNew - dupErrLast; Assert(iwch > ((PTXTOBJ)rgpdobj[0])->iwchFirst || dupAdjust == 0); if (dupAdjust != 0) { wCarry = dupAdjust & 1; if (dupAdjust > 0) { dupAdjust >>= 1; if (dupErrLast < -dupErrNew) dupAdjust += wCarry; dupAdjust = min(dupPrevChar /*-1*/, dupAdjust); } else { dupAdjust >>= 1; if (dupErrNew < -dupErrLast) dupAdjust += wCarry; dupAdjust = max(/*1*/ - dupIdeal, dupAdjust); } rgdup[iwchPrev] -= dupAdjust; dupIdeal += dupAdjust; } rgdup[iwch] = dupIdeal; dupSum += (dupIdeal - dupAdjust); dupErrLast = dupReal - dupIdeal; iwchPrev = iwch; dupPrevChar = dupIdeal; /* here David Bangs algorithm stops */ } } *pdupText = 0; *pdupTrail = 0; for (itxtobj=0; itxtobj < (long)cdobj - 1; itxtobj++) { ptxtobj = (PTXTOBJ) rgpdobj[itxtobj]; dupTotal = 0; for(iwch = ptxtobj->iwchFirst; iwch < ptxtobj->iwchLim; iwch++) dupTotal += rgdup[iwch]; *pdupText += dupTotal; lserr = LsdnSetTextDup(plnobj->pilsobj->plsc, ptxtobj->plsdnUpNode, dupTotal); Assert(lserr == lserrNone); } Assert(itxtobj == (long)cdobj - 1); ptxtobj = (PTXTOBJ) rgpdobj[itxtobj]; Assert(ptxtobj->txtkind == txtkindEOL && cNumOfTrailSpaces == 1|| ptxtobj->iwchLim - ptxtobj->iwchFirst > (long)cNumOfTrailSpaces); dupTotal = 0; for (iwch = ptxtobj->iwchLim - 1; iwch > ptxtobj->iwchLim - (long)cNumOfTrailSpaces - 1; iwch--) { dupTotal += rgdup[iwch]; *pdupTrail += rgdup[iwch]; } Assert(iwch == ptxtobj->iwchLim - (long)cNumOfTrailSpaces - 1); for (; iwch >= ptxtobj->iwchFirst; iwch--) { dupTotal += rgdup[iwch]; } *pdupText += dupTotal; lserr = LsdnSetTextDup(plnobj->pilsobj->plsc, ptxtobj->plsdnUpNode, dupTotal); Assert(lserr == lserrNone); return; } /* Internal functions implementation */ /* G E T F I R S T P O S A F T E R S T A R T S P A C E S */ /*---------------------------------------------------------------------------- %%Function: GetFirstPosAfterStartSpaces %%Contact: sergeyge Reports index of the first char after leading spaces ----------------------------------------------------------------------------*/ static void GetFirstPosAfterStartSpaces(const LSGRCHNK* plsgrchnk, long itxtobjLast, long iwchLim, long* pitxtobjAfterStartSpaces, long* piwchAfterStartSpaces, BOOL* pfFirstOnLineAfter) { PILSOBJ pilsobj; PLNOBJ plnobj; long iwch; BOOL fInStartSpace; long itxtobj; PTXTOBJ ptxtobj; long iwchLimInDobj; PLSCHNK rglschnk; Assert(plsgrchnk->clsgrchnk > 0); rglschnk = plsgrchnk->plschnk; plnobj = ((PTXTOBJ)rglschnk[0].pdobj)->plnobj; pilsobj = plnobj->pilsobj; itxtobj = 0; ptxtobj = (PTXTOBJ)rglschnk[0].pdobj; iwch = 0; *pitxtobjAfterStartSpaces = 0; *piwchAfterStartSpaces = ptxtobj->iwchFirst; *pfFirstOnLineAfter = !(plsgrchnk->pcont[0] & fcontNonTextBefore); fInStartSpace = *pfFirstOnLineAfter; while (fInStartSpace && itxtobj <= itxtobjLast) { ptxtobj = (PTXTOBJ)rglschnk[itxtobj].pdobj; iwchLimInDobj = iwchLim; if (itxtobj < itxtobjLast) iwchLimInDobj = ptxtobj->iwchLim; if (plsgrchnk->pcont[itxtobj] & fcontNonTextBefore) { *pfFirstOnLineAfter = fFalse; *pitxtobjAfterStartSpaces = itxtobj; *piwchAfterStartSpaces = ptxtobj->iwchFirst; fInStartSpace = fFalse; } else if (ptxtobj->txtkind == txtkindRegular) { for (iwch = ptxtobj->iwchFirst; iwch < iwchLimInDobj && pilsobj->pwchOrig[iwch] == pilsobj->wchSpace; iwch++); if ((ptxtobj->txtf & txtfGlyphBased) && iwch < iwchLimInDobj) { for(; !FIwchFirstInContext(pilsobj, iwch); iwch--); Assert(iwch >= ptxtobj->iwchFirst); } if (iwch < iwchLimInDobj) { *pitxtobjAfterStartSpaces = itxtobj; *piwchAfterStartSpaces = iwch; fInStartSpace = fFalse; } } /* REVIEW: sergeyge---should something be changed in the following check? */ else if (ptxtobj->txtkind != txtkindEOL // && ptxtobj->txtkind != txtkindSpecSpace ) { *pitxtobjAfterStartSpaces = itxtobj; *piwchAfterStartSpaces = ptxtobj->iwchFirst; fInStartSpace = fFalse; } itxtobj++; iwch = iwchLimInDobj; } if (fInStartSpace) { *pitxtobjAfterStartSpaces = itxtobj; *piwchAfterStartSpaces = iwchLim; } return; } /* H A N D L E S I M P L E T E X T W Y S I */ /*---------------------------------------------------------------------------- %%Function: HandleSimpleTextWysi %%Contact: sergeyge Implements Latin-like justification in spaces (if needed) on the reference device and WYSIWYG algorithm for the exact positioning under assumption that there were no NominalToIdeal modifications (except for Latin kerning) on the line. Startegy: Distribute in spaces if needed Scale down width of spaces from the reference device to the presentation one Apply WYSIWYG algorithm ----------------------------------------------------------------------------*/ static LSERR HandleSimpleTextWysi(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long durToDistribute, long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, BOOL fExactSync, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces, long* pdupText, long* pdupTail) { PTXTOBJ ptxtobj; BOOL fFullyJustified; fFullyJustified = fFalse; if (itxtobjLast > itxtobjAfterStartSpaces || (itxtobjLast == itxtobjAfterStartSpaces && iwchLast >= iwchAfterStartSpaces)) { ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj; if (lskjust != lskjNone && durToDistribute > 0) { FullPositiveSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, ptxtobj->plnobj->pilsobj->pdur, NULL, durToDistribute, &fFullyJustified); ScaleSpaces(plsgrchnk, lstflow, itxtobjLast, iwchLast); } else if (!fForcedBreak && durToDistribute < 0) { fFullyJustified = fTrue; NegativeSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, ptxtobj->plnobj->pilsobj->pdur, NULL, -durToDistribute); ScaleSpaces(plsgrchnk, lstflow, itxtobjLast, iwchLast); } } Unreferenced(fExactSync); /* if (fExactSync)*/ ApplyWysi(plsgrchnk, lstflow); /* else ApplyNonExactWysi(plsgrchnk, lstflow); */ return FinalAdjustmentOnPres(plsgrchnk, itxtobjLast, iwchLast, dupAvailable, fFullyJustified, fForcedBreak, fSuppressTrailingSpaces, pdupText, pdupTail); } /* H A N D L E S I M P L E T E X T P R E S */ /*---------------------------------------------------------------------------- %%Function: HandleSimpleTextPres %%Contact: sergeyge Implements Latin-like justification in spaces (if needed) on the presentation device under assumption that there were no NominalToIdeal modifications (except for Latin kerning) on the line. ----------------------------------------------------------------------------*/ static LSERR HandleSimpleTextPres(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long dupAvailable, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces, long* pdupText, long* pdupTail) { PTXTOBJ ptxtobj; BOOL fFullyJustified; long* rgdup; long itxtobj; long iwchLim; long iwch; long dupTotal; long dupToDistribute; if (itxtobjLast > itxtobjAfterStartSpaces || (itxtobjLast == itxtobjAfterStartSpaces && iwchLast >= iwchAfterStartSpaces)) { ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj; rgdup = ptxtobj->plnobj->pdup; dupTotal = 0; /* REVIEW sergeyge: should we think about eliminating this loop for online view? */ for (itxtobj=0; itxtobj <= itxtobjLast; itxtobj++) { ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj; iwchLim = iwchLast + 1; if (itxtobj < itxtobjLast) iwchLim = ptxtobj->iwchLim; for (iwch = ptxtobj->iwchFirst; iwch < iwchLim; iwch++) { dupTotal += rgdup[iwch]; } } dupToDistribute = dupAvailable - dupTotal; if (lskjust != lskjNone && dupToDistribute > 0) { FullPositiveSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, rgdup, NULL, dupToDistribute, &fFullyJustified); } else if (!fForcedBreak && dupToDistribute < 0) { NegativeSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, rgdup, NULL, -dupToDistribute); } } return FinalAdjustmentOnPres(plsgrchnk, itxtobjLast, iwchLast, dupAvailable, fFalse, fForcedBreak, fSuppressTrailingSpaces, pdupText, pdupTail); } /* H A N D L E G E N E R A L S P A C E S E X A C T S Y N C */ /*---------------------------------------------------------------------------- %%Function: HandleGeneralSpacesExactSync %%Contact: sergeyge Implements Latin-like justification in spaces (if needed) on the reference device and WYSIWYG algorithm for the exact positioning in the general case Startegy: Distribute in spaces if needed Scale down changes applied to characters during NTI and distribution If glyphs were detected on the line, scale down changes apllied to glyphs during NTI and adjust offsets Apply WYSIWYG algorithm If some characters were changed on the left side prepare additional width array for the display time ----------------------------------------------------------------------------*/ static LSERR HandleGeneralSpacesExactSync(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long durToDistribute, long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces, long* pdupText, long* pdupTail) { LSERR lserr; PLNOBJ plnobj; PILSOBJ pilsobj; PTXTOBJ ptxtobj; BOOL fFullyJustified = fFalse; BOOL fLeftSideAffected = fFalse; BOOL fGlyphDetected = fFalse; plnobj = ((PTXTOBJ) plsgrchnk->plschnk[0].pdobj)->plnobj; pilsobj = plnobj->pilsobj; if (itxtobjLast > itxtobjAfterStartSpaces || (itxtobjLast == itxtobjAfterStartSpaces && iwchLast >= iwchAfterStartSpaces)) { ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj; if (lskjust != lskjNone && durToDistribute > 0) { FullPositiveSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, pilsobj->pdur, pilsobj->pdurGind, durToDistribute, &fFullyJustified); } else if (!fForcedBreak && durToDistribute < 0) { fFullyJustified = fTrue; NegativeSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, pilsobj->pdur, pilsobj->pdurGind, -durToDistribute); } } ScaleCharSides(plsgrchnk, lstflow, &fLeftSideAffected, &fGlyphDetected); if (fGlyphDetected) { ScaleGlyphSides(plsgrchnk, lstflow); UpdateGlyphOffsets(plsgrchnk); SetBeforeJustCopy(plsgrchnk); } ApplyWysi(plsgrchnk, lstflow); lserr = FinalAdjustmentOnPres(plsgrchnk, itxtobjLast, iwchLast, dupAvailable, fFullyJustified, fForcedBreak, fSuppressTrailingSpaces, pdupText, pdupTail); if (lserr != lserrNone) return lserr; /* If pdupPen is already used, don't forget to copy pdup there---ScaleSides could change it */ if (fLeftSideAffected || plnobj->pdup != plnobj->pdupPen) { lserr = FillDupPen(plsgrchnk, lstflow, itxtobjLast, iwchLast); if (lserr != lserrNone) return lserr; } return lserrNone; } /* H A N D L E G E N E R A L S P A C E S P R E S */ /*---------------------------------------------------------------------------- %%Function: HandleGeneralSpacesPres %%Contact: sergeyge Implements Latin-like justification in spaces (if needed) directly on the presentation device in the general case Startegy: Scale down changes applied to characters during NTI If glyphs were detected on the line, scale down changes apllied to glyphs during NTI and adjust glyph offsets Distribute in spaces if needed If glyphs were detected on the line, adjust glyph offsets If some characters were changed on the left side prepare additional width array for the display time ----------------------------------------------------------------------------*/ static LSERR HandleGeneralSpacesPres(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces, long* pdupText, long* pdupTail) { LSERR lserr; PLNOBJ plnobj; PTXTOBJ ptxtobj; PTXTOBJ ptxtobjLast; long* rgdup; BOOL fFullyJustified; long itxtobj; long iwchLastInDobj; long iFirst; long iLim; long i; long dupTotal; long dupToDistribute; BOOL fLeftSideAffected = fFalse; BOOL fGlyphDetected = fFalse; ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[max(0, itxtobjLast)].pdobj; plnobj = ptxtobjLast->plnobj; ScaleCharSides(plsgrchnk, lstflow, &fLeftSideAffected, &fGlyphDetected); if (fGlyphDetected) { ScaleGlyphSides(plsgrchnk, lstflow); UpdateGlyphOffsets(plsgrchnk); SetBeforeJustCopy(plsgrchnk); } if (itxtobjLast > itxtobjAfterStartSpaces || (itxtobjLast == itxtobjAfterStartSpaces && iwchLast >= iwchAfterStartSpaces)) { ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj; dupTotal = 0; for (itxtobj=0; itxtobj <= itxtobjLast; itxtobj++) { ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj; if (ptxtobj->txtf & txtfGlyphBased) { iFirst = ptxtobj->igindFirst; iwchLastInDobj = iwchLast; if (itxtobj < itxtobjLast) iwchLastInDobj = ptxtobj->iwchLim - 1; iLim = IgindLastFromIwch(ptxtobj, iwchLastInDobj) + 1; rgdup = plnobj->pdupGind; } else { iFirst = ptxtobj->iwchFirst; iLim = iwchLast + 1; if (itxtobj < itxtobjLast) iLim = ptxtobj->iwchLim; rgdup = plnobj->pdup; } for (i =iFirst; i < iLim; i++) { dupTotal += rgdup[i]; } } dupToDistribute = dupAvailable - dupTotal; if (lskjust != lskjNone && dupToDistribute > 0) { FullPositiveSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, plnobj->pdup, plnobj->pdupGind, dupToDistribute, &fFullyJustified); } else if (!fForcedBreak && dupToDistribute < 0) { NegativeSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, plnobj->pdup, plnobj->pdupGind, -dupToDistribute); } if (fGlyphDetected) { UpdateGlyphOffsets(plsgrchnk); } } lserr = FinalAdjustmentOnPres(plsgrchnk, itxtobjLast, iwchLast, dupAvailable, fFalse, fForcedBreak, fSuppressTrailingSpaces, pdupText, pdupTail); if (lserr != lserrNone) return lserr; /* If pdupPen is already used, don't forget to copy pdup there---ScaleSides could change it */ if (fLeftSideAffected || plnobj->pdup != plnobj->pdupPen) { lserr = FillDupPen(plsgrchnk, lstflow, itxtobjLast, iwchLast); if (lserr != lserrNone) return lserr; } return lserrNone; } /* H A N D L E T A B L E B A S E D */ /*---------------------------------------------------------------------------- %%Function: HandleTableBased %%Contact: sergeyge Implements FE-like justification or compression on the reference device and WYSIWYG algorithm for the exact positioning Startegy: Apply needed type of justification or compression Scale down changes applied to characters during NTI and justification If glyphs were detected on the line, scale down changes apllied to glyphs during NTI and adjust offsets Apply WYSIWYG algorithm If some characters were changed on the left side prepare additional width array for the display time ----------------------------------------------------------------------------*/ static LSERR HandleTablesBased(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long durToDistribute, long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, BOOL fFirstOnLineAfter, long itxtobjLast, long iwchLast, long cNonText, BOOL fLastObjectIsText, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces, long* pdupText, long* pdupTail, long* pdupExtNonText) { LSERR lserr; PILSOBJ pilsobj = NULL; PLNOBJ plnobj; long durExtNonText = 0; DWORD clschnk; MWCLS mwclsLast; long durCompLastLeft = 0; long durCompLastRight = 0; long durHangingChar; long dupHangingChar = 0; BOOL fHangingUsed = fFalse; long durCompressTotal; long iwchLastTemp; BOOL fScaledExp; BOOL fFullyJustified = fFalse; BOOL fLeftSideAffected = fFalse; BOOL fGlyphDetected = fFalse; Assert(lskjust == lskjFullInterLetterAligned || lskjust == lskjFullScaled || lskjust == lskjNone); *pdupExtNonText = 0; clschnk = plsgrchnk->clsgrchnk; Assert(clschnk > 0); plnobj = ((PTXTOBJ) plsgrchnk->plschnk[0].pdobj)->plnobj; pilsobj = plnobj->pilsobj; if (itxtobjLast > itxtobjAfterStartSpaces || (itxtobjLast == itxtobjAfterStartSpaces && iwchLast >= iwchAfterStartSpaces)) { Assert(clschnk > 0); if (pilsobj->fSnapGrid) { if (durToDistribute < 0) { Assert(-durToDistribute <= pilsobj->pdur[iwchLast]); fHangingUsed = fTrue; } } else if (durToDistribute < 0) { fFullyJustified = fTrue; lserr = FetchCompressInfo(plsgrchnk, fFirstOnLineAfter, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast + 1, LONG_MAX, &durCompressTotal); if (lserr != lserrNone) return lserr; if (fLastObjectIsText && !(((PTXTOBJ) plsgrchnk->plschnk[0].pdobj)->txtf & txtfGlyphBased)) GetCompLastCharInfo(pilsobj, iwchLast, &mwclsLast, &durCompLastRight, &durCompLastLeft); if (pilsobj->ptxtinf[iwchLast].fHangingPunct) { Assert(lskjust == lskjNone || lskjust == lskjFullInterLetterAligned || lskjust == lskjFullScaled); Assert(fLastObjectIsText); if (durCompLastRight >= -durToDistribute) { Assert(durCompLastRight > 0); CompressLastCharRight(pilsobj, iwchLast, durCompLastRight); if (lskjust != lskjNone) { fScaledExp = (lskjust != lskjFullInterLetterAligned); lserr = ApplyExpand(plsgrchnk, lstflow, fScaledExp, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, cNonText, durCompLastRight + durToDistribute, &durExtNonText, &fFullyJustified); if (lserr != lserrNone) return lserr; } } else if (durCompressTotal - durCompLastRight >= -durToDistribute) { lserr = ApplyCompress(plsgrchnk, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, -durToDistribute); if (lserr != lserrNone) return lserr; } else if (durCompressTotal >= -durToDistribute) { if (durCompLastRight > 0) CompressLastCharRight(pilsobj, iwchLast, durCompLastRight); lserr = ApplyCompress(plsgrchnk, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast + 1, -durToDistribute - durCompLastRight); if (lserr != lserrNone) return lserr; } else { durHangingChar = pilsobj->pdur[iwchLast]; /* Order of operations is important here because dur of the hanging punctuation gets chnaged in the next lines of code and durHangingChar is used in ApplyCompress/ApplyExpand calls below!!! */ if (durCompLastRight > 0) CompressLastCharRight(pilsobj, iwchLast, durCompLastRight); fHangingUsed = fTrue; if (durHangingChar + durToDistribute >= 0) { fScaledExp = (lskjust != lskjFullInterLetterAligned); lserr = ApplyExpand(plsgrchnk, lstflow, fScaledExp, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, cNonText, durHangingChar + durToDistribute, &durExtNonText, &fFullyJustified); if (lserr != lserrNone) return lserr; } else { lserr = ApplyCompress(plsgrchnk, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, -durToDistribute - durHangingChar); if (lserr != lserrNone) return lserr; } } } else { if (durCompLastRight >= -durToDistribute) { Assert(!(((PTXTOBJ) plsgrchnk->plschnk[0].pdobj)->txtf & txtfGlyphBased)); CompressLastCharRight(pilsobj, iwchLast, -durToDistribute); } else { if (durCompLastRight > 0) { Assert(!(((PTXTOBJ) plsgrchnk->plschnk[0].pdobj)->txtf & txtfGlyphBased)); CompressLastCharRight(pilsobj, iwchLast, durCompLastRight); } lserr = ApplyCompress(plsgrchnk, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast + 1, -durToDistribute - durCompLastRight); if (lserr != lserrNone) return lserr; } } } else { /* Assert (durToDistribute >= 0 || iwchLast == iwchAfterStartSpaces);---Unfortunately it might be not true for the second line of Warichu, because durTotal for it is scaled up value of dup of the first line */ if (lskjust != lskjNone && durToDistribute > 0) { Assert(lskjust == lskjFullScaled || lskjust == lskjFullInterLetterAligned); iwchLastTemp = iwchLast; if (!fLastObjectIsText) iwchLastTemp++; lserr = ApplyExpand(plsgrchnk, lstflow, lskjust == lskjFullScaled, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLastTemp, cNonText, durToDistribute, &durExtNonText, &fFullyJustified); if (lserr != lserrNone) return lserr; } } } else if (cNonText != 0 && lskjust != lskjNone && durToDistribute > 0) { durExtNonText = durToDistribute; } ScaleExtNonText(pilsobj, lstflow, durExtNonText, pdupExtNonText); ScaleCharSides(plsgrchnk, lstflow, &fLeftSideAffected, &fGlyphDetected); if (fGlyphDetected) { ScaleGlyphSides(plsgrchnk, lstflow); UpdateGlyphOffsets(plsgrchnk); SetBeforeJustCopy(plsgrchnk); } ApplyWysi(plsgrchnk, lstflow); if (fHangingUsed) GetDupLastChar(plsgrchnk, iwchLast, &dupHangingChar); lserr = FinalAdjustmentOnPres(plsgrchnk, itxtobjLast, iwchLast, dupAvailable + dupHangingChar - *pdupExtNonText, fFullyJustified, fForcedBreak, fSuppressTrailingSpaces, pdupText, pdupTail); if (lserr != lserrNone) return lserr; /* If pdupPen is already used, don't forget to copy pdup there---ScaleSides could change it */ if (fLeftSideAffected || plnobj->pdup != plnobj->pdupPen) { lserr = FillDupPen(plsgrchnk, lstflow, itxtobjLast, iwchLast); if (lserr != lserrNone) return lserr; } return lserrNone; } /* H A N D L E F U L L G L Y P H S E X A C T S Y N C */ /*---------------------------------------------------------------------------- %%Function: HandleFullGlyphsExactSync %%Contact: sergeyge Implements glyph-based justification on the reference device and WYSIWYG algorithm for the exact positioning Startegy: Apply glyph-based justification if needed Scale down changes applied to characters during NTI and justification If glyphs were detected on the line, scale down changes apllied to glyphs during NTI and adjust offsets Apply WYSIWYG algorithm If some characters were changed on the left side prepare additional width array for the display time ----------------------------------------------------------------------------*/ static LSERR HandleFullGlyphsExactSync(const LSGRCHNK* plsgrchnk, long durToDistribute, long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces, long* pdupText, long* pdupTail) { LSERR lserr; PILSOBJ pilsobj; PLNOBJ plnobj; BOOL fFullyJustified = fFalse; BOOL fLeftSideAffected = fFalse; BOOL fGlyphDetected = fFalse; plnobj = ((PTXTOBJ) plsgrchnk->plschnk[0].pdobj)->plnobj; pilsobj = plnobj->pilsobj; ScaleGlyphSides(plsgrchnk, lstflow); UpdateGlyphOffsets(plsgrchnk); SetBeforeJustCopy(plsgrchnk); if (itxtobjLast > itxtobjAfterStartSpaces || (itxtobjLast == itxtobjAfterStartSpaces && iwchLast >= iwchAfterStartSpaces)) { lserr = ApplyGlyphExpand(plsgrchnk, lstflow, lsdevReference, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, durToDistribute, pilsobj->pdur, pilsobj->pdurGind, pilsobj->pdurRight, pilsobj->pduGright, &fFullyJustified); if (lserr != lserrNone) return lserr; } ScaleCharSides(plsgrchnk, lstflow, &fLeftSideAffected, &fGlyphDetected); if (fGlyphDetected) { ScaleGlyphSides(plsgrchnk, lstflow); UpdateGlyphOffsets(plsgrchnk); } ApplyWysi(plsgrchnk, lstflow); lserr = FinalAdjustmentOnPres(plsgrchnk, itxtobjLast, iwchLast, dupAvailable, fFullyJustified, fForcedBreak, fSuppressTrailingSpaces, pdupText, pdupTail); if (lserr != lserrNone) return lserr; /* If pdupPen is already used, don't forget to copy pdup there---ScaleSides could change it */ if (fLeftSideAffected || plnobj->pdup != plnobj->pdupPen) { lserr = FillDupPen(plsgrchnk, lstflow, itxtobjLast, iwchLast); if (lserr != lserrNone) return lserr; } return lserrNone; } /* H A N D L E F U L L G L Y P H S P R E S */ /*---------------------------------------------------------------------------- %%Function: HandleFullGlyphsPres %%Contact: sergeyge Implements glyph-based justification directly on the presentation device Startegy: Scale down changes applied to characters during NTI If glyphs were detected on the line, scale down changes apllied to glyphs during NTI and adjust offsets Apply glyph-based justification if needed If glyphs were detected on the line, adjust offsets If some characters were changed on the left side prepare additional width array for the display time ----------------------------------------------------------------------------*/ static LSERR HandleFullGlyphsPres(const LSGRCHNK* plsgrchnk, long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces, long* pdupText, long* pdupTail) { LSERR lserr; PILSOBJ pilsobj; PLNOBJ plnobj; PTXTOBJ ptxtobj; PTXTOBJ ptxtobjLast; long* rgdup; long itxtobj; long iwchLastInDobj; long iFirst; long iLim; long i; long dupTotal; long dupToDistribute; BOOL fFullyJustified = fFalse; BOOL fLeftSideAffected = fFalse; BOOL fGlyphDetected = fFalse; ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[max(0, itxtobjLast)].pdobj; plnobj = ptxtobjLast->plnobj; pilsobj = plnobj->pilsobj; ScaleCharSides(plsgrchnk, lstflow, &fLeftSideAffected, &fGlyphDetected); if (fGlyphDetected) { ScaleGlyphSides(plsgrchnk, lstflow); UpdateGlyphOffsets(plsgrchnk); SetBeforeJustCopy(plsgrchnk); } if (itxtobjLast > itxtobjAfterStartSpaces || (itxtobjLast == itxtobjAfterStartSpaces && iwchLast >= iwchAfterStartSpaces)) { rgdup = plnobj->pdup; dupTotal = 0; for (itxtobj=0; itxtobj <= itxtobjLast; itxtobj++) { ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj; if (ptxtobj->txtf & txtfGlyphBased) { iFirst = ptxtobj->igindFirst; iwchLastInDobj = iwchLast; if (itxtobj < itxtobjLast) iwchLastInDobj = ptxtobj->iwchLim - 1; iLim = IgindLastFromIwch(ptxtobj, iwchLastInDobj) + 1; rgdup = plnobj->pdupGind; } else { iFirst = ptxtobj->iwchFirst; iLim = iwchLast + 1; if (itxtobj < itxtobjLast) iLim = ptxtobj->iwchLim; rgdup = plnobj->pdup; } for (i =iFirst; i < iLim; i++) { dupTotal += rgdup[i]; } } dupToDistribute = dupAvailable - dupTotal; lserr = ApplyGlyphExpand(plsgrchnk, lstflow, lsdevPres, itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, dupToDistribute, plnobj->pdup, plnobj->pdupGind, pilsobj->pdurRight, pilsobj->pduGright, &fFullyJustified); if (lserr != lserrNone) return lserr; if (fGlyphDetected) { UpdateGlyphOffsets(plsgrchnk); } } lserr = FinalAdjustmentOnPres(plsgrchnk, itxtobjLast, iwchLast, dupAvailable, fFalse, fForcedBreak, fSuppressTrailingSpaces, pdupText, pdupTail); if (lserr != lserrNone) return lserr; /* If pdupPen is already used, don't forget to copy pdup there---ScaleSides could change it */ if (fLeftSideAffected || plnobj->pdup != plnobj->pdupPen) { lserr = FillDupPen(plsgrchnk, lstflow, itxtobjLast, iwchLast); if (lserr != lserrNone) return lserr; } return lserrNone; }