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

2115 lines
66 KiB
C

#include <limits.h>
#include "lsmem.h"
#include "lstxtbrk.h"
#include "lstxtbrs.h"
#include "lstxtmap.h"
#include "lsdntext.h"
#include "brko.h"
#include "locchnk.h"
#include "lschp.h"
#include "posichnk.h"
#include "objdim.h"
#include "lshyph.h"
#include "lskysr.h"
#include "lstxtffi.h"
#include "txtils.h"
#include "txtln.h"
#include "txtobj.h"
#define FWrapTrailingSpaces(pilsobj, ptxtobj, fInChildList) \
(lserr = LsdnFInChildList((pilsobj)->plsc, (ptxtobj)->plsdnUpNode, &(fInChildList)), \
Assert(lserr == lserrNone), \
(fInChildList) || ((pilsobj)->grpf & fTxtWrapTrailingSpaces))
#define FRegularBreakableBeforeDobj(ptxtobj) \
((ptxtobj)->txtkind == txtkindRegular || (ptxtobj)->txtkind == txtkindYsrChar || \
(ptxtobj)->txtkind == txtkindSpecSpace || (ptxtobj)->txtkind == txtkindHardHyphen)
#define FRegularBreakableAfterDobj(ptxtobj) \
((ptxtobj)->txtkind == txtkindRegular || (ptxtobj)->txtkind == txtkindYsrChar || \
(ptxtobj)->txtkind == txtkindSpecSpace)
/* Internal Functions prototypes */
static BOOL FindPrevSpace(PCLOCCHNK plocchnk, long itxtobjCur, long iwchCur,
long* pitxtobjSpace, long* piwchSpace);
static BOOL FindNextSpace(PCLOCCHNK plocchnk, long itxtobjCur, long iwchCur,
long* pitxtobjSpace, long* piwchSpace);
static LSERR TryPrevBreakFindYsr(PCLOCCHNK plocchnk, long itxtobjCur, long iwchCur,
long itxtobjSpace, long iwchSpace,
BOOL* pfBroken, BOOL* pfFoundYsr, long* pitxtobjYsr, PBRKOUT ptbo);
static LSERR TryNextBreakFindYsr(PCLOCCHNK plocchnk, long itxtobjCur, long iwchCur,
long itxtobjSpace, long iwchSpace,
BOOL* pfBroken, PBRKOUT ptbo);
static LSERR TryBreakWithHyphen(PCLOCCHNK plocchnk, long itxtobjCur, long iwchCur,
BOOL fSpaceFound, long itxtobjSpace, long iwchSpace,
BOOL fFoundYsr, long itxtobjYsr, BOOL* pfBroken, PBRKOUT ptbo);
static LSERR TryBreakAtSpace(PCLOCCHNK plocchnk, PCPOSICHNK pposichnk,long itxtobjSpace, long iwchSpace,
BRKKIND brkkind, BOOL* pfBroken, long* pitxtobjCurNew, long* piwchCurNew, PBRKOUT ptbo);
static LSERR TryBreakAtSpaceWrap(PCLOCCHNK plocchnk, PCPOSICHNK pposichnk,
long itxtobjSpace, long iwchSpace, BRKKIND brkkind,
BOOL* pfBroken, long* pitxtobjCurNew, long* piwchCurNew, PBRKOUT ptbo);
static LSERR TryBreakAtSpaceNormal(PCLOCCHNK plocchnk, long itxtobjSpace, long iwchSpace, BRKKIND brkkind,
BOOL* pfBroken, long* pitxtobjCurNew, long* piwchCurNew, PBRKOUT ptbo);
static LSERR TryBreakAcrossSpaces(PCLOCCHNK plocchnk,
BOOL fBeforeFound, long itxtobjBefore, long iwchBefore,
BOOL fAfterFound, long itxtobjAfter, long iwchAfter, BRKKIND brkkind,
BOOL* pfBroken, PBRKOUT ptbo);
static LSERR TryPrevBreakRegular(PCLOCCHNK plocchnk, long itxtobj, long iwchSpace, long iwchCur,
BOOL* pfBroken, PBRKOUT ptbo);
static LSERR TryNextBreakRegular(PCLOCCHNK plocchnk, long itxtobj, long iwchSpace, long iwchCur,
BOOL* pfBroken, PBRKOUT ptbo);
static LSERR CheckBreakAtLastChar(PCLOCCHNK pclocchnk, BRKCLS brkclsLeading, long iwch, long itxtobj,
BOOL* pfBroken);
static LSERR TryBreakAtHardHyphen(PCLOCCHNK plocchnk, long itxtobj, long iwch, BRKKIND brkkind,
BOOL* pfBroken, PBRKOUT ptbo);
static LSERR TryBreakAtOptBreak(PCLOCCHNK plocchnk, long itxtobj, BRKKIND brkkind,
BOOL* pfBroken, PBRKOUT ptbo);
static LSERR TryBreakAtEOL(PCLOCCHNK plocchnk, long itxtobj, BRKKIND brkkind, BOOL* pfBroken, PBRKOUT ptbo);
static LSERR TryBreakAtNonReqHyphen(PCLOCCHNK plocchnk, long itxtobj, BRKKIND brkkind,
BOOL* pfBroken, PBRKOUT ptbo);
static LSERR TryBreakAfterChunk(PCLOCCHNK plocchnk, BRKCOND brkcond, BOOL* pfBroken, PBRKOUT ptbo);
static LSERR TryBreakBeforeChunk(PCLOCCHNK plocchnk, BRKCOND brkcond, BOOL* pfBroken, PBRKOUT ptbo);
static LSERR CanBreakBeforeText(PCLOCCHNK plocchnk, BRKCOND* pbrktxt);
static LSERR CanBreakAfterText(PCLOCCHNK plocchnk, BOOL fNonSpaceFound, long itxtobjBefore,
long iwchBefore, BRKCOND* pbrktxt);
static LSERR FillPtboPbrkinf(PCLOCCHNK plocchnk, long itxtobj, long iwch,
/*long itxtobjBeforeTrail,*/ long iwchBeforeTrail, BRKKIND brkkind,
BREAKINFO** ppbrkinf, PBRKOUT ptbo);
/* Export Functions Implementation */
/* F I N D P R E V B R E A K T E X T */
/*----------------------------------------------------------------------------
%%Function: FindPrevBreakTxt
%%Contact: sergeyge
Breaks the line in general case.
Strategy:
in loop while break was not found:
--Finds the last space.
--Checks for break opportunity behind last space. If it exists, performs break.
--If there is no such an opportunity tries to hyphenate if needed.
--Tries to breaks at space, if other possibilies did not work
----------------------------------------------------------------------------*/
LSERR WINAPI FindPrevBreakText(PCLOCCHNK plocchnk, PCPOSICHNK pposichnk, BRKCOND brkcondAfter, PBRKOUT ptbo)
{
LSERR lserr;
PILSOBJ pilsobj;
long iwchFirst;
long itxtobjCur = 0; /* Initialization to keep compiler satisfied */
PTXTOBJ ptxtobjCur;
long iwchCur = 0; /* Initialization to keep compiler satisfied */ /* Absolute index of current char in rgwch */
long itxtobjSpace;
long iwchSpace; /* Absolute index of last space in rgwch */
long itxtobjYsr;
BOOL fSpaceFound;
BOOL fBroken;
BOOL fFoundYsr;
long itxtobjCurNew;
long iwchCurNew;
BOOL fInChildList;
Assert(plocchnk->clschnk > 0);
pilsobj = ((PTXTOBJ)plocchnk->plschnk[0].pdobj)->plnobj->pilsobj;
iwchFirst = ((PTXTOBJ)plocchnk->plschnk[0].pdobj)->iwchFirst;
fBroken = fFalse;
if (pposichnk->ichnk == ichnkOutside)
{
/* Check break after chunk. If break is impossible, make sure that it is not considered any longer */
lserr = TryBreakAfterChunk(plocchnk, brkcondAfter, &fBroken, ptbo);
if (lserr != lserrNone) return lserr;
if (!fBroken)
{
itxtobjCur = plocchnk->clschnk-1;
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj;
iwchCur = ptxtobjCur->iwchFirst + plocchnk->plschnk[itxtobjCur].dcp - 1;
if (iwchCur < ptxtobjCur->iwchFirst)
itxtobjCur--;
Assert(itxtobjCur >= 0 || iwchCur < iwchFirst);
if (itxtobjCur >= 0)
FindNonSpaceBefore(plocchnk->plschnk, itxtobjCur, iwchCur, &itxtobjCur, &iwchCur);
/* if not found, we are safe because iwchCur will be < iwchFirst in this case */
}
}
else
{
itxtobjCur = pposichnk->ichnk;
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj;
Assert(ptxtobjCur->iwchFirst + pposichnk->dcp > 0);
iwchCur = ptxtobjCur->iwchFirst + pposichnk->dcp - 1;
if (ptxtobjCur->txtkind == txtkindEOL)
{
lserr = TryBreakAtEOL(plocchnk, itxtobjCur, brkkindPrev, &fBroken, ptbo);
if (lserr != lserrNone) return lserr;
}
else if (!FRegularBreakableAfterDobj(ptxtobjCur))
{
/* It won't be done after FindPrevSpace for non-regular DOBJ's, because they might overwrite
don't break before space logic
*/
iwchCur--;
if (iwchCur < ptxtobjCur->iwchFirst)
itxtobjCur--;
}
}
while (!fBroken && iwchCur >= iwchFirst)
{
/* it is important to start search for space before subtructing 1,
since space might have been a truncation point
it is not very beautiful that iwchCur is wrong for ichnkOutside, but
fortunately it still works correctly with FindPrevSpace.
*/
fSpaceFound = FindPrevSpace(plocchnk, itxtobjCur, iwchCur, &itxtobjSpace, &iwchSpace);
/* now index of the current wchar should be decreased by 1 in both starting situation(obviously)
and following iterations (because break cannot happen before space),
but not for non-Regular DOBJ's.
At starting situation it has already been done. In following iterations Hard/OptBreak's should
produce hard-coded break opportunity
*/
Assert(itxtobjCur >= 0);
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj;
if (FRegularBreakableAfterDobj(ptxtobjCur))
{
iwchCur--;
if (iwchCur < ptxtobjCur->iwchFirst && itxtobjCur > 0)
itxtobjCur--;
}
/* Check if there is break opportunity behind last space */
lserr = TryPrevBreakFindYsr(plocchnk, itxtobjCur, iwchCur, itxtobjSpace, iwchSpace,
&fBroken, &fFoundYsr, &itxtobjYsr, ptbo);
if (lserr != lserrNone) return lserr;
if (!fBroken)
{
if ((pilsobj->grpf & fTxtDoHyphenation) && iwchCur > iwchSpace)
{
lserr = LsdnFInChildList(ptxtobjCur->plnobj->pilsobj->plsc, ptxtobjCur->plsdnUpNode, &fInChildList);
if (lserr != lserrNone) return lserr;
if (!fInChildList)
{
lserr = TryBreakWithHyphen(plocchnk, itxtobjCur, iwchCur, fSpaceFound, itxtobjSpace, iwchSpace,
fFoundYsr, itxtobjYsr, &fBroken, ptbo);
if (lserr != lserrNone) return lserr;
}
}
if (!fBroken)
{
if (fSpaceFound)
{
lserr = TryBreakAtSpace(plocchnk, pposichnk, itxtobjSpace, iwchSpace, brkkindPrev,
&fBroken, &itxtobjCurNew, &iwchCurNew, ptbo);
if (lserr != lserrNone) return lserr;
iwchCur = iwchCurNew;
itxtobjCur = itxtobjCurNew;
}
else
{
iwchCur = iwchFirst - 1;
}
}
}
}
if (!fBroken)
{
memset(ptbo, 0, sizeof (*ptbo));
Assert(ptbo->fSuccessful == fFalse);
/* Addition for the new break logic---brkcond is added as input/output*/
ptbo->brkcond = brkcondCan;
if (pilsobj->grpf & fTxtApplyBreakingRules)
{
lserr = CanBreakBeforeText(plocchnk, &ptbo->brkcond);
if (lserr != lserrNone) return lserr;
}
/* end of new breaking logic */
}
return lserrNone;
}
/* F I N D N E X T B R E A K T E X T */
/*----------------------------------------------------------------------------
%%Function: FindNextBreakTxt
%%Contact: sergeyge
Breaks the line in general case.
Strategy:
in loop while break was not found:
--Finds the next space.
--Checks for break opportunity before found space. If it exists, performs break.
--Tries to breaks at space, if other possibilies did not work
----------------------------------------------------------------------------*/
LSERR WINAPI FindNextBreakText(PCLOCCHNK plocchnk, PCPOSICHNK pposichnk, BRKCOND brkcondBefore, PBRKOUT ptbo)
{
LSERR lserr;
PILSOBJ pilsobj;
long iwchLast;
long itxtobjCur = 0; /* Initialization to keep compiler satisfied */
PTXTOBJ ptxtobjCur; /* Initialization to keep compiler satisfied */
long iwchCur = 0; /* Absolute index of current char in rgwch */
long itxtobjSpace;
long iwchSpace; /* Absolute index of last space in rgwch */
BOOL fSpaceFound;
BOOL fBroken;
long itxtobjCurNew;
long iwchCurNew;
BOOL fInChildList;
BOOL fNonSpaceFound;
long itxtobjBefore;
long iwchBefore;
BREAKINFO* pbrkinf;
Assert(plocchnk->clschnk > 0);
pilsobj = ((PTXTOBJ)plocchnk->plschnk[0].pdobj)->plnobj->pilsobj;
iwchLast = ((PTXTOBJ)plocchnk->plschnk[plocchnk->clschnk - 1].pdobj)->iwchLim - 1;
fBroken = fFalse;
if (pposichnk->ichnk == ichnkOutside)
{
/* Check break after chunk. If break is impossible, make sure that it is not considered any longer */
lserr = TryBreakBeforeChunk(plocchnk, brkcondBefore, &fBroken, ptbo);
if (lserr != lserrNone) return lserr;
if (!fBroken)
{
itxtobjCur = 0;
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[0].pdobj;
iwchCur = ptxtobjCur->iwchFirst;
/* Hack: In the case of NRH or alike satisfy condition of the while loop below */
if (ptxtobjCur->iwchLim == ptxtobjCur->iwchFirst)
iwchCur--;
}
}
else
{
itxtobjCur = pposichnk->ichnk;
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj;
Assert(ptxtobjCur->iwchFirst + pposichnk->dcp > 0);
iwchCur = ptxtobjCur->iwchFirst + pposichnk->dcp - 1;
/* if truncation point was space, find first next opportunity after spaces */
if (!FWrapTrailingSpaces(pilsobj, ptxtobjCur, fInChildList))
{
FindNonSpaceAfter(plocchnk->plschnk, plocchnk->clschnk,
itxtobjCur, iwchCur, &itxtobjCur, &iwchCur);
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj;
}
/* Hack: In the case of NRH or alike satisfy condition of the while loop below */
if (ptxtobjCur->iwchLim == ptxtobjCur->iwchFirst)
iwchCur = ptxtobjCur->iwchFirst - 1;
}
while (!fBroken && iwchCur <= iwchLast)
{
fSpaceFound = FindNextSpace(plocchnk, itxtobjCur, iwchCur, &itxtobjSpace, &iwchSpace);
/* Check if there is break opportunity before next space */
lserr = TryNextBreakFindYsr(plocchnk, itxtobjCur, iwchCur, itxtobjSpace, iwchSpace,
&fBroken, ptbo);
if (lserr != lserrNone) return lserr;
if (!fBroken)
{
if (fSpaceFound)
{
lserr = TryBreakAtSpace(plocchnk, pposichnk, itxtobjSpace, iwchSpace, brkkindNext,
&fBroken, &itxtobjCurNew, &iwchCurNew, ptbo);
if (lserr != lserrNone) return lserr;
if (!fBroken)
{
iwchCur = iwchCurNew;
itxtobjCur = itxtobjCurNew;
Assert(itxtobjCur >= 0 && itxtobjCur < (long)plocchnk->clschnk);
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj;
/* Hack: In the case of NRH or alike satisfy condition of the while loop */
if (ptxtobjCur->iwchLim == ptxtobjCur->iwchFirst)
iwchCur--;
}
}
else
{
iwchCur = iwchLast + 1;
}
}
}
if (!fBroken)
{
memset(ptbo, 0, sizeof (*ptbo));
Assert(ptbo->fSuccessful == fFalse);
ptbo->brkcond = brkcondCan;
Assert(plocchnk->clschnk > 0);
itxtobjCur = plocchnk->clschnk - 1;
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj;
iwchCur = ptxtobjCur->iwchLim - 1;
fNonSpaceFound = FindNonSpaceBefore(plocchnk->plschnk, itxtobjCur, iwchCur,
&itxtobjBefore, &iwchBefore);
if (pilsobj->grpf & fTxtApplyBreakingRules)
{
lserr = CanBreakAfterText(plocchnk, fNonSpaceFound, itxtobjBefore, iwchBefore, &ptbo->brkcond);
if (lserr != lserrNone) return lserr;
if (iwchBefore != iwchCur && ptbo->brkcond == brkcondCan)
ptbo->brkcond = brkcondPlease;
}
if (ptbo->brkcond != brkcondNever)
{
/* if following Assert fails, iwchCur is calculated incorrectly a few lines above,
but it must be correct, because NonRecHyphen/... would have already caused break
*/
Assert(ptxtobjCur->iwchLim > ptxtobjCur->iwchFirst);
lserr = FillPtboPbrkinf(plocchnk, itxtobjCur, iwchCur, /*itxtobjBefore,*/ iwchBefore,
brkkindNext, &pbrkinf, ptbo);
if (lserr != lserrNone) return lserr;
ptbo->fSuccessful = fFalse;
/* next if statement with comment is copied from TryBreakNextNormal() with replacement of
iwchCur - 1 by iwchCur */
/* fModWidthSpace can be at the last char here only iff fWrapAllSpaces;
if we touch balanced space here, the logic of GetMinCompressAmount should be rethinked!*/
if (pilsobj->pdurRight != NULL && pilsobj->pdurRight[iwchCur] != 0 &&
!pilsobj->ptxtinf[iwchCur].fModWidthSpace)
{
pbrkinf->u.normal.durFix = - pilsobj->pdurRight[iwchCur];
ptbo->objdim.dur -= pilsobj->pdurRight[iwchCur];
}
}
}
return lserrNone;
}
/* Internal Functions Implementation */
/* F I N D P R E V S P A C E */
/*----------------------------------------------------------------------------
%%Function: FindPrevSpace
%%Contact: sergeyge
Returns TRUE if there is a space and FALSE otherwise.
Reports the index of the dobj containing last space
and space's index in rgwchOrig array.
----------------------------------------------------------------------------*/
static BOOL FindPrevSpace(PCLOCCHNK plocchnk, long itxtobjCur, long iwchCur,
long* pitxtobjSpace, long* piwchSpace)
{
PILSOBJ pilsobj;
BOOL fSpaceFound;
PTXTOBJ ptxtobjCur;
long* rgwSpaces;
long iwSpacesCur;
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj;
pilsobj = ptxtobjCur->plnobj->pilsobj;
rgwSpaces = pilsobj->pwSpaces;
fSpaceFound = fFalse;
/* In the case fWrapAllSpaces space is treated as a regular character */
if (!(pilsobj->grpf & fTxtWrapAllSpaces))
{
if (ptxtobjCur->txtkind == txtkindRegular)
{
iwSpacesCur = ptxtobjCur->u.reg.iwSpacesLim - 1;
while (iwSpacesCur >= ptxtobjCur->u.reg.iwSpacesFirst &&
/* current character might be space, if text chunk is not last on the line */
rgwSpaces[iwSpacesCur] > iwchCur)
{
iwSpacesCur--;
}
if (ptxtobjCur->txtf & txtfGlyphBased)
{
while (iwSpacesCur >= ptxtobjCur->u.reg.iwSpacesFirst &&
!FIwchOneToOne(pilsobj, rgwSpaces[iwSpacesCur]))
iwSpacesCur--;
}
if (iwSpacesCur >= ptxtobjCur->u.reg.iwSpacesFirst)
{
fSpaceFound = fTrue;
*pitxtobjSpace = itxtobjCur;
*piwchSpace = rgwSpaces[iwSpacesCur];
}
}
else if (ptxtobjCur->txtkind == txtkindSpecSpace)
{
fSpaceFound = fTrue;
*pitxtobjSpace = itxtobjCur;
*piwchSpace = iwchCur;
}
itxtobjCur--;
while (!fSpaceFound && itxtobjCur >= 0)
{
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj;
if (ptxtobjCur->txtkind == txtkindRegular)
{
iwSpacesCur = ptxtobjCur->u.reg.iwSpacesLim - 1;
if (ptxtobjCur->txtf & txtfGlyphBased)
{
while (iwSpacesCur >= ptxtobjCur->u.reg.iwSpacesFirst &&
!FIwchOneToOne(pilsobj, rgwSpaces[iwSpacesCur]))
iwSpacesCur--;
}
if (iwSpacesCur >= ptxtobjCur->u.reg.iwSpacesFirst)
{
fSpaceFound = fTrue;
*pitxtobjSpace = itxtobjCur;
*piwchSpace = rgwSpaces[iwSpacesCur];
}
}
else if (ptxtobjCur->txtkind == txtkindSpecSpace)
{
fSpaceFound = fTrue;
*pitxtobjSpace = itxtobjCur;
*piwchSpace = ptxtobjCur->iwchLim - 1;
}
itxtobjCur--;
}
}
if (!fSpaceFound)
{
*pitxtobjSpace = -1;
*piwchSpace = ((PTXTOBJ)plocchnk->plschnk[0].pdobj)->iwchFirst - 1;
}
return fSpaceFound;
}
/* F I N D N E X T S P A C E */
/*----------------------------------------------------------------------------
%%Function: FindNextSpace
%%Contact: sergeyge
Returns TRUE if there is a space and FALSE otherwise.
Reports the index of the dobj containing last space
and space's index in rgwchOrig array.
----------------------------------------------------------------------------*/
static BOOL FindNextSpace(PCLOCCHNK plocchnk, long itxtobjCur, long iwchCur,
long* pitxtobjSpace, long* piwchSpace)
{
PILSOBJ pilsobj;
BOOL fSpaceFound;
PTXTOBJ ptxtobjCur;
long* rgwSpaces;
long iwSpacesCur;
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj;
pilsobj = ptxtobjCur->plnobj->pilsobj;
rgwSpaces = pilsobj->pwSpaces;
fSpaceFound = fFalse;
/* In the case fWrapAllSpaces space is treated as a regular character */
if (!(pilsobj->grpf & fTxtWrapAllSpaces))
{
if (ptxtobjCur->txtkind == txtkindRegular)
{
iwSpacesCur = ptxtobjCur->u.reg.iwSpacesFirst;
while (iwSpacesCur < ptxtobjCur->u.reg.iwSpacesLim &&
rgwSpaces[iwSpacesCur] < iwchCur)
{
iwSpacesCur++;
}
if (ptxtobjCur->txtf & txtfGlyphBased)
{
while (iwSpacesCur < ptxtobjCur->u.reg.iwSpacesLim &&
!FIwchOneToOne(pilsobj, rgwSpaces[iwSpacesCur]))
iwSpacesCur++;
}
if (iwSpacesCur < ptxtobjCur->u.reg.iwSpacesLim)
{
fSpaceFound = fTrue;
*pitxtobjSpace = itxtobjCur;
*piwchSpace = rgwSpaces[iwSpacesCur];
}
}
else if (ptxtobjCur->txtkind == txtkindSpecSpace)
{
fSpaceFound = fTrue;
*pitxtobjSpace = itxtobjCur;
*piwchSpace = iwchCur;
}
itxtobjCur++;
while (!fSpaceFound && itxtobjCur < (long)plocchnk->clschnk)
{
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj;
if (ptxtobjCur->txtkind == txtkindRegular)
{
iwSpacesCur = ptxtobjCur->u.reg.iwSpacesFirst;
if (ptxtobjCur->txtf & txtfGlyphBased)
{
while (iwSpacesCur < ptxtobjCur->u.reg.iwSpacesLim &&
!FIwchOneToOne(pilsobj, rgwSpaces[iwSpacesCur]))
iwSpacesCur++;
}
if (iwSpacesCur < ptxtobjCur->u.reg.iwSpacesLim)
{
fSpaceFound = fTrue;
*pitxtobjSpace = itxtobjCur;
*piwchSpace = rgwSpaces[iwSpacesCur];
}
}
else if (ptxtobjCur->txtkind == txtkindSpecSpace)
{
fSpaceFound = fTrue;
*pitxtobjSpace = itxtobjCur;
*piwchSpace = ptxtobjCur->iwchFirst;
}
itxtobjCur++;
}
}
if (!fSpaceFound)
{
*pitxtobjSpace = plocchnk->clschnk;
*piwchSpace = ((PTXTOBJ)plocchnk->plschnk[plocchnk->clschnk-1].pdobj)->iwchLim;
}
return fSpaceFound;
}
/* T R Y P R E V B R E A K F I N D Y S R */
/*----------------------------------------------------------------------------
%%Function: TryPrevBreakFindYsr
%%Contact: sergeyge
Realizes break if there is one before next space.
Since each special character has its own dobj we need to check only type of dobj
----------------------------------------------------------------------------*/
static LSERR TryPrevBreakFindYsr(PCLOCCHNK plocchnk, long itxtobjCur, long iwchCur,
long itxtobjSpace, long iwchSpace,
BOOL* pfBroken, BOOL* pfFoundYsr, long* pitxtobjYsr, PBRKOUT ptbo)
{
LSERR lserr;
PILSOBJ pilsobj;
PTXTOBJ ptxtobjCur;
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj;
pilsobj = ptxtobjCur->plnobj->pilsobj;
*pfBroken = fFalse;
*pfFoundYsr = fFalse;
/* following condition is almost always TRUE,
so in bread-and-butter situation we do almost nothing */
if ((long)itxtobjCur == itxtobjSpace && !(pilsobj->grpf & fTxtApplyBreakingRules))
{
return lserrNone;
}
/* In loop condition check for itxtobjCur > itxtobjSpace is necessary for the case of empty
DOBJ's: NonReqHyphen, OptBreak
*/
while((itxtobjCur > itxtobjSpace || iwchCur > iwchSpace) && !*pfBroken)
{
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj;
Assert(ptxtobjCur->txtkind != txtkindEOL && ptxtobjCur->txtkind != txtkindTab);
Assert(ptxtobjCur->txtkind != txtkindSpecSpace || (pilsobj->grpf & fTxtWrapAllSpaces));
switch (ptxtobjCur->txtkind)
{
case txtkindRegular:
if (pilsobj->grpf & fTxtApplyBreakingRules)
{
lserr = TryPrevBreakRegular(plocchnk, itxtobjCur, iwchSpace, iwchCur, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
}
break;
case txtkindHardHyphen:
lserr = TryBreakAtHardHyphen(plocchnk, itxtobjCur, iwchCur, brkkindPrev, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
break;
case txtkindOptBreak:
lserr = TryBreakAtOptBreak(plocchnk, itxtobjCur, brkkindPrev, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
break;
case txtkindNonReqHyphen:
lserr = TryBreakAtNonReqHyphen(plocchnk, itxtobjCur, brkkindPrev, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
break;
case txtkindYsrChar:
if (!*pfFoundYsr)
{
*pfFoundYsr = fTrue;
*pitxtobjYsr = itxtobjCur;
}
break;
case txtkindSpecSpace:
/* It is possible for fTxtWrapAllSpaces case */
Assert(pilsobj->grpf & fTxtApplyBreakingRules);
Assert(pilsobj->grpf & fTxtWrapAllSpaces);
lserr = TryPrevBreakRegular(plocchnk, itxtobjCur, iwchSpace, iwchCur, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
break;
}
iwchCur = ptxtobjCur->iwchFirst - 1;
itxtobjCur--;
}
return lserrNone;
}
/* T R Y N E X T B R E A K F I N D Y S R */
/*----------------------------------------------------------------------------
%%Function: TryPrevBreakFindYsr
%%Contact: sergeyge
Realizes break if there is one after last space.
Also fills info about last YSR character after last space.
Since each special character has its own dobj we need to check only type of dobj
----------------------------------------------------------------------------*/
static LSERR TryNextBreakFindYsr(PCLOCCHNK plocchnk, long itxtobjCur, long iwchCur,
long itxtobjSpace, long iwchSpace,
BOOL* pfBroken, PBRKOUT ptbo)
{
LSERR lserr;
PILSOBJ pilsobj;
PTXTOBJ ptxtobjCur;
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj;
pilsobj = ptxtobjCur->plnobj->pilsobj;
*pfBroken = fFalse;
/* In loop condition check for itxtobjCur < itxtobjSpace is necessary for the case of empty
DOBJ's: NonReqHyphen, OptBreak
*/
while((itxtobjCur < itxtobjSpace || iwchCur < iwchSpace) && !*pfBroken)
{
ptxtobjCur = (PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj;
Assert(ptxtobjCur->txtkind != txtkindSpecSpace || (pilsobj->grpf & fTxtWrapAllSpaces));
switch (ptxtobjCur->txtkind)
{
case txtkindRegular:
if (pilsobj->grpf & fTxtApplyBreakingRules)
{
lserr = TryNextBreakRegular(plocchnk, itxtobjCur, iwchSpace, iwchCur, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
}
break;
case txtkindHardHyphen:
lserr = TryBreakAtHardHyphen(plocchnk, itxtobjCur, iwchCur, brkkindNext, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
break;
case txtkindOptBreak:
lserr = TryBreakAtOptBreak(plocchnk, itxtobjCur, brkkindNext, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
break;
case txtkindEOL:
lserr = TryBreakAtEOL(plocchnk, itxtobjCur, brkkindNext, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
break;
case txtkindNonReqHyphen:
lserr = TryBreakAtNonReqHyphen(plocchnk, itxtobjCur, brkkindNext, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
break;
case txtkindSpecSpace:
/* It is possible for fTxtWrapAllSpaces case */
Assert(pilsobj->grpf & fTxtApplyBreakingRules);
Assert(pilsobj->grpf & fTxtWrapAllSpaces);
lserr = TryNextBreakRegular(plocchnk, itxtobjCur, iwchSpace, iwchCur, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
break;
}
iwchCur = ptxtobjCur->iwchLim;
itxtobjCur++;
}
return lserrNone;
}
/* T R Y B R E A K W I T H H Y P H E N */
/*----------------------------------------------------------------------------
%%Function: TryBreakWithHyphen
%%Contact: sergeyge
Tries to realize break as hyphenation
Strategy:
--Checks if hyphenation should be performed (CheckHotZone)
--If it should, calls hyphenator.
` --If hyphenator is successful tryes to insert hyphen
else sets break opportunity at the last space
----------------------------------------------------------------------------*/
static LSERR TryBreakWithHyphen(PCLOCCHNK plocchnk, long itxtobjCur, long iwchCur,
BOOL fSpaceFound, long itxtobjSpace, long iwchSpace,
BOOL fFoundYsr, long itxtobjYsr, BOOL* pfBroken, PBRKOUT ptbo)
{
LSERR lserr;
PILSOBJ pilsobj;
long itxtobjWordStart;
long iwchWordStart;
PTXTOBJ ptxtobjWordStart;
PTXTOBJ ptxtobjYsr;
long dwchYsr;
LSCP cpMac;
LSCP cpWordStart;
PLSRUN plsrunYsr;
YSRINF ysrinf;
HYPHOUT hyphout;
struct lshyph lshyphLast;
struct lshyph lshyphNew;
BOOL fHyphenInserted;
BOOL fInHyphenZone = fTrue;
DWORD kysr;
WCHAR wchYsr;
long urPenLast;
OBJDIM objdim;
BREAKINFO* pbrkinf;
long itxtobjPrevPrev;
long durBorder;
BOOL fSuccessful;
long i;
if (!fSpaceFound)
{
itxtobjWordStart = 0;
iwchWordStart = ((PTXTOBJ)plocchnk->plschnk[0].pdobj)->iwchFirst;
}
else
{
itxtobjWordStart = itxtobjSpace;
iwchWordStart = iwchSpace + 1;
lserr = CheckHotZone(plocchnk, itxtobjSpace, iwchSpace, &fInHyphenZone);
if (lserr != lserrNone) return lserr;
}
ptxtobjWordStart = (PTXTOBJ)plocchnk->plschnk[itxtobjWordStart].pdobj;
pilsobj = ptxtobjWordStart->plnobj->pilsobj;
fHyphenInserted = fFalse;
if (fInHyphenZone)
{
/* Fill lshyphLast if there was YSR character */
if (fFoundYsr)
{
plsrunYsr = plocchnk->plschnk[itxtobjYsr].plsrun;
lserr = (*pilsobj->plscbk->pfnGetHyphenInfo)(pilsobj->pols, plsrunYsr, &kysr, &wchYsr);
if (lserr != lserrNone) return lserr;
lshyphLast.kysr = kysr;
lshyphLast.wchYsr = wchYsr;
lshyphLast.cpYsr = plocchnk->plschnk[itxtobjYsr].cpFirst;
}
else
{
lshyphLast.kysr = kysrNil;
}
Assert (iwchCur >= ((PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj)->iwchFirst ||
((PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj)->iwchFirst == ((PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj)->iwchLim);
cpMac = plocchnk->plschnk[itxtobjCur].cpFirst +
(iwchCur - ((PTXTOBJ)plocchnk->plschnk[itxtobjCur].pdobj)->iwchFirst) + 1;
cpWordStart = plocchnk->plschnk[itxtobjWordStart].cpFirst +
(iwchWordStart - ptxtobjWordStart->iwchFirst);
lshyphNew.kysr = kysrNormal;
while (!fHyphenInserted && lshyphNew.kysr != kysrNil)
{
lserr = (pilsobj->plscbk->pfnHyphenate)(pilsobj->pols, &lshyphLast, cpWordStart, cpMac, &lshyphNew);
if (lserr != lserrNone) return lserr;
if (lshyphNew.kysr != kysrNil)
{
/* if TryBreak.. will be unsuccessful we will try hyphenation again with a new cpMac */
Assert(lshyphNew.cpYsr >= cpWordStart && lshyphNew.cpYsr < cpMac);
cpMac = lshyphNew.cpYsr;
lshyphLast = lshyphNew;
for (i=0; i <= itxtobjCur && plocchnk->plschnk[i].cpFirst <= cpMac; i++);
itxtobjYsr = i - 1;
Assert(lshyphNew.cpYsr < plocchnk->plschnk[itxtobjYsr].cpFirst +
(long)plocchnk->plschnk[itxtobjYsr].dcp);
dwchYsr = cpMac - plocchnk->plschnk[itxtobjYsr].cpFirst;
ysrinf.wchYsr = lshyphNew.wchYsr;
ysrinf.kysr = (WORD)lshyphNew.kysr;
itxtobjPrevPrev = ichnkOutside;
for (i=itxtobjYsr; i >= 0 && plocchnk->plschnk[i].cpFirst > cpMac - 1; i--);
if (i >= 0)
itxtobjPrevPrev = i;
lserr = ProcessYsr(plocchnk, itxtobjYsr, dwchYsr, itxtobjYsr, itxtobjPrevPrev, ysrinf,
&fSuccessful, &hyphout);
if (lserr != lserrNone) return lserr;
Assert(hyphout.ddurDnodePrevPrev == 0);
if (fSuccessful)
{
/* try break may be unsuccessful because it won't fit in the column */
ptxtobjYsr = (PTXTOBJ)plocchnk->plschnk[itxtobjYsr].pdobj;
if (ptxtobjYsr->txtf & txtfGlyphBased)
lserr = CalcPartWidthsGlyphs(ptxtobjYsr, dwchYsr + 1, &objdim, &urPenLast);
else
lserr = CalcPartWidths(ptxtobjYsr, dwchYsr + 1, &objdim, &urPenLast);
if (lserr != lserrNone) return lserr;
durBorder = 0;
if (plocchnk->plschnk[itxtobjYsr].plschp->fBorder)
{
lserr = LsdnGetBorderAfter(pilsobj->plsc, ptxtobjYsr->plsdnUpNode, &durBorder);
Assert(lserr == lserrNone);
}
if (plocchnk->ppointUvLoc[itxtobjYsr].u + urPenLast + hyphout.durChangeTotal + durBorder
<= plocchnk->lsfgi.urColumnMax)
{
fHyphenInserted = fTrue;
ptbo->fSuccessful = fTrue;
ptbo->posichnk.ichnk = itxtobjYsr;
ptbo->posichnk.dcp = dwchYsr + 1;
ptbo->objdim = objdim;
ptbo->objdim.dur = urPenLast + hyphout.durChangeTotal;
lserr = GetPbrkinf(pilsobj, plocchnk->plschnk[itxtobjYsr].pdobj, brkkindPrev, &pbrkinf);
if (lserr != lserrNone) return lserr;
pbrkinf->pdobj = plocchnk->plschnk[itxtobjYsr].pdobj;
pbrkinf->brkkind = brkkindPrev;
pbrkinf->dcp = dwchYsr + 1;
pbrkinf->brkt = brktHyphen;
pbrkinf->u.hyphen.iwchLim = hyphout.iwchLim;
pbrkinf->u.hyphen.dwchYsr = hyphout.dwchYsr;
pbrkinf->u.hyphen.durHyphen = hyphout.durHyphen;
pbrkinf->u.hyphen.dupHyphen = hyphout.dupHyphen;
pbrkinf->u.hyphen.durPrev = hyphout.durPrev;
pbrkinf->u.hyphen.dupPrev = hyphout.dupPrev;
pbrkinf->u.hyphen.durPrevPrev = hyphout.durPrevPrev;
pbrkinf->u.hyphen.dupPrevPrev = hyphout.dupPrevPrev;
pbrkinf->u.hyphen.ddurDnodePrev = hyphout.ddurDnodePrev;
pbrkinf->u.hyphen.wchPrev = hyphout.wchPrev;
pbrkinf->u.hyphen.wchPrevPrev = hyphout.wchPrevPrev;
pbrkinf->u.hyphen.gindHyphen = hyphout.gindHyphen;
pbrkinf->u.hyphen.gindPrev = hyphout.gindPrev;
pbrkinf->u.hyphen.gindPrevPrev = hyphout.gindPrevPrev;
pbrkinf->u.hyphen.igindHyphen = hyphout.igindHyphen;
pbrkinf->u.hyphen.igindPrev = hyphout.igindPrev;
pbrkinf->u.hyphen.igindPrevPrev = hyphout.igindPrevPrev;
}
}
}
}
}
*pfBroken = fHyphenInserted;
return lserrNone;
}
/* T R Y B R E A K A T S P A C E */
/*----------------------------------------------------------------------------
%%Function: TryBreakAtSpace
%%Contact: sergeyge
Dispatchs desicion to either TryBreakAtSpaceNormal or
TryBreakAtSpaceWrap
----------------------------------------------------------------------------*/
static LSERR TryBreakAtSpace(PCLOCCHNK plocchnk, PCPOSICHNK pposichnk, long itxtobjSpace, long iwchSpace,
BRKKIND brkkind, BOOL* pfBroken, long* pitxtobjCurNew, long* piwchCurNew, PBRKOUT ptbo)
{
LSERR lserr;
PILSOBJ pilsobj;
PTXTOBJ ptxtobj;
BOOL fInChildList;
ptxtobj = (PTXTOBJ)plocchnk->plschnk[itxtobjSpace].pdobj;
pilsobj = ptxtobj->plnobj->pilsobj;
Assert(!(pilsobj->grpf & fTxtWrapAllSpaces));
if (FWrapTrailingSpaces(pilsobj, ptxtobj, fInChildList))
{
lserr = TryBreakAtSpaceWrap(plocchnk, pposichnk, itxtobjSpace, iwchSpace, brkkind,
pfBroken, pitxtobjCurNew, piwchCurNew, ptbo);
}
else
{
lserr = TryBreakAtSpaceNormal(plocchnk, itxtobjSpace, iwchSpace, brkkind,
pfBroken, pitxtobjCurNew, piwchCurNew, ptbo);
}
return lserr;
}
/* T R Y B R E A K A T S P A C E W R A P */
/*----------------------------------------------------------------------------
%%Function: TryBreakAtSpaceWrap
%%Contact: sergeyge
Realizes break at space for the fWrapTrailingSpaces case.
----------------------------------------------------------------------------*/
static LSERR TryBreakAtSpaceWrap(PCLOCCHNK plocchnk, PCPOSICHNK pposichnk,
long itxtobjSpace, long iwchSpace, BRKKIND brkkind,
BOOL* pfBroken, long* pitxtobjCurNew, long* piwchCurNew, PBRKOUT ptbo)
{
LSERR lserr;
PILSOBJ pilsobj;
PTXTOBJ ptxtobjSpace;
long itxtobjBefore;
long itxtobjAfter;
long iwchBefore;
long iwchAfter;
BOOL fBeforeFound;
BOOL fAfterFound = fTrue;
*pfBroken = fFalse;
*pitxtobjCurNew = -1;
*piwchCurNew = -1;
ptxtobjSpace = (PTXTOBJ)plocchnk->plschnk[itxtobjSpace].pdobj;
pilsobj = ptxtobjSpace->plnobj->pilsobj;
fBeforeFound = FindNonSpaceBefore(plocchnk->plschnk, itxtobjSpace, iwchSpace,
&itxtobjBefore, &iwchBefore);
Assert(fBeforeFound || iwchBefore == ((PTXTOBJ)plocchnk->plschnk[0].pdobj)->iwchFirst - 1);
/* iwchBefore is needed for check that previous char is not space */
if (brkkind == brkkindPrev && /* previous break only, next break must be after */
iwchSpace - iwchBefore > 1 && /* previous character is space */
pposichnk->ichnk != ichnkOutside && /* and space exceeds right margin */
iwchSpace == (long)(((PTXTOBJ)plocchnk->plschnk[pposichnk->ichnk].pdobj)->iwchFirst +
pposichnk->dcp - 1))
{
fAfterFound = fTrue;
itxtobjAfter = itxtobjSpace;
iwchAfter = iwchSpace;
}
else
{
fAfterFound = FindNextChar(plocchnk->plschnk, plocchnk->clschnk, itxtobjSpace, iwchSpace,
&itxtobjAfter, &iwchAfter);
}
lserr = TryBreakAcrossSpaces(plocchnk,
fBeforeFound, itxtobjBefore, iwchBefore,
fAfterFound, itxtobjAfter, iwchAfter, brkkind, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
if (!*pfBroken)
{
if (brkkind == brkkindPrev)
{
FindPrevChar(plocchnk->plschnk, itxtobjSpace, iwchSpace,
pitxtobjCurNew, piwchCurNew);
}
else
{
Assert(brkkind == brkkindNext);
*pitxtobjCurNew = itxtobjAfter;
*piwchCurNew = iwchAfter;
}
}
return lserrNone;
}
/* T R Y B R E A K A T S P A C E N O R M A L */
/*----------------------------------------------------------------------------
%%Function: TryBreakAtSpaceNormal
%%Contact: sergeyge
Realizes break at space for the normal (!fWrapTrailingSpaces) case.
----------------------------------------------------------------------------*/
static LSERR TryBreakAtSpaceNormal(PCLOCCHNK plocchnk, long itxtobjSpace, long iwchSpace, BRKKIND brkkind,
BOOL* pfBroken, long* pitxtobjCurNew, long* piwchCurNew, PBRKOUT ptbo)
{
LSERR lserr;
PILSOBJ pilsobj;
PTXTOBJ ptxtobjSpace;
long itxtobjBefore;
long itxtobjAfter;
long iwchBefore;
long iwchAfter;
BOOL fBeforeFound;
BOOL fAfterFound;
*pfBroken = fFalse;
*pitxtobjCurNew = -1;
*piwchCurNew = -1;
ptxtobjSpace = (PTXTOBJ)plocchnk->plschnk[itxtobjSpace].pdobj;
pilsobj = ptxtobjSpace->plnobj->pilsobj;
fBeforeFound = FindNonSpaceBefore(plocchnk->plschnk,
itxtobjSpace, iwchSpace, &itxtobjBefore, &iwchBefore);
Assert(fBeforeFound || iwchBefore == ((PTXTOBJ)plocchnk->plschnk[0].pdobj)->iwchFirst - 1);
fAfterFound = FindNonSpaceAfter(plocchnk->plschnk, plocchnk->clschnk,
itxtobjSpace, iwchSpace, &itxtobjAfter, &iwchAfter);
lserr = TryBreakAcrossSpaces(plocchnk, fBeforeFound, itxtobjBefore, iwchBefore,
fAfterFound, itxtobjAfter, iwchAfter, brkkind, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
if (!*pfBroken)
{
if (brkkind == brkkindPrev)
{
*pitxtobjCurNew = itxtobjBefore;
*piwchCurNew = iwchBefore;
}
else
{
Assert(brkkind == brkkindNext);
*pitxtobjCurNew = itxtobjAfter;
*piwchCurNew = iwchAfter;
}
}
return lserrNone;
}
/* T R Y B R E A K A C R O S S S P A C E S */
/*----------------------------------------------------------------------------
%%Function: TryBreakAcrossSpaces
%%Contact: sergeyge
Checks break across spaces, sets it if it is possible
----------------------------------------------------------------------------*/
static LSERR TryBreakAcrossSpaces(PCLOCCHNK plocchnk,
BOOL fBeforeFound, long itxtobjBefore, long iwchBefore,
BOOL fAfterFound, long itxtobjAfter, long iwchAfter, BRKKIND brkkind,
BOOL* pfBroken, PBRKOUT ptbo)
{
LSERR lserr;
PILSOBJ pilsobj;
PTXTOBJ ptxtobjBefore = NULL;
PTXTOBJ ptxtobjAfter = NULL;
BRKCLS brkclsLeading = 0; /* Initialization to keep compiler satisfied */
BRKCLS brkclsFollowing = 0; /* Initialization to keep compiler satisfied */
BRKCLS brkclsJunk;
BRKCOND brktxt;
BREAKINFO* pbrkinf;
BOOL fCanBreak;
pilsobj = ((PTXTOBJ)plocchnk->plschnk[0].pdobj)->plnobj->pilsobj;
fCanBreak = fTrue;
*pfBroken = fFalse;
if (fAfterFound)
{
ptxtobjAfter = (PTXTOBJ)plocchnk->plschnk[itxtobjAfter].pdobj;
if (ptxtobjAfter->txtkind == txtkindEOL)
{
lserr = TryBreakAtEOL(plocchnk, itxtobjAfter, brkkind, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
Assert (*pfBroken == fTrue);
}
}
if (!*pfBroken && (pilsobj->grpf & fTxtApplyBreakingRules) )
{
if (fAfterFound)
{
Assert(ptxtobjAfter->txtkind != txtkindTab && ptxtobjAfter->txtkind != txtkindEOL);
/* Space After is possible for fWarapTrailingSpaces case*/
if (ptxtobjAfter->txtkind == txtkindOptBreak ||
ptxtobjAfter->txtkind == txtkindNonReqHyphen)
{
fAfterFound = fFalse; /* After char of no importance for making break decision */
}
else if (!FRegularBreakableBeforeDobj(ptxtobjAfter))
{
fCanBreak = fFalse; /* Cannot break before non-standard dobj's,
compare with CheckBreakAtLastChar */
}
else if ((ptxtobjAfter->txtf & txtfGlyphBased) && iwchAfter > ptxtobjAfter->iwchFirst)
/* if iwchAfter is first character of Dnode, it is definitely not shaped together
with the previous char */
{
if (!FIwchLastInContext(pilsobj, iwchAfter - 1))
{
fCanBreak = fFalse;
/* Additional hack to handle case when Accented spaces are separated by spaces */
if (iwchAfter - 1 > iwchBefore + 1 && /* There are more spaces in between */
FIwchFirstInContext(pilsobj, iwchAfter - 1) )
{
fCanBreak = fTrue;
iwchAfter--;
}
}
}
}
else
{
if (brkkind == brkkindPrev)
/* patch for the cases when we break across spaces
at the end of text chunk during PrevBreak logic.
Problems are possible because trailing spaces could exceed RM,
and no information about following chunk was passed in.
*/
{
BOOL fStoppedAfter;
Assert(fCanBreak);
Assert(plocchnk->clschnk > 0);
/* Check if there is Splat, or Hidden text producing fStopped after this chunk
In this case we must break after
(we will set fAfterFound and fBeforeFound to False to ensure it)
*/
lserr = LsdnFStoppedAfterChunk(pilsobj->plsc,
((PTXTOBJ)plocchnk->plschnk[plocchnk->clschnk-1].pdobj)->plsdnUpNode,
&fStoppedAfter);
if (lserr != lserrNone) return lserr;
if (fStoppedAfter)
{
Assert(fCanBreak);
Assert(!fAfterFound);
fBeforeFound = fFalse;
}
else
/* If there is no Splat, or Hidden text producing fStopped after this chunk
we should not break if next chunk returnd brkcondNever on the left side.
*/
{
lserr = LsdnFCanBreakBeforeNextChunk(pilsobj->plsc,
((PTXTOBJ)plocchnk->plschnk[plocchnk->clschnk-1].pdobj)->plsdnUpNode,
&fCanBreak);
if (lserr != lserrNone) return lserr;
}
}
else
{
Assert (brkkind == brkkindNext);
fCanBreak = fFalse; /* Do not break; let code at the ens of FindNextBreak set correct brkcond */
}
}
if (fBeforeFound)
{
ptxtobjBefore = (PTXTOBJ)plocchnk->plschnk[itxtobjBefore].pdobj;
Assert(ptxtobjBefore->txtkind != txtkindTab &&
ptxtobjBefore->txtkind != txtkindSpecSpace &&
ptxtobjBefore->txtkind != txtkindEOL);
if (ptxtobjBefore->txtkind == txtkindHardHyphen ||
ptxtobjBefore->txtkind == txtkindOptBreak ||
ptxtobjBefore->txtkind == txtkindNonReqHyphen)
{
fBeforeFound = fFalse; /* Before char of no importance for making break decision */
}
else if (ptxtobjBefore->txtkind == txtkindNonBreakSpace ||
ptxtobjBefore->txtkind == txtkindNonBreakHyphen ||
ptxtobjBefore->txtkind == txtkindOptNonBreak)
{
fCanBreak = fFalse; /* Cannot break after Non-Breaks */
}
}
if (fCanBreak)
{
if (fBeforeFound)
{
lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols, plocchnk->plschnk[itxtobjBefore].plsrun,
plocchnk->plschnk[itxtobjBefore].cpFirst + (iwchBefore - ptxtobjBefore->iwchFirst),
pilsobj->pwchOrig[iwchBefore], &brkclsLeading, &brkclsJunk);
if (lserr != lserrNone) return lserr;
Assert(brkclsLeading < pilsobj->cBreakingClasses && brkclsJunk < pilsobj->cBreakingClasses);
if (brkclsLeading >= pilsobj->cBreakingClasses || brkclsJunk >= pilsobj->cBreakingClasses)
return lserrInvalidBreakingClass;
}
if (fAfterFound)
{
lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols, plocchnk->plschnk[itxtobjAfter].plsrun,
plocchnk->plschnk[itxtobjAfter].cpFirst + (iwchAfter - ptxtobjAfter->iwchFirst),
pilsobj->pwchOrig[iwchAfter], &brkclsJunk, &brkclsFollowing);
if (lserr != lserrNone) return lserr;
Assert(brkclsJunk < pilsobj->cBreakingClasses && brkclsFollowing < pilsobj->cBreakingClasses);
if (brkclsJunk >= pilsobj->cBreakingClasses || brkclsFollowing >= pilsobj->cBreakingClasses)
return lserrInvalidBreakingClass;
}
if (fBeforeFound && fAfterFound)
{
fCanBreak = FCanBreakAcrossSpaces(pilsobj, brkclsLeading, brkclsFollowing);
}
else if (fBeforeFound && !fAfterFound)
{
lserr = (*pilsobj->plscbk->pfnCanBreakAfterChar)(pilsobj->pols, brkclsLeading, &brktxt);
if (lserr != lserrNone) return lserr;
fCanBreak = (brktxt != brkcondNever);
}
else if (!fBeforeFound && fAfterFound)
{
lserr = (*pilsobj->plscbk->pfnCanBreakBeforeChar)(pilsobj->pols, brkclsFollowing, &brktxt);
if (lserr != lserrNone) return lserr;
fCanBreak = (brktxt != brkcondNever);
}
}
}
if (!*pfBroken && fCanBreak)
{
FillPtboPbrkinf(plocchnk, itxtobjAfter, iwchAfter - 1, /*itxtobjBefore,*/ iwchBefore,
brkkind, &pbrkinf, ptbo);
*pfBroken = fTrue;
}
return lserrNone;
}
/* T R Y P R E V B R E A K R E G U L A R */
/*----------------------------------------------------------------------------
%%Function: TryPrevBreakRegular
%%Contact: sergeyge
Checks (and sets) for prev break inside regular dobj
----------------------------------------------------------------------------*/
static LSERR TryPrevBreakRegular(PCLOCCHNK plocchnk, long itxtobj, long iwchSpace, long iwchCur,
BOOL* pfBroken, PBRKOUT ptbo)
{
LSERR lserr;
PTXTOBJ ptxtobj;
PILSOBJ pilsobj;
PLSRUN plsrun;
long iwchFirst;
BRKCLS brkclsFollowingCache;
BRKCLS brkclsLeading;
BRKCLS brkclsFollowing;
BREAKINFO* pbrkinf;
*pfBroken = fFalse;
if (iwchCur <= iwchSpace) return lserrNone;
ptxtobj = (PTXTOBJ)plocchnk->plschnk[itxtobj].pdobj;
pilsobj = ptxtobj->plnobj->pilsobj;
Assert(ptxtobj->txtkind == txtkindRegular ||
(ptxtobj->txtkind == txtkindSpecSpace && (pilsobj->grpf & fTxtWrapAllSpaces)));
Assert( pilsobj->grpf & fTxtApplyBreakingRules );
plsrun = plocchnk->plschnk[itxtobj].plsrun;
iwchFirst = ptxtobj->iwchFirst;
if (iwchSpace + 1 > iwchFirst)
iwchFirst = iwchSpace + 1;
lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols, plsrun,
plocchnk->plschnk[itxtobj].cpFirst + (iwchCur - ptxtobj->iwchFirst),
pilsobj->pwchOrig[iwchCur], &brkclsLeading, &brkclsFollowingCache);
if (lserr != lserrNone) return lserr;
Assert(brkclsLeading < pilsobj->cBreakingClasses && brkclsFollowingCache < pilsobj->cBreakingClasses);
if (brkclsLeading >= pilsobj->cBreakingClasses || brkclsFollowingCache >= pilsobj->cBreakingClasses)
return lserrInvalidBreakingClass;
lserr = CheckBreakAtLastChar(plocchnk, brkclsLeading, iwchCur, itxtobj, pfBroken);
if (lserr != lserrNone) return lserr;
iwchCur--;
while (!*pfBroken && iwchCur >= iwchFirst)
{
brkclsFollowing = brkclsFollowingCache;
lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols, plsrun,
plocchnk->plschnk[itxtobj].cpFirst + (iwchCur - ptxtobj->iwchFirst),
pilsobj->pwchOrig[iwchCur], &brkclsLeading, &brkclsFollowingCache);
if (lserr != lserrNone) return lserr;
Assert(brkclsLeading < pilsobj->cBreakingClasses && brkclsFollowingCache < pilsobj->cBreakingClasses);
if (brkclsLeading >= pilsobj->cBreakingClasses || brkclsFollowingCache >= pilsobj->cBreakingClasses)
return lserrInvalidBreakingClass;
*pfBroken = FCanBreak(pilsobj, brkclsLeading, brkclsFollowing) &&
(!(ptxtobj->txtf & txtfGlyphBased) || FIwchLastInContext(pilsobj, iwchCur));
iwchCur --;
}
if (*pfBroken)
{
lserr = FillPtboPbrkinf(plocchnk, itxtobj, iwchCur+1, /*itxtobj,*/ iwchCur+1,
brkkindPrev, &pbrkinf, ptbo);
if (lserr != lserrNone) return lserr;
/* fModWidthSpace can be at the last char here only iff fWrapAllSpaces;
if we touch balanced space here, the logic of GetMinCompressAmount should be rethinked!*/
if (pilsobj->pdurRight != NULL && pilsobj->pdurRight[iwchCur + 1] > 0 &&
!pilsobj->ptxtinf[iwchCur - 1].fModWidthSpace)
{
pbrkinf->u.normal.durFix = - pilsobj->pdurRight[iwchCur + 1];
ptbo->objdim.dur -= pilsobj->pdurRight[iwchCur + 1];
}
}
return lserrNone;
}
/* T R Y N E X T B R E A K R E G U L A R */
/*----------------------------------------------------------------------------
%%Function: TryNextBreakRegular
%%Contact: sergeyge
Checks (and sets) for next break inside regular dobj
----------------------------------------------------------------------------*/
static LSERR TryNextBreakRegular(PCLOCCHNK plocchnk, long itxtobj, long iwchSpace, long iwchCur,
BOOL* pfBroken, PBRKOUT ptbo)
{
LSERR lserr;
PTXTOBJ ptxtobj;
PILSOBJ pilsobj;
PLSRUN plsrun;
long iwchLast;
BRKCLS brkclsLeadingCache;
BRKCLS brkclsLeading;
BRKCLS brkclsFollowing;
BRKCLS brkclsJunk;
BREAKINFO* pbrkinf;
*pfBroken = fFalse;
if (iwchCur >= iwchSpace) return lserrNone;
ptxtobj = (PTXTOBJ)plocchnk->plschnk[itxtobj].pdobj;
pilsobj = ptxtobj->plnobj->pilsobj;
Assert(ptxtobj->txtkind == txtkindRegular ||
(ptxtobj->txtkind == txtkindSpecSpace && (pilsobj->grpf & fTxtWrapAllSpaces)));
Assert(pilsobj->grpf & fTxtApplyBreakingRules);
plsrun = plocchnk->plschnk[itxtobj].plsrun;
iwchLast = ptxtobj->iwchLim - 1;
/* The last possibility for break is BEFORE LAST CHAR before space */
if (iwchSpace - 1 < iwchLast)
iwchLast = iwchSpace - 1;
lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols, plsrun,
plocchnk->plschnk[itxtobj].cpFirst + (iwchCur - ptxtobj->iwchFirst),
pilsobj->pwchOrig[iwchCur], &brkclsLeadingCache, &brkclsJunk);
if (lserr != lserrNone) return lserr;
Assert(brkclsLeadingCache < pilsobj->cBreakingClasses && brkclsJunk < pilsobj->cBreakingClasses);
if (brkclsLeadingCache >= pilsobj->cBreakingClasses || brkclsJunk >= pilsobj->cBreakingClasses)
return lserrInvalidBreakingClass;
while (!*pfBroken && iwchCur < iwchLast)
{
brkclsLeading = brkclsLeadingCache;
lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols, plsrun,
plocchnk->plschnk[itxtobj].cpFirst + (iwchCur + 1 - ptxtobj->iwchFirst),
pilsobj->pwchOrig[iwchCur + 1], &brkclsLeadingCache, &brkclsFollowing);
if (lserr != lserrNone) return lserr;
Assert(brkclsLeadingCache < pilsobj->cBreakingClasses && brkclsFollowing < pilsobj->cBreakingClasses);
if (brkclsLeadingCache >= pilsobj->cBreakingClasses || brkclsFollowing >= pilsobj->cBreakingClasses)
return lserrInvalidBreakingClass;
*pfBroken = FCanBreak(pilsobj, brkclsLeading, brkclsFollowing) &&
(!(ptxtobj->txtf & txtfGlyphBased) || FIwchLastInContext(pilsobj, iwchCur));
iwchCur++;
}
if (!*pfBroken && iwchCur == iwchLast && iwchLast < iwchSpace - 1)
{
lserr = CheckBreakAtLastChar(plocchnk, brkclsLeadingCache, iwchLast, itxtobj, pfBroken);
iwchCur++;
if (lserr != lserrNone) return lserr;
}
if (*pfBroken)
{
Assert (iwchCur >= 1);
FillPtboPbrkinf(plocchnk, itxtobj, iwchCur-1, /*itxtobj,*/ iwchCur-1, brkkindNext, &pbrkinf, ptbo);
/* fModWidthSpace can be at the last char here only iff fWrapAllSpaces;
if we touch balanced space here, the logic of GetMinCompressAmount should be rethinked!*/
if (pilsobj->pdurRight != NULL && pilsobj->pdurRight[iwchCur - 1] != 0 &&
!pilsobj->ptxtinf[iwchCur - 1].fModWidthSpace)
{
pbrkinf->u.normal.durFix = - pilsobj->pdurRight[iwchCur - 1];
ptbo->objdim.dur -= pilsobj->pdurRight[iwchCur - 1];
}
}
return lserrNone;
}
/* C H E C K B R E A K A T L A S T C H A R */
/*----------------------------------------------------------------------------
%%Function: CheckBreakAtLastChar
%%Contact: sergeyge
Checks (and sets) for prev break inside regular dobj
----------------------------------------------------------------------------*/
static LSERR CheckBreakAtLastChar(PCLOCCHNK plocchnk, BRKCLS brkclsLeading, long iwch, long itxtobj, BOOL* pfBroken)
{
LSERR lserr;
PTXTOBJ ptxtobj;
PILSOBJ pilsobj;
long itxtobjAfter;
long iwchAfter;
BRKCLS brkclsFollowing;
BRKCLS brkclsJunk;
/* BRKTXTCOND brktxt;*/
*pfBroken = fFalse;
ptxtobj = (PTXTOBJ)plocchnk->plschnk[itxtobj].pdobj;
pilsobj = ptxtobj->plnobj->pilsobj;
if ((ptxtobj->txtf & txtfGlyphBased) && !FIwchLastInContext(pilsobj, iwch))
return lserrNone;
pilsobj = ptxtobj->plnobj->pilsobj;
if (iwch < ptxtobj->iwchLim - 1)
{
lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols, plocchnk->plschnk[itxtobj].plsrun,
plocchnk->plschnk[itxtobj].cpFirst + (iwch + 1 - ptxtobj->iwchFirst),
pilsobj->pwchOrig[iwch + 1], &brkclsJunk, &brkclsFollowing);
if (lserr != lserrNone) return lserr;
Assert(brkclsJunk < pilsobj->cBreakingClasses && brkclsFollowing < pilsobj->cBreakingClasses);
if (brkclsJunk >= pilsobj->cBreakingClasses || brkclsFollowing >= pilsobj->cBreakingClasses)
return lserrInvalidBreakingClass;
*pfBroken = FCanBreak(pilsobj, brkclsLeading, brkclsFollowing);
}
else if (FindNextChar(plocchnk->plschnk, plocchnk->clschnk, itxtobj, iwch,
&itxtobjAfter, &iwchAfter))
{
ptxtobj = (PTXTOBJ)plocchnk->plschnk[itxtobjAfter].pdobj;
if (FRegularBreakableBeforeDobj(ptxtobj))
{
Assert(ptxtobj->txtkind != txtkindSpecSpace || (pilsobj->grpf & fTxtWrapAllSpaces) );
lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols, plocchnk->plschnk[itxtobjAfter].plsrun,
plocchnk->plschnk[itxtobjAfter].cpFirst + (iwchAfter - ptxtobj->iwchFirst),
pilsobj->pwchOrig[iwchAfter], &brkclsJunk, &brkclsFollowing);
if (lserr != lserrNone) return lserr;
Assert(brkclsJunk < pilsobj->cBreakingClasses && brkclsFollowing < pilsobj->cBreakingClasses);
if (brkclsJunk >= pilsobj->cBreakingClasses || brkclsFollowing >= pilsobj->cBreakingClasses)
return lserrInvalidBreakingClass;
*pfBroken = FCanBreak(pilsobj, brkclsLeading, brkclsFollowing);
}
}
/* Manager takes care of the ELSE situation; */
return lserrNone;
}
/* T R Y B R E A K A T H A R D H Y P H E N */
/*----------------------------------------------------------------------------
%%Function: TryBreakAtHardHyphen
%%Contact: sergeyge
Realizes break at hard hyphen
----------------------------------------------------------------------------*/
static LSERR TryBreakAtHardHyphen(PCLOCCHNK plocchnk, long itxtobj, long iwch, BRKKIND brkkind,
BOOL* pfBroken, PBRKOUT ptbo)
{
LSERR lserr;
BREAKINFO* pbrkinf;
Assert(((PTXTOBJ)plocchnk->plschnk[itxtobj].pdobj)->txtkind == txtkindHardHyphen);
Assert(!(((PTXTOBJ)plocchnk->plschnk[itxtobj].pdobj)->txtf & txtfGlyphBased));
lserr = FillPtboPbrkinf(plocchnk, itxtobj, iwch, /*itxtobj,*/ iwch, brkkind, &pbrkinf, ptbo);
if (lserr != lserrNone) return lserr;
*pfBroken = fTrue;
return lserrNone;
}
/* T R Y B R E A K A T O P T B R E A K */
/*----------------------------------------------------------------------------
%%Function: TryBreakAtOptBreak
%%Contact: sergeyge
Realizes break at OptBreak
----------------------------------------------------------------------------*/
static LSERR TryBreakAtOptBreak(PCLOCCHNK plocchnk, long itxtobj, BRKKIND brkkind,
BOOL* pfBroken, PBRKOUT ptbo)
{
LSERR lserr;
PTXTOBJ ptxtobj;
BREAKINFO* pbrkinf;
ptxtobj = (PTXTOBJ)plocchnk->plschnk[itxtobj].pdobj;
Assert(!(ptxtobj->txtf & txtfGlyphBased));
Assert(ptxtobj->txtkind == txtkindOptBreak);
Assert(ptxtobj->iwchLim == ptxtobj->iwchFirst + 1 && (ptxtobj->txtf & txtfVisi)||
ptxtobj->iwchLim == ptxtobj->iwchFirst);
lserr = FillPtboPbrkinf(plocchnk, itxtobj, ptxtobj->iwchLim-1, /*itxtobj,*/ ptxtobj->iwchLim-1,
brkkind, &pbrkinf, ptbo);
if (lserr != lserrNone) return lserr;
ptbo->posichnk.dcp = 1;
pbrkinf->dcp = 1;
pbrkinf->brkt = brktOptBreak;
*pfBroken = fTrue;
return lserrNone;
}
/* T R Y B R E A K A T E O L */
/*----------------------------------------------------------------------------
%%Function: TryBreakAtEOL
%%Contact: sergeyge
Realizes break at EOP/EOL
----------------------------------------------------------------------------*/
static LSERR TryBreakAtEOL(PCLOCCHNK plocchnk, long itxtobj, BRKKIND brkkind, BOOL* pfBroken, PBRKOUT ptbo)
{
LSERR lserr;
PTXTOBJ ptxtobj;
long itxtobjBefore;
long iwchBefore;
BREAKINFO* pbrkinf;
ptxtobj = (PTXTOBJ)plocchnk->plschnk[itxtobj].pdobj;
Assert(ptxtobj->txtkind == txtkindEOL);
Assert(ptxtobj->iwchLim == ptxtobj->iwchFirst + 1);
FindNonSpaceBefore(plocchnk->plschnk, itxtobj, ptxtobj->iwchFirst, &itxtobjBefore, &iwchBefore);
lserr = FillPtboPbrkinf(plocchnk, itxtobj, ptxtobj->iwchFirst, /*itxtobjBefore,*/ iwchBefore,
brkkind, &pbrkinf, ptbo);
if (lserr != lserrNone) return lserr;
*pfBroken = fTrue;
return lserrNone;
}
/* T R Y B R E A K A T N O N R E Q H Y P H E N */
/*----------------------------------------------------------------------------
%%Function: TryBreakAtNonReqHyphen
%%Contact: sergeyge
Realizes break at NonReqHyphen.
----------------------------------------------------------------------------*/
static LSERR TryBreakAtNonReqHyphen(PCLOCCHNK plocchnk, long itxtobj, BRKKIND brkkind,
BOOL* pfBroken, PBRKOUT ptbo)
{
LSERR lserr;
PILSOBJ pilsobj;
PLNOBJ plnobj;
PTXTOBJ ptxtobj;
YSRINF ysrinf;
HYPHOUT hyphout;
BREAKINFO* pbrkinf;
LSCP cpMac;
DWORD kysr;
WCHAR wchYsr;
long itxtobjPrev;
long itxtobjPrevPrev;
BOOL fSuccessful;
long durBorder;
long i;
ptxtobj = (PTXTOBJ)plocchnk->plschnk[itxtobj].pdobj;
plnobj = ptxtobj->plnobj;
pilsobj = plnobj->pilsobj;
cpMac = plocchnk->plschnk[itxtobj].cpFirst;
Assert( ptxtobj->txtkind == txtkindNonReqHyphen);
Assert(!(ptxtobj->txtf & txtfGlyphBased));
lserr = (*pilsobj->plscbk->pfnGetHyphenInfo)(pilsobj->pols, plocchnk->plschnk[itxtobj].plsrun, &kysr, &wchYsr);
if (lserr != lserrNone) return lserr;
if (kysr == kysrNil)
kysr = kysrNormal;
ysrinf.wchYsr = wchYsr;
ysrinf.kysr = (WORD)kysr;
itxtobjPrev = ichnkOutside;
for (i=itxtobj; i >= 0 && plocchnk->plschnk[i].cpFirst > cpMac - 1; i--);
if (i >= 0)
itxtobjPrev = i;
itxtobjPrevPrev = ichnkOutside;
for (i=itxtobj; i >= 0 && plocchnk->plschnk[i].cpFirst > cpMac - 2; i--);
if (i >= 0)
itxtobjPrevPrev = i;
lserr = ProcessYsr(plocchnk, itxtobj, - 1, itxtobjPrev, itxtobjPrevPrev, ysrinf, &fSuccessful, &hyphout);
if (lserr != lserrNone) return lserr;
if (fSuccessful)
{
durBorder = 0;
if (plocchnk->plschnk[itxtobj].plschp->fBorder)
{
lserr = LsdnGetBorderAfter(pilsobj->plsc, ptxtobj->plsdnUpNode, &durBorder);
Assert(lserr == lserrNone);
}
if (plocchnk->ppointUvLoc[itxtobj].u + hyphout.durChangeTotal + durBorder <=
plocchnk->lsfgi.urColumnMax || brkkind == brkkindNext)
{
*pfBroken = fTrue;
ptbo->fSuccessful = fTrue;
ptbo->posichnk.ichnk = itxtobj;
ptbo->posichnk.dcp = 1;
lserr = LsdnGetObjDim(pilsobj->plsc, ptxtobj->plsdnUpNode, &ptbo->objdim);
if (lserr != lserrNone) return lserr;
ptbo->objdim.dur += hyphout.durChangeTotal;
lserr = GetPbrkinf(pilsobj, plocchnk->plschnk[itxtobj].pdobj, brkkind, &pbrkinf);
if (lserr != lserrNone) return lserr;
pbrkinf->pdobj = plocchnk->plschnk[itxtobj].pdobj;
pbrkinf->brkkind = brkkind;
pbrkinf->dcp = 1;
pbrkinf->brkt = brktNonReq;
pbrkinf->u.nonreq.durHyphen = hyphout.durHyphen;
if (pilsobj->grpf & fTxtVisiCondHyphens)
{
pbrkinf->u.nonreq.wchHyphenPres = pilsobj->wchVisiNonReqHyphen;
pbrkinf->u.nonreq.dupHyphen = plnobj->pdup[ptxtobj->iwchFirst];
}
else
{
pbrkinf->u.nonreq.wchHyphenPres = pilsobj->wchHyphen;
pbrkinf->u.nonreq.dupHyphen = hyphout.dupHyphen;
}
pbrkinf->u.nonreq.iwchLim = hyphout.iwchLim;
pbrkinf->u.nonreq.dwchYsr = hyphout.dwchYsr - 1;
pbrkinf->u.nonreq.durPrev = hyphout.durPrev;
pbrkinf->u.nonreq.dupPrev = hyphout.dupPrev;
pbrkinf->u.nonreq.durPrevPrev = hyphout.durPrevPrev;
pbrkinf->u.nonreq.dupPrevPrev = hyphout.dupPrevPrev;
pbrkinf->u.nonreq.ddurDnodePrev = hyphout.ddurDnodePrev;
pbrkinf->u.nonreq.ddurDnodePrevPrev = hyphout.ddurDnodePrevPrev;
pbrkinf->u.nonreq.ddurTotal = hyphout.durChangeTotal;
pbrkinf->u.nonreq.wchPrev = hyphout.wchPrev;
pbrkinf->u.nonreq.wchPrevPrev = hyphout.wchPrevPrev;
pbrkinf->u.nonreq.gindPrev = hyphout.gindPrev;
pbrkinf->u.nonreq.gindPrevPrev = hyphout.gindPrevPrev;
pbrkinf->u.nonreq.igindPrev = hyphout.igindPrev;
pbrkinf->u.nonreq.igindPrevPrev = hyphout.igindPrevPrev;
}
}
return lserrNone;
}
/* T R Y B R E A K A F T E R C H U N K */
/*----------------------------------------------------------------------------
%%Function: TryBreakAfterChunk
%%Contact: sergeyge
----------------------------------------------------------------------------*/
static LSERR TryBreakAfterChunk(PCLOCCHNK plocchnk, BRKCOND brkcond, BOOL* pfBroken, PBRKOUT ptbo)
{
LSERR lserr;
PILSOBJ pilsobj;
PTXTOBJ ptxtobjLast;
long itxtobjLast;
long iwchLast;
long itxtobjBefore;
long iwchBefore;
BOOL fNonSpaceFound;
BRKCOND brkcondTemp;
BREAKINFO* pbrkinf;
*pfBroken = fFalse;
itxtobjLast = plocchnk->clschnk-1;
ptxtobjLast = (PTXTOBJ)plocchnk->plschnk[itxtobjLast].pdobj;
pilsobj = ptxtobjLast->plnobj->pilsobj;
iwchLast = ptxtobjLast->iwchLim - 1;
Assert(ptxtobjLast->txtkind != txtkindTab &&
ptxtobjLast->txtkind != txtkindEOL);
switch (ptxtobjLast->txtkind)
{
case txtkindRegular:
case txtkindSpecSpace:
case txtkindYsrChar:
fNonSpaceFound = FindNonSpaceBefore(plocchnk->plschnk, itxtobjLast, iwchLast,
&itxtobjBefore, &iwchBefore);
if (pilsobj->grpf & fTxtApplyBreakingRules)
{
lserr = CanBreakAfterText(plocchnk, fNonSpaceFound, itxtobjBefore, iwchBefore, &brkcondTemp);
if (lserr != lserrNone) return lserr;
if (iwchBefore != iwchLast && brkcondTemp == brkcondCan)
brkcondTemp = brkcondPlease;
if (brkcond == brkcondPlease && brkcondTemp != brkcondNever ||
brkcond == brkcondCan && brkcondTemp == brkcondPlease)
{
*pfBroken = fTrue;
lserr = FillPtboPbrkinf(plocchnk, itxtobjLast, iwchLast, /*itxtobjBefore,*/ iwchBefore,
brkkindPrev, &pbrkinf, ptbo);
if (lserr != lserrNone) return lserr;
}
}
else
{
Assert(iwchLast >= ptxtobjLast->iwchFirst);
if (brkcond == brkcondPlease ||
brkcond == brkcondCan && iwchLast != iwchBefore)
{
*pfBroken = fTrue;
lserr = FillPtboPbrkinf(plocchnk, itxtobjLast, iwchLast, /*itxtobjBefore,*/ iwchBefore,
brkkindPrev, &pbrkinf, ptbo);
if (lserr != lserrNone) return lserr;
}
}
break;
case txtkindNonBreakSpace:
case txtkindNonBreakHyphen:
case txtkindOptNonBreak:
break;
case txtkindHardHyphen:
lserr = TryBreakAtHardHyphen(plocchnk, itxtobjLast, iwchLast, brkkindPrev, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
break;
case txtkindOptBreak:
lserr = TryBreakAtOptBreak(plocchnk, itxtobjLast, brkkindPrev, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
break;
case txtkindNonReqHyphen:
lserr = TryBreakAtNonReqHyphen(plocchnk, itxtobjLast, brkkindPrev, pfBroken, ptbo);
if (lserr != lserrNone) return lserr;
break;
}
return lserrNone;
}
/* T R Y B R E A K B E F O R E C H U N K */
/*----------------------------------------------------------------------------
%%Function: TryBreakBeforeChunk
%%Contact: sergeyge
----------------------------------------------------------------------------*/
static LSERR TryBreakBeforeChunk(PCLOCCHNK plocchnk, BRKCOND brkcond, BOOL* pfBroken, PBRKOUT ptbo)
{
LSERR lserr;
PILSOBJ pilsobj;
BRKCOND brkcondTemp;
pilsobj = ((PTXTOBJ)plocchnk->plschnk[0].pdobj)->plnobj->pilsobj;
*pfBroken = fFalse;
if (!(pilsobj->grpf & fTxtApplyBreakingRules))
*pfBroken = (brkcond == brkcondPlease);
else
{
lserr = CanBreakBeforeText(plocchnk, &brkcondTemp);
if (lserr != lserrNone) return lserr;
*pfBroken = (brkcond == brkcondPlease && brkcondTemp != brkcondNever ||
brkcond == brkcondCan && brkcondTemp == brkcondPlease);
}
if (*pfBroken)
{
memset(ptbo, 0, sizeof (*ptbo));
ptbo->fSuccessful = fTrue;
return lserrNone;
}
return lserrNone;
}
/* C A N B R E A K B E F O R E T E X T */
/*----------------------------------------------------------------------------
%%Function: CanBreakBeforeText
%%Contact: sergeyge
Checks if break before text chunk is possible.
----------------------------------------------------------------------------*/
static LSERR CanBreakBeforeText(PCLOCCHNK plocchnk, BRKCOND* pbrktxt)
{
LSERR lserr;
PILSOBJ pilsobj;
PTXTOBJ ptxtobj;
WCHAR wch;
BRKCLS brkclsBefore;
BRKCLS brkclsJunk;
Assert(plocchnk->clschnk > 0);
ptxtobj = (PTXTOBJ)plocchnk->plschnk[0].pdobj;
pilsobj = ptxtobj->plnobj->pilsobj;
if (plocchnk->lsfgi.fFirstOnLine || !FRegularBreakableBeforeDobj(ptxtobj))
{
*pbrktxt = brkcondNever;
}
else
{
wch = pilsobj->pwchOrig[ptxtobj->iwchFirst];
if ( (wch == pilsobj->wchSpace || ptxtobj->txtkind == txtkindSpecSpace) &&
!(pilsobj->grpf & fTxtWrapAllSpaces) )
{
*pbrktxt = brkcondNever;
}
else
{
lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols, plocchnk->plschnk[0].plsrun,
plocchnk->plschnk[0].cpFirst, wch, &brkclsJunk, &brkclsBefore);
if (lserr != lserrNone) return lserr;
lserr = (*pilsobj->plscbk->pfnCanBreakBeforeChar)(pilsobj->pols, brkclsBefore, pbrktxt);
if (lserr != lserrNone) return lserr;
}
}
return lserrNone;
}
/* C A N B R E A K A F T E R T E X T */
/*----------------------------------------------------------------------------
%%Function: CanBreakAfterText
%%Contact: sergeyge
Checks if break after text chunk is possible.
----------------------------------------------------------------------------*/
static LSERR CanBreakAfterText(PCLOCCHNK plocchnk, BOOL fNonSpaceFound, long itxtobjBefore,
long iwchBefore, BRKCOND* pbrktxt)
{
LSERR lserr;
PILSOBJ pilsobj;
PTXTOBJ ptxtobj;
BRKCLS brkclsAfter;
BRKCLS brkclsJunk;
if (fNonSpaceFound)
{
ptxtobj = (PTXTOBJ)plocchnk->plschnk[itxtobjBefore].pdobj;
pilsobj = ptxtobj->plnobj->pilsobj;
Assert(ptxtobj->txtkind != txtkindTab &&
ptxtobj->txtkind != txtkindSpecSpace &&
ptxtobj->txtkind != txtkindEOL);
if (ptxtobj->txtkind == txtkindHardHyphen ||
ptxtobj->txtkind == txtkindOptBreak ||
ptxtobj->txtkind == txtkindNonReqHyphen)
{
*pbrktxt = brkcondPlease;
}
else if (ptxtobj->txtkind == txtkindNonBreakSpace ||
ptxtobj->txtkind == txtkindNonBreakHyphen ||
ptxtobj->txtkind == txtkindOptNonBreak)
{
*pbrktxt = brkcondNever;
}
else
{
Assert(ptxtobj->txtkind == txtkindRegular ||
ptxtobj->txtkind == txtkindYsrChar);
lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols,
plocchnk->plschnk[itxtobjBefore].plsrun,
plocchnk->plschnk[itxtobjBefore].cpFirst + (iwchBefore - ptxtobj->iwchFirst),
pilsobj->pwchOrig[iwchBefore], &brkclsAfter, &brkclsJunk);
if (lserr != lserrNone) return lserr;
lserr = (*pilsobj->plscbk->pfnCanBreakAfterChar)(pilsobj->pols, brkclsAfter, pbrktxt);
if (lserr != lserrNone) return lserr;
}
}
else
{
/* REVIEW sergeyge: check if it is correct */
*pbrktxt = brkcondPlease;
// *pbrktxt = brkcondNever;
}
return lserrNone;
}
/* F I L L P T B O P B R K I N F */
/*----------------------------------------------------------------------------
%%Function: FillPtboPbrkinf
%%Contact: sergeyge
Prepares output of the breaking procedure
----------------------------------------------------------------------------*/
static LSERR FillPtboPbrkinf(PCLOCCHNK plocchnk, long itxtobj, long iwch,
/* long itxtobjBefore,*/ long iwchBefore, BRKKIND brkkind,
BREAKINFO** ppbrkinf, PBRKOUT ptbo)
{
LSERR lserr;
PILSOBJ pilsobj;
PTXTOBJ ptxtobj;
long dwchBreak;
long igindLim;
long dur;
ptxtobj = (PTXTOBJ)plocchnk->plschnk[itxtobj].pdobj;
pilsobj = ptxtobj->plnobj->pilsobj;
dwchBreak = iwch - ptxtobj->iwchFirst + 1;
igindLim = 0;
if (ptxtobj->txtf & txtfGlyphBased)
{
igindLim = IgindFirstFromIwch(ptxtobj, ptxtobj->iwchFirst + dwchBreak);
lserr = CalcPartWidthsGlyphs(ptxtobj, dwchBreak, &ptbo->objdim, &dur);
}
else
lserr = CalcPartWidths(ptxtobj, dwchBreak, &ptbo->objdim, &dur);
if (lserr != lserrNone) return lserr;
ptbo->fSuccessful = fTrue;
ptbo->objdim.dur = dur;
ptbo->posichnk.ichnk = itxtobj;
ptbo->posichnk.dcp = dwchBreak;
if (iwchBefore < ptxtobj->iwchFirst)
{
if (!(pilsobj->grpf & fTxtSpacesInfluenceHeight))
{
ptbo->objdim.heightsRef.dvMultiLineHeight = dvHeightIgnore;
ptbo->objdim.heightsPres.dvMultiLineHeight = dvHeightIgnore;
}
}
lserr = GetPbrkinf(pilsobj, (PDOBJ)ptxtobj, brkkind, ppbrkinf);
if (lserr != lserrNone) return lserr;
(*ppbrkinf)->pdobj = (PDOBJ)ptxtobj;
(*ppbrkinf)->brkkind = brkkind;
(*ppbrkinf)->dcp = (LSDCP)dwchBreak;
(*ppbrkinf)->u.normal.igindLim = igindLim;
Assert((*ppbrkinf)->brkt == brktNormal);
Assert((*ppbrkinf)->u.normal.durFix == 0);
return lserrNone;
}