WindowsXP-SP1/windows/richedit/lssrc/lstxtbr1.c
2020-09-30 16:53:49 +02:00

726 lines
23 KiB
C

#include <limits.h>
#include "lsmem.h"
#include "lstxtbr1.h"
#include "lstxtbrs.h"
#include "lstxtmap.h"
#include "lsdntext.h"
#include "brko.h"
#include "locchnk.h"
#include "locchnk.h"
#include "posichnk.h"
#include "objdim.h"
#include "lstxtffi.h"
#include "txtils.h"
#include "txtln.h"
#include "txtobj.h"
static void TruncateGlyphBased(PTXTOBJ ptxtobj, long itxtobj, long urTotal, long urColumnMax,
PPOSICHNK pposichnk);
/* Export Functions Implementation */
/* Q U I C K B R E A K T E X T */
/*----------------------------------------------------------------------------
%%Function: QuickBreakText
%%Contact: sergeyge
Breaks the line if it is easy to do, namely:
-- break-character is space
-- previous character is not space
----------------------------------------------------------------------------*/
LSERR QuickBreakText(PDOBJ pdobj, BOOL* pfSuccessful, LSDCP* pdcpBreak, POBJDIM pobjdim)
{
LSERR lserr;
PILSOBJ pilsobj;
PTXTOBJ ptxtobj;
long iwchSpace;
long dur;
*pfSuccessful = fFalse;
ptxtobj = (PTXTOBJ)pdobj;
pilsobj = ptxtobj->plnobj->pilsobj;
Assert(!(pilsobj->grpf & fTxtDoHyphenation));
Assert(!(pilsobj->grpf & fTxtWrapTrailingSpaces));
Assert(!(pilsobj->grpf & fTxtWrapAllSpaces));
Assert(!(ptxtobj->txtf & txtfGlyphBased));
if (ptxtobj->txtkind == txtkindRegular)
{
if (!(pilsobj->grpf & fTxtApplyBreakingRules))
{
if (ptxtobj->u.reg.iwSpacesLim > ptxtobj->u.reg.iwSpacesFirst)
{
iwchSpace = pilsobj->pwSpaces[ptxtobj->u.reg.iwSpacesLim - 1];
Assert(iwchSpace < ptxtobj->iwchLim - 1); /* formatting never stops at space */
if (iwchSpace + 1 - ptxtobj->iwchFirst > ptxtobj->u.reg.iwSpacesLim - ptxtobj->u.reg.iwSpacesFirst)
{
*pfSuccessful = fTrue;
*pdcpBreak = iwchSpace - ptxtobj->iwchFirst + 1;
lserr = CalcPartWidths(ptxtobj, *pdcpBreak, pobjdim, &dur);
Assert(lserr == lserrNone);
pobjdim->dur = dur;
Assert(*pdcpBreak > 1);
ptxtobj->iwchLim = iwchSpace + 1;
}
}
}
else
{
LSCP cpFirst;
PLSRUN plsrun;
long iwchFirst;
long iwchCur;
long iwchInSpace;
BRKCLS brkclsFollowingCache;
BRKCLS brkclsLeading;
BRKCLS brkclsFollowing;
Assert(pilsobj->pwchOrig[ptxtobj->iwchLim - 1] != pilsobj->wchSpace);
lserr = LsdnGetCpFirst(pilsobj->plsc, ptxtobj->plsdnUpNode, &cpFirst);
Assert(lserr == lserrNone);
lserr = LsdnGetPlsrun(pilsobj->plsc, ptxtobj->plsdnUpNode, &plsrun);
Assert(lserr == lserrNone);
iwchFirst = ptxtobj->iwchFirst;
if (ptxtobj->u.reg.iwSpacesLim > ptxtobj->u.reg.iwSpacesFirst)
iwchFirst = pilsobj->pwSpaces[ptxtobj->u.reg.iwSpacesLim - 1] + 1;
iwchCur = ptxtobj->iwchLim - 1;
lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols, plsrun,
cpFirst + (iwchCur - ptxtobj->iwchFirst),
pilsobj->pwchOrig[iwchCur], &brkclsLeading, &brkclsFollowingCache);
if (lserr != lserrNone) return lserr;
Assert(brkclsLeading < pilsobj->cBreakingClasses && brkclsFollowingCache < pilsobj->cBreakingClasses);
iwchCur--;
while (!*pfSuccessful && iwchCur >= iwchFirst)
{
brkclsFollowing = brkclsFollowingCache;
lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols, plsrun,
cpFirst + (iwchCur - ptxtobj->iwchFirst),
pilsobj->pwchOrig[iwchCur], &brkclsLeading, &brkclsFollowingCache);
if (lserr != lserrNone) return lserr;
Assert(brkclsLeading < pilsobj->cBreakingClasses && brkclsFollowingCache < pilsobj->cBreakingClasses);
*pfSuccessful = FCanBreak(pilsobj, brkclsLeading, brkclsFollowing);
iwchCur --;
}
if (!*pfSuccessful && iwchFirst > ptxtobj->iwchFirst)
{
Assert(pilsobj->pwchOrig[iwchCur] == pilsobj->wchSpace);
iwchCur--;
for (iwchInSpace = iwchCur; iwchInSpace >= ptxtobj->iwchFirst &&
pilsobj->pwchOrig[iwchInSpace] == pilsobj->wchSpace; iwchInSpace--);
if (iwchInSpace >= ptxtobj->iwchFirst)
{
brkclsFollowing = brkclsFollowingCache;
lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols, plsrun,
cpFirst + (iwchInSpace - ptxtobj->iwchFirst),
pilsobj->pwchOrig[iwchInSpace], &brkclsLeading, &brkclsFollowingCache);
if (lserr != lserrNone) return lserr;
Assert(brkclsLeading < pilsobj->cBreakingClasses && brkclsFollowingCache < pilsobj->cBreakingClasses);
*pfSuccessful = FCanBreakAcrossSpaces(pilsobj, brkclsLeading, brkclsFollowing);
}
}
if (*pfSuccessful)
{
*pdcpBreak = iwchCur + 1 - ptxtobj->iwchFirst + 1;
lserr = CalcPartWidths(ptxtobj, *pdcpBreak, pobjdim, &dur);
Assert(lserr == lserrNone);
pobjdim->dur = dur;
Assert(*pdcpBreak >= 1);
ptxtobj->iwchLim = iwchCur + 2;
}
}
}
return lserrNone;
}
/* S E T B R E A K T E X T */
/*----------------------------------------------------------------------------
%%Function:SetBreakText
%%Contact: sergeyge
----------------------------------------------------------------------------*/
LSERR WINAPI SetBreakText(PDOBJ pdobj, BRKKIND brkkind, DWORD nBreakRec, BREAKREC* rgBreakRec, DWORD* pnActual)
{
LSERR lserr;
PLNOBJ plnobj;
PILSOBJ pilsobj;
PTXTOBJ ptxtobj;
long iwchLim;
long ibrkinf;
BREAKINFO* pbrkinf;
BOOL fInChildList;
Unreferenced(nBreakRec);
Unreferenced(rgBreakRec);
*pnActual = 0;
ptxtobj = (PTXTOBJ) pdobj;
plnobj = ptxtobj->plnobj;
pilsobj = plnobj->pilsobj;
for (ibrkinf = 0; ibrkinf < (long)pilsobj->breakinfMac &&
(pilsobj->pbreakinf[ibrkinf].pdobj != pdobj || pilsobj->pbreakinf[ibrkinf].brkkind != brkkind);
ibrkinf++ );
if (ibrkinf < (long)pilsobj->breakinfMac)
{
pbrkinf = &pilsobj->pbreakinf[ibrkinf];
switch (pbrkinf->brkt)
{
case brktNormal:
iwchLim = ptxtobj->iwchFirst + pbrkinf->dcp;
if (iwchLim < ptxtobj->iwchLim)
ptxtobj->iwchLim = iwchLim;
ptxtobj->igindLim = pbrkinf->u.normal.igindLim;
if (pbrkinf->u.normal.durFix != 0)
{
Assert(!(ptxtobj->txtf & txtfGlyphBased));
pilsobj->pdur[ptxtobj->iwchLim - 1] += pbrkinf->u.normal.durFix;
Assert (pilsobj->pdurRight != NULL);
pilsobj->pdurRight[ptxtobj->iwchLim - 1] = 0;
}
break;
case brktHyphen:
iwchLim = pbrkinf->u.hyphen.iwchLim;
ptxtobj->iwchLim = iwchLim;
plnobj->pdobjHyphen = ptxtobj;
plnobj->dwchYsr = pbrkinf->u.hyphen.dwchYsr;
pilsobj->pwchOrig[iwchLim - 1] = pilsobj->wchHyphen;
plnobj->pwch[iwchLim - 1] = pilsobj->wchHyphen;
if (pbrkinf->u.hyphen.gindHyphen != 0)
{
ptxtobj->igindLim = pbrkinf->u.hyphen.igindHyphen + 1;
plnobj->pgind[pbrkinf->u.hyphen.igindHyphen] = pbrkinf->u.hyphen.gindHyphen;
pilsobj->pdurGind[pbrkinf->u.hyphen.igindHyphen] = pbrkinf->u.hyphen.durHyphen;
plnobj->pdupGind[pbrkinf->u.hyphen.igindHyphen] = pbrkinf->u.hyphen.dupHyphen;
if (pilsobj->pduGright != NULL)
pilsobj->pduGright[pbrkinf->u.hyphen.igindHyphen] = 0;
/* REVIEW sergeyge: It would be nice to move this activity to lstxtmap module */
plnobj->pgmap[iwchLim - 1] = (WORD)(pbrkinf->u.hyphen.igindHyphen -
(ptxtobj->igindFirst - plnobj->pgmap[ptxtobj->iwchFirst]));
pilsobj->ptxtinf[iwchLim - 1].fOneToOne = fTrue;
pilsobj->ptxtinf[iwchLim - 1].fFirstInContext = fTrue;
pilsobj->ptxtinf[iwchLim - 1].fLastInContext = fTrue;
pilsobj->pginf[pbrkinf->u.hyphen.igindHyphen] = ginffOneToOne |
ginffFirstInContext | ginffLastInContext;
}
else
{
pilsobj->pdur[iwchLim - 1] = pbrkinf->u.hyphen.durHyphen;
plnobj->pdup[iwchLim - 1] = pbrkinf->u.hyphen.dupHyphen;
if (pilsobj->pdurRight != NULL)
pilsobj->pdurRight[iwchLim - 1] = 0;
if (pilsobj->pdurLeft != NULL)
pilsobj->pdurLeft[iwchLim - 1] = 0;
}
if (pbrkinf->u.hyphen.wchPrev != 0)
{
pilsobj->pwchOrig[iwchLim - 2] = pbrkinf->u.hyphen.wchPrev;
plnobj->pwch[iwchLim - 2] = pbrkinf->u.hyphen.wchPrev;
if (pbrkinf->u.hyphen.gindPrev != 0)
{
plnobj->pgind[pbrkinf->u.hyphen.igindPrev] = pbrkinf->u.hyphen.gindPrev;
pilsobj->pdurGind[pbrkinf->u.hyphen.igindPrev] = pbrkinf->u.hyphen.durPrev;
plnobj->pdupGind[pbrkinf->u.hyphen.igindPrev] = pbrkinf->u.hyphen.dupPrev;
if (pilsobj->pduGright != NULL)
pilsobj->pduGright[pbrkinf->u.hyphen.igindPrev] = 0;
/* REVIEW sergeyge: It would be nice to move this activity to lstxtmap module */
/* If Prev glyph is added the following activity is required;
If it is just replaced, we assign the same values,because ProcessYsr
would not allow replace not OneToOne character
*/
plnobj->pgmap[iwchLim - 2] = (WORD)(pbrkinf->u.hyphen.igindPrev -
(ptxtobj->igindFirst - plnobj->pgmap[ptxtobj->iwchFirst]));
pilsobj->ptxtinf[iwchLim - 2].fOneToOne = fTrue;
pilsobj->ptxtinf[iwchLim - 2].fFirstInContext = fTrue;
pilsobj->ptxtinf[iwchLim - 2].fLastInContext = fTrue;
pilsobj->pginf[pbrkinf->u.hyphen.igindPrev] = ginffOneToOne |
ginffFirstInContext | ginffLastInContext;
}
else
{
pilsobj->pdur[iwchLim - 2] = pbrkinf->u.hyphen.durPrev;
plnobj->pdup[iwchLim - 2] = pbrkinf->u.hyphen.dupPrev;
if (pilsobj->pdurRight != NULL)
pilsobj->pdurRight[iwchLim - 2] = 0;
if (pilsobj->pdurLeft != NULL)
pilsobj->pdurLeft[iwchLim - 2] = 0;
}
}
if (pbrkinf->u.hyphen.wchPrevPrev != 0)
{
pilsobj->pwchOrig[iwchLim - 3] = pbrkinf->u.hyphen.wchPrevPrev;
plnobj->pwch[iwchLim - 3] = pbrkinf->u.hyphen.wchPrevPrev;
if (pbrkinf->u.hyphen.gindPrevPrev != 0)
{
plnobj->pgind[pbrkinf->u.hyphen.igindPrevPrev] = pbrkinf->u.hyphen.gindPrevPrev;
pilsobj->pdurGind[pbrkinf->u.hyphen.igindPrevPrev] = pbrkinf->u.hyphen.durPrevPrev;
plnobj->pdupGind[pbrkinf->u.hyphen.igindPrevPrev] = pbrkinf->u.hyphen.dupPrevPrev;
if (pilsobj->pduGright != NULL)
pilsobj->pduGright[pbrkinf->u.hyphen.igindPrevPrev] = 0;
}
else
{
pilsobj->pdur[iwchLim - 3] = pbrkinf->u.hyphen.durPrevPrev;
plnobj->pdup[iwchLim - 3] = pbrkinf->u.hyphen.dupPrevPrev;
if (pilsobj->pdurRight != NULL)
pilsobj->pdurRight[iwchLim - 3] = 0;
if (pilsobj->pdurLeft != NULL)
pilsobj->pdurLeft[iwchLim - 3] = 0;
}
}
if (pbrkinf->u.hyphen.ddurDnodePrev != 0)
{
lserr = LsdnResetWidthInPreviousDnodes(pilsobj->plsc, ptxtobj->plsdnUpNode,
pbrkinf->u.hyphen.ddurDnodePrev, 0);
if (lserr != lserrNone) return lserr;
}
lserr = LsdnSetHyphenated(pilsobj->plsc);
if (lserr != lserrNone) return lserr;
break;
case brktNonReq:
Assert(pbrkinf->dcp == 1);
iwchLim = pbrkinf->u.nonreq.iwchLim;
ptxtobj->iwchLim = iwchLim;
Assert(iwchLim == ptxtobj->iwchFirst + pbrkinf->u.nonreq.dwchYsr);
plnobj->pdobjHyphen = ptxtobj;
plnobj->dwchYsr = pbrkinf->u.nonreq.dwchYsr;
Assert(ptxtobj->iwchLim == iwchLim);
pilsobj->pwchOrig[iwchLim - 1] = pilsobj->wchHyphen;
plnobj->pwch[iwchLim - 1] = pbrkinf->u.nonreq.wchHyphenPres;
pilsobj->pdur[iwchLim - 1] = pbrkinf->u.nonreq.durHyphen;
plnobj->pdup[iwchLim - 1] = pbrkinf->u.nonreq.dupHyphen;
if (pilsobj->pdurRight != NULL)
pilsobj->pdurRight[iwchLim - 1] = 0;
if (pilsobj->pdurLeft != NULL)
pilsobj->pdurLeft[iwchLim - 1] = 0;
if (pbrkinf->u.nonreq.wchPrev != 0)
{
pilsobj->pwchOrig[iwchLim - 2] = pbrkinf->u.nonreq.wchPrev;
plnobj->pwch[iwchLim - 2] = pbrkinf->u.nonreq.wchPrev;
if (pbrkinf->u.nonreq.gindPrev != 0)
{
plnobj->pgind[pbrkinf->u.nonreq.igindPrev] = pbrkinf->u.nonreq.gindPrev;
pilsobj->pdurGind[pbrkinf->u.nonreq.igindPrev] = pbrkinf->u.nonreq.durPrev;
plnobj->pdupGind[pbrkinf->u.nonreq.igindPrev] = pbrkinf->u.nonreq.dupPrev;
if (pilsobj->pduGright != NULL)
pilsobj->pduGright[pbrkinf->u.nonreq.igindPrev] = 0;
}
else
{
pilsobj->pdur[iwchLim - 2] = pbrkinf->u.nonreq.durPrev;
plnobj->pdup[iwchLim - 2] = pbrkinf->u.nonreq.dupPrev;
if (pilsobj->pdurRight != NULL)
pilsobj->pdurRight[iwchLim - 2] = 0;
if (pilsobj->pdurLeft != NULL)
pilsobj->pdurLeft[iwchLim - 2] = 0;
}
}
if (pbrkinf->u.nonreq.wchPrevPrev != 0)
{
pilsobj->pwchOrig[iwchLim - 3] = pbrkinf->u.nonreq.wchPrevPrev;
plnobj->pwch[iwchLim - 3] = pbrkinf->u.nonreq.wchPrevPrev;
if (pbrkinf->u.nonreq.gindPrevPrev != 0)
{
plnobj->pgind[pbrkinf->u.nonreq.igindPrevPrev] = pbrkinf->u.nonreq.gindPrevPrev;
pilsobj->pdurGind[pbrkinf->u.nonreq.igindPrevPrev] = pbrkinf->u.nonreq.durPrevPrev;
plnobj->pdupGind[pbrkinf->u.nonreq.igindPrevPrev] = pbrkinf->u.nonreq.dupPrevPrev;
if (pilsobj->pduGright != NULL)
pilsobj->pduGright[pbrkinf->u.nonreq.igindPrevPrev] = 0;
}
else
{
pilsobj->pdur[iwchLim - 3] = pbrkinf->u.nonreq.durPrevPrev;
plnobj->pdup[iwchLim - 3] = pbrkinf->u.nonreq.dupPrevPrev;
if (pilsobj->pdurRight != NULL)
pilsobj->pdurRight[iwchLim - 3] = 0;
if (pilsobj->pdurLeft != NULL)
pilsobj->pdurLeft[iwchLim - 3] = 0;
}
}
if (pbrkinf->u.nonreq.ddurDnodePrev != 0 || pbrkinf->u.nonreq.ddurDnodePrevPrev != 0)
{
lserr = LsdnResetWidthInPreviousDnodes(pilsobj->plsc, ptxtobj->plsdnUpNode,
pbrkinf->u.nonreq.ddurDnodePrev, pbrkinf->u.nonreq.ddurDnodePrevPrev);
if (lserr != lserrNone) return lserr;
}
lserr = LsdnFInChildList(pilsobj->plsc, ptxtobj->plsdnUpNode, &fInChildList);
Assert(lserr == lserrNone);
if (!fInChildList)
{
lserr = LsdnSetHyphenated(pilsobj->plsc);
Assert(lserr == lserrNone);
}
break;
case brktOptBreak:
break;
default:
NotReached();
}
}
else
{
/* REVIEW sergeyge: we should return to the discussion of brkkind later.
At the moment manager passes brkkindNext if during NextBreak object retrurned break
with dcp == 0 and break was snapped to the previous DNODE inside chunk
*/
// Assert(ptxtobj->iwchLim == ptxtobj->iwchFirst || ptxtobj->txtkind == txtkindEOL ||
// brkkind == brkkindImposedAfter);
}
return lserrNone;
}
/* F O R C E B R E A K T E X T */
/*----------------------------------------------------------------------------
%%Function: ForceBreakText
%%Contact: sergeyge
Force break method.
Breaks behind all characters in dobj, if they fit in line, or
dobj consists of one character which is the first on the line,
Breaks before the last character otherwise.
----------------------------------------------------------------------------*/
LSERR WINAPI ForceBreakText(PCLOCCHNK plocchnk, PCPOSICHNK pposichnk, PBRKOUT ptbo)
{
LSERR lserr;
PILSOBJ pilsobj;
PTXTOBJ ptxtobjLast;
long itxtobjLast;
long dcpLast;
OBJDIM objdim;
BREAKINFO* pbrkinf;
long igindLim;
pilsobj = ((PTXTOBJ)plocchnk->plschnk[0].pdobj)->plnobj->pilsobj;
memset(ptbo, 0, sizeof(*ptbo));
ptbo->fSuccessful = fTrue;
igindLim = 0;
/* Outside means before for ForceBreak */
if (pposichnk->ichnk == ichnkOutside)
{
itxtobjLast = 0;
ptxtobjLast = (PTXTOBJ)plocchnk->plschnk[itxtobjLast].pdobj;
dcpLast = 1;
}
else
{
itxtobjLast = pposichnk->ichnk;
ptxtobjLast = (PTXTOBJ)plocchnk->plschnk[itxtobjLast].pdobj;
Assert(ptxtobjLast->iwchFirst + pposichnk->dcp > 0);
Assert(pposichnk->dcp > 0);
dcpLast = pposichnk->dcp;
if (pilsobj->fTruncatedBefore)
{
BOOL fInChildList;
lserr = LsdnFInChildList(pilsobj->plsc, ptxtobjLast->plsdnUpNode, &fInChildList);
Assert(lserr == lserrNone);
if (!fInChildList)
{
dcpLast++;
Assert(ptxtobjLast->iwchLim + 1 >= ptxtobjLast->iwchFirst + dcpLast);
/* possible because if truncation returned dcp == 0, manager has reset it to previous dnode */
if (ptxtobjLast->iwchLim + 1 == ptxtobjLast->iwchFirst + dcpLast)
{
itxtobjLast++;
Assert(itxtobjLast < (long)plocchnk->clschnk);
ptxtobjLast = (PTXTOBJ)plocchnk->plschnk[itxtobjLast].pdobj;
dcpLast = 1;
}
}
}
}
ptbo->posichnk.ichnk = itxtobjLast;
lserr = LsdnGetObjDim(pilsobj->plsc, ptxtobjLast->plsdnUpNode, &ptbo->objdim);
if (lserr != lserrNone) return lserr;
if (plocchnk->lsfgi.fFirstOnLine && itxtobjLast == 0 && ptxtobjLast->iwchLim == ptxtobjLast->iwchFirst)
{
Assert(!(ptxtobjLast->txtf & txtfGlyphBased));
ptbo->posichnk.dcp = 1;
}
else
{
if (ptxtobjLast->txtf & txtfGlyphBased)
{
Assert(ptxtobjLast->iwchLim > ptxtobjLast->iwchFirst);
if (!plocchnk->lsfgi.fFirstOnLine || itxtobjLast > 0 || dcpLast > 1)
{
ptbo->posichnk.dcp = 0;
if (dcpLast > 1)
ptbo->posichnk.dcp = DcpAfterContextFromDcp(ptxtobjLast, dcpLast - 1);
}
else
ptbo->posichnk.dcp = DcpAfterContextFromDcp(ptxtobjLast, 1);
igindLim = IgindFirstFromIwch(ptxtobjLast, ptxtobjLast->iwchFirst + ptbo->posichnk.dcp);
lserr = CalcPartWidthsGlyphs(ptxtobjLast, ptbo->posichnk.dcp, &objdim, &ptbo->objdim.dur);
if (lserr != lserrNone) return lserr;
}
else
{
if (!plocchnk->lsfgi.fFirstOnLine || itxtobjLast > 0 || dcpLast > 1)
{
ptbo->posichnk.dcp = dcpLast - 1;
lserr = CalcPartWidths(ptxtobjLast, ptbo->posichnk.dcp, &objdim, &ptbo->objdim.dur);
if (lserr != lserrNone) return lserr;
}
else
{
if (ptxtobjLast->iwchLim > ptxtobjLast->iwchFirst)
{
lserr = CalcPartWidths(ptxtobjLast, 1, &objdim, &ptbo->objdim.dur);
}
else
{
ptbo->objdim.dur = 0;
}
ptbo->posichnk.dcp = 1;
}
}
}
/* Don't check that Heights of this dobj should be ignored, since in normal case, if there were spaces
there was also break */
lserr = GetPbrkinf(pilsobj, (PDOBJ)ptxtobjLast, brkkindForce, &pbrkinf);
if (lserr != lserrNone) return lserr;
pbrkinf->pdobj = (PDOBJ)ptxtobjLast;
pbrkinf->brkkind = brkkindForce;
pbrkinf->dcp = ptbo->posichnk.dcp;
pbrkinf->u.normal.igindLim = igindLim;
Assert(pbrkinf->brkt == brktNormal);
Assert(pbrkinf->u.normal.durFix == 0);
return lserrNone;
}
/* T R U N C A T E T E X T */
/*----------------------------------------------------------------------------
%%Function: TruncateText
%%Contact: sergeyge
Truncates text chunk
----------------------------------------------------------------------------*/
LSERR WINAPI TruncateText(PCLOCCHNK plocchnk, PPOSICHNK pposichnk)
{
LSERR lserr;
PILSOBJ pilsobj;
PTXTOBJ ptxtobj = NULL;
long itxtobj;
long iwchCur;
long iwchFirst;
long* pdur;
long urColumnMax;
long urTotal;
OBJDIM objdim;
BOOL fTruncateBefore;
pilsobj = ((PTXTOBJ)plocchnk->plschnk[0].pdobj)->plnobj->pilsobj;
urColumnMax = plocchnk->lsfgi.urColumnMax;
Assert(plocchnk->ppointUvLoc[0].u <= urColumnMax);
for (itxtobj = plocchnk->clschnk - 1; plocchnk->ppointUvLoc[itxtobj].u > urColumnMax; itxtobj--);
ptxtobj = (PTXTOBJ)plocchnk->plschnk[itxtobj].pdobj;
lserr = LsdnGetObjDim(pilsobj->plsc, ptxtobj->plsdnUpNode, &objdim);
if (lserr != lserrNone) return lserr;
urTotal = plocchnk->ppointUvLoc[itxtobj].u + objdim.dur;
Assert(urTotal > urColumnMax);
if (ptxtobj->txtf & txtfGlyphBased)
{
TruncateGlyphBased(ptxtobj, itxtobj, urTotal, urColumnMax, pposichnk);
return lserrNone;
}
iwchCur = ptxtobj->iwchLim;
iwchFirst = ptxtobj->iwchFirst;
pdur = pilsobj->pdur;
while (urTotal > urColumnMax)
{
iwchCur--;
urTotal -= pdur[iwchCur];
}
Assert(iwchCur >= iwchFirst);
/* REVIEW sergeyge--- extremely ugly condition,
and still slightly incompatible with Word.
To make it more compatible txtkind should be checked against
OptBreak, OptNonBreak, NonReqHyphen
If we won't check it for OptBreak,..., we will have different break point for the Visi case
Before fix for bug 227 we checked also that prev char is not space, but now it is not important.
*/
if ((pilsobj->grpf & fTxtFCheckTruncateBefore) && iwchCur > 0 &&
/* We enforce that there is no funny logic if EOL is truncation point */
ptxtobj->txtkind != txtkindEOL &&
!(iwchCur == iwchFirst && itxtobj > 0 &&
((PTXTOBJ)plocchnk->plschnk[itxtobj-1].pdobj)->txtkind != txtkindRegular &&
((PTXTOBJ)plocchnk->plschnk[itxtobj-1].pdobj)->txtkind != txtkindHardHyphen &&
((PTXTOBJ)plocchnk->plschnk[itxtobj-1].pdobj)->txtkind != txtkindYsrChar)
)
{
BOOL fInChildList;
lserr = LsdnFInChildList(pilsobj->plsc, ptxtobj->plsdnUpNode, &fInChildList);
Assert(lserr == lserrNone);
if (!fInChildList)
{
PLSRUN plsrunCur = plocchnk->plschnk[itxtobj].plsrun;
LSCP cpCur = plocchnk->plschnk[itxtobj].cpFirst + (iwchCur - iwchFirst);
long durCur = 0;
PLSRUN plsrunPrev = NULL;
WCHAR wchPrev = 0;
LSCP cpPrev = -1;
long durPrev = 0;
if (iwchCur > iwchFirst)
{
plsrunPrev = plsrunCur;
wchPrev = pilsobj->pwchOrig[iwchCur - 1];
durPrev = pilsobj->pdur[iwchCur - 1];
cpPrev = cpCur - 1;
}
else if (itxtobj > 0)
{
PTXTOBJ ptxtobjPrev = (PTXTOBJ)plocchnk->plschnk[itxtobj - 1].pdobj;
long iwchPrev = ptxtobjPrev->iwchLim - 1;
plsrunPrev= plocchnk->plschnk[itxtobj - 1].plsrun;
wchPrev = pilsobj->pwchOrig[iwchPrev];
durPrev = pilsobj->pdur[iwchPrev];
cpPrev = plocchnk->plschnk[itxtobj-1].cpFirst + (iwchPrev - ptxtobjPrev->iwchFirst);
}
/* REVIEW sergeyge: dangerous change to fix bug 399. It looks correct, but might trigger some other
incompatibility.
*/
durCur = pilsobj->pdur[iwchCur];
if (pilsobj->pdurRight != NULL)
durCur -= pilsobj->pdurRight[iwchCur];
lserr = (*pilsobj->plscbk->pfnFTruncateBefore)(pilsobj->pols,
plsrunCur, cpCur, pilsobj->pwchOrig[iwchCur], durCur,
plsrunPrev, cpPrev, wchPrev, durPrev,
urTotal + durCur - urColumnMax, &fTruncateBefore);
if (lserr != lserrNone) return lserr;
if (fTruncateBefore && iwchCur > 0 && pdur[iwchCur-1] > 0)
{
iwchCur--;
pilsobj->fTruncatedBefore = fTrue;
}
}
}
pposichnk->ichnk = itxtobj;
pposichnk->dcp = iwchCur - iwchFirst + 1;
return lserrNone;
}
/* internal functions implementation */
static void TruncateGlyphBased(PTXTOBJ ptxtobj, long itxtobj, long urTotal, long urColumnMax,
PPOSICHNK pposichnk)
{
PILSOBJ pilsobj;
long iwchFirst;
long iwchCur;
long igindCur;
long igindFirst;
long* pdurGind;
pilsobj= ptxtobj->plnobj->pilsobj;
iwchFirst = ptxtobj->iwchFirst;
igindCur = ptxtobj->igindLim;
igindFirst = ptxtobj->igindFirst;
pdurGind = pilsobj->pdurGind;
while (urTotal > urColumnMax)
{
igindCur--;
urTotal -= pdurGind[igindCur];
}
Assert(igindCur >= igindFirst);
iwchCur = IwchFirstFromIgind(ptxtobj, igindCur);
pposichnk->ichnk = itxtobj;
pposichnk->dcp = iwchCur - iwchFirst + 1;
}