|
|
#include "dispmain.h"
#include "lsc.h"
#include "lsdnode.h"
#include "lstflow.h"
#include "lsline.h"
#include "lssubl.h"
#include "dispul.h"
#include "lstfset.h"
#include "lssubset.h"
#include "dispmisc.h"
#include "dispi.h"
#include "dninfo.h"
#include "memory.h"
#include "port.h"
static LSERR DisplayDnode(PLSC plsc, PLSDNODE pdn, const POINT* pptOrg, POINTUV pt, UINT kdispmode, LSTFLOW lstflow, const RECT* prectClip, BOOL fDrawStrike, BOOL fDrawUnderline, long upLimUnderline); static LSERR ShadeSubline(PLSSUBL plssubl, const POINT* pptOrg, UINT kdispmode, const RECT* prectClip, long upLimUnderline, long upLeftIndent);
static LSERR DrawBorders(PLSSUBL plssubl, const POINT* pptOrg, UINT kdispmode, const RECT* prectClip, long upLimUnderline, long upLeftIndent);
static long GetDupUnderline(long up, long dup, long upLimUnderline);
static BOOL FGetNeighboringOpeningBorder(PLSDNODE pdnClosingBorder, PLSDNODE pdnNext, POINTUV* pptStart, LSCP cpLim, LSTFLOW lstflowMain, PLSDNODE* ppdnOpeningBorder, POINTUV* pptStartOpeningBorder);
#define FIsDnodeToShade(pdn, cpLim) (FDnodeBeforeCpLim(pdn, cpLim) && FIsDnodeReal(pdn) && \
!(pdn)->u.real.lschp.fInvisible && (pdn)->u.real.lschp.fShade)
#define UpdateMaximum(a,b) if ((a) < (b)) (a) = (b); else
#define FIsDnodeOpeningBorder(pdn, lstflowMain) ((pdn)->fOpenBorder ^ ((pdn)->plssubl->lstflow != (lstflowMain)))
#define FIsDnodeClosingBorder(pdn, lstflowMain) (!FIsDnodeOpeningBorder(pdn, lstflowMain))
// %%Function: DisplaySublineCore
// %%Contact: victork
//
//
// Displays subline with shading, striking and underlining, merging consecutive underlined dnodes
//
// Logic to select underlining method:
//
// If (metrics_are_good)
// Draw_by_fnDrawUnderline;
// else
// if (There_is_merging_going)
// Draw_by_pfnDrawUnderlineAsText;
// else
// Draw_along_with_Display;
LSERR DisplaySublineCore( PLSSUBL plssubl, /* subline to display */ const POINT* pptOrg, /* (x,y) starting point */ UINT kdispmode, /* transparent or opaque */ const RECT* prectClip, /* clipping rect (x,y) */ long upLimUnderline, long upLeftIndent) { LSERR lserr; LSCP cpLim = plssubl->cpLimDisplay; PLSC plsc = plssubl->plsc; LSTFLOW lstflowMain = plssubl->lstflow; BOOL fCollectVisual = plsc->plslineDisplay->fCollectVisual;
LSSTRIKEMETRIC lsstrikemetric;
// Underline merge group - normal scenario: we first count dnodes willing to participate
// in merging looking ahead, then draw them, then underline them as a whole
PLSDNODE pdnFirstInGroup = NULL; /* First dnode in Underline merge group */ int cdnodesLeftInGroup = 0; /* these are not displayed yet */ int cdnodesToUnderline = 0; /* these are already displayed */ BOOL fGoodUnderline = fFalse; /* is there metric for UL */ LSULMETRIC lsulmetric; /* merge metric info (if fGoodUnderline) */ long upUnderlineStart = 0; /* Starting point for the group */ BOOL fMergeUnderline = fFalse; /* There is more then one dnode in the group */
BOOL fUnderlineWithDisplay, fStrikeWithDisplay;
POINTUV pt; PLSDNODE pdn;
FLineValid(plsc->plslineDisplay, plsc); // Assert the display context is valid
Assert(plssubl->plsdnUpTemp == NULL); // against displaying accepted sublines
if (fCollectVisual) { CreateDisplayTree(plssubl); }
if (plsc->plslineDisplay->AggregatedDisplayFlags & fPortDisplayShade) { lserr = ShadeSubline(plssubl, pptOrg, kdispmode, prectClip, upLimUnderline, upLeftIndent); if (lserr != lserrNone) return lserr; }
pt.u = upLeftIndent; pt.v = 0; pdn = AdvanceToFirstDnode(plssubl, lstflowMain, &pt);
while (FDnodeBeforeCpLim(pdn, cpLim)) {
if (pdn->klsdn == klsdnReal && !pdn->u.real.lschp.fInvisible) { /* Real dnode */ fStrikeWithDisplay = fFalse; if (pdn->u.real.lschp.fStrike) { BOOL fGoodStrike; lserr = GetStrikeMetric(plsc, pdn, lstflowMain, &lsstrikemetric, &fGoodStrike); if (lserr != lserrNone) return lserr; fStrikeWithDisplay = !fGoodStrike; }
fUnderlineWithDisplay = fFalse; if (pdn->u.real.lschp.fUnderline && pt.u < upLimUnderline) { /* Node has underline */ if (cdnodesLeftInGroup == 0) { /* There are no on-going UL group */ /* Find out how many dnodes will participate in the merge and what metric to use */ lserr = GetUnderlineMergeMetric(plsc, pdn, pt, upLimUnderline, lstflowMain, cpLim, &lsulmetric, &cdnodesLeftInGroup , &fGoodUnderline); if (lserr != lserrNone) return lserr; fMergeUnderline = (cdnodesLeftInGroup > 1); cdnodesToUnderline = 0; }
if (!fGoodUnderline) fUnderlineWithDisplay = !fMergeUnderline; else fUnderlineWithDisplay = fFalse;
if (!fUnderlineWithDisplay) { if (cdnodesToUnderline == 0) { /* Mark starting point of underline merge */ pdnFirstInGroup = pdn; upUnderlineStart = pt.u; } /* Add to pending UL dnode count */ ++cdnodesToUnderline; } // current dnode will be displayed shortly - consider it done
--cdnodesLeftInGroup ; } lserr = DisplayDnode(plsc, pdn, pptOrg, pt, kdispmode, lstflowMain, prectClip, fStrikeWithDisplay, fUnderlineWithDisplay, upLimUnderline); if (lserr != lserrNone) return lserr; if (pdn->u.real.lschp.fStrike && !fStrikeWithDisplay) { lserr = StrikeDnode(plsc, pdn, pptOrg, pt, &lsstrikemetric, kdispmode, prectClip, upLimUnderline, lstflowMain); if (lserr != lserrNone) return lserr; } /* Draw any pending UL after last dnode in group has been drawn */ if (cdnodesToUnderline != 0 && cdnodesLeftInGroup == 0) { lserr = DrawUnderlineMerge(plsc, pdnFirstInGroup, pptOrg, cdnodesToUnderline, upUnderlineStart, fGoodUnderline, &lsulmetric, kdispmode, prectClip, upLimUnderline, lstflowMain); if (lserr != lserrNone) return lserr; cdnodesToUnderline = 0; } } pdn = AdvanceToNextDnode(pdn, lstflowMain, &pt); } if (fCollectVisual) { // call display method for submitting dnodes
pt.u = upLeftIndent; pt.v = 0; pdn = AdvanceToFirstSubmittingDnode(plssubl, lstflowMain, &pt);
while (FDnodeBeforeCpLim(pdn, cpLim)) { lserr = DisplayDnode(plsc, pdn, pptOrg, pt, kdispmode, lstflowMain, prectClip, fFalse, fFalse, upLimUnderline); if (lserr != lserrNone) return lserr; pdn = AdvanceToNextSubmittingDnode(pdn, lstflowMain, &pt); } } if (plsc->plslineDisplay->AggregatedDisplayFlags & fPortDisplayBorder) { lserr = DrawBorders(plssubl, pptOrg, kdispmode, prectClip, upLimUnderline, upLeftIndent); if (lserr != lserrNone) return lserr; }
if (fCollectVisual) { // destroy display tree
DestroyDisplayTree(plssubl); }
return lserrNone; }
// %%Function: DisplayDnode
// %%Contact: victork
static LSERR DisplayDnode(PLSC plsc, PLSDNODE pdn, const POINT* pptOrg, POINTUV pt, UINT kdispmode, LSTFLOW lstflowMain, const RECT* prectClip, BOOL fDrawStrike, BOOL fDrawUnderline, long upLimUnderline) { PDOBJ pdobj; DISPIN dispin;
pdobj = pdn->u.real.pdobj;
dispin.plschp = &(pdn->u.real.lschp); dispin.plsrun = pdn->u.real.plsrun; dispin.kDispMode = kdispmode; dispin.lstflow = pdn->plssubl->lstflow; dispin.prcClip = (RECT*) prectClip;
dispin.fDrawUnderline = fDrawUnderline; dispin.fDrawStrikethrough = fDrawStrike; dispin.heightsPres = pdn->u.real.objdim.heightsPres; dispin.dup = pdn->u.real.dup; dispin.dupLimUnderline = GetDupUnderline(pt.u, dispin.dup, upLimUnderline);
if (dispin.lstflow != lstflowMain) { // Dnode lstflow is opposite to lstflowMain - get real starting point
pt.u = pt.u + dispin.dup - 1;
// Partial underlining can only happen on the top level
Assert(dispin.dupLimUnderline == 0 || dispin.dupLimUnderline == dispin.dup); }
pt.v += pdn->u.real.lschp.dvpPos; LsPointXYFromPointUV(pptOrg, lstflowMain, &pt, &(dispin.ptPen)); return (*plsc->lsiobjcontext.rgobj[pdn->u.real.lschp.idObj].lsim.pfnDisplay)(pdobj, &dispin); }
// %%Function: ShadeSubline
// %%Contact: victork
LSERR ShadeSubline(PLSSUBL plssubl, /* subline to shade */ const POINT* pptOrg, /* (x,y) starting point */ UINT kdispmode, /* transparent or opaque */ const RECT* prectClip, /* clipping rect (x,y) */ long upLimUnderline, long upLeftIndent) { LSERR lserr; LSCP cpLim = plssubl->cpLimDisplay; PLSC plsc = plssubl->plsc; PLSLINE plsline = plsc->plslineDisplay; LSTFLOW lstflowMain = plssubl->lstflow;
POINTUV pt; PLSDNODE pdn;
HEIGHTS heightsLineWithAddedSpace; HEIGHTS heightsLineWithoutAddedSpace; OBJDIM objdimSubline; POINT ptStart; PLSRUN plsrunFirst, plsrunPrevious; long upStart; long dupInclTrail, dupExclTrail; HEIGHTS heightsRunsInclTrail; HEIGHTS heightsRunsExclTrail;
BOOL fInterruptShading; BOOL fCollectVisual = plsc->plslineDisplay->fCollectVisual;
heightsLineWithAddedSpace.dvAscent = plsline->dvpAbove + plsline->lslinfo.dvpAscent; heightsLineWithAddedSpace.dvDescent = plsline->dvpBelow + plsline->lslinfo.dvpDescent; heightsLineWithAddedSpace.dvMultiLineHeight = dvHeightIgnore; heightsLineWithoutAddedSpace.dvAscent = plsline->lslinfo.dvpAscent; heightsLineWithoutAddedSpace.dvDescent = plsline->lslinfo.dvpDescent; heightsLineWithoutAddedSpace.dvMultiLineHeight = dvHeightIgnore; lserr = LssbGetObjDimSubline(plssubl, &lstflowMain, &objdimSubline); if (lserr != lserrNone) return lserr; if (fCollectVisual) { // shade submitting dnodes - pretend they are on the top level, no merging for them
pt.u = upLeftIndent; pt.v = 0; pdn = AdvanceToFirstSubmittingDnode(plssubl, lstflowMain, &pt);
while (FDnodeBeforeCpLim(pdn, cpLim)) { if (FIsDnodeToShade(pdn, cpLim)) { LsPointXYFromPointUV(pptOrg, lstflowMain, &pt, &ptStart); dupInclTrail = pdn->u.real.dup; dupExclTrail = GetDupUnderline(pt.u, dupInclTrail, upLimUnderline); lserr = (*plsc->lscbk.pfnShadeRectangle)(plsc->pols, pdn->u.real.plsrun, &ptStart, &heightsLineWithAddedSpace, &heightsLineWithoutAddedSpace, &(objdimSubline.heightsPres), &(pdn->u.real.objdim.heightsPres), &(pdn->u.real.objdim.heightsPres), dupExclTrail, dupInclTrail, lstflowMain, kdispmode, prectClip); if (lserr != lserrNone) return lserr; } pdn = AdvanceToNextSubmittingDnode(pdn, lstflowMain, &pt); } }
pt.u = upLeftIndent; pt.v = 0; pdn = AdvanceToFirstDnode(plssubl, lstflowMain, &pt);
while (FDnodeBeforeCpLim(pdn, cpLim) && !FIsDnodeToShade(pdn, cpLim)) { pdn = AdvanceToNextDnode(pdn, lstflowMain, &pt); }
// next loop will do one shading merge at a run
while (FDnodeBeforeCpLim(pdn, cpLim)) { // pdn is the first dnode to participate in the shade merge
// initialize the merge with this dnode data
LsPointXYFromPointUV(pptOrg, lstflowMain, &pt, &ptStart); plsrunFirst = pdn->u.real.plsrun; upStart = pt.u; heightsRunsInclTrail = pdn->u.real.objdim.heightsPres;
// What should we have in heightsRunsExclTrail if all shading is in trailing spaces?
// I decided to put heights of the first run there for convenience sake
// Client can check for dupExclTrail == 0.
heightsRunsExclTrail = heightsRunsInclTrail;
// We will now append to the merge as many dnodes as possible
// The loop will stop when dnode doesn't need to be shaded - while condition
// or if callback says two dnodes are not to be shaded together - break inside
plsrunPrevious = pdn->u.real.plsrun; pdn = AdvanceToNextDnode(pdn, lstflowMain, &pt); while (FIsDnodeToShade(pdn, cpLim)) { lserr = (*plsc->lscbk.pfnFInterruptShade)(plsc->pols, plsrunPrevious,pdn->u.real.plsrun, &fInterruptShading); if (lserr != lserrNone) return lserr;
if (fInterruptShading) { break; } plsrunPrevious = pdn->u.real.plsrun;
UpdateMaximum(heightsRunsInclTrail.dvAscent, pdn->u.real.objdim.heightsPres.dvAscent); UpdateMaximum(heightsRunsInclTrail.dvDescent, pdn->u.real.objdim.heightsPres.dvDescent); UpdateMaximum(heightsRunsInclTrail.dvMultiLineHeight, pdn->u.real.objdim.heightsPres.dvMultiLineHeight);
if (pt.u < upLimUnderline) { UpdateMaximum(heightsRunsExclTrail.dvAscent, pdn->u.real.objdim.heightsPres.dvAscent); UpdateMaximum(heightsRunsExclTrail.dvDescent, pdn->u.real.objdim.heightsPres.dvDescent); UpdateMaximum(heightsRunsExclTrail.dvMultiLineHeight, pdn->u.real.objdim.heightsPres.dvMultiLineHeight); }
pdn = AdvanceToNextDnode(pdn, lstflowMain, &pt); } // Merge is stopped - time to draw
dupInclTrail = pt.u - upStart; dupExclTrail = GetDupUnderline(upStart, dupInclTrail, upLimUnderline);
lserr = (*plsc->lscbk.pfnShadeRectangle)(plsc->pols, plsrunFirst, &ptStart, &heightsLineWithAddedSpace, &heightsLineWithoutAddedSpace, &(objdimSubline.heightsPres), &heightsRunsExclTrail, &heightsRunsInclTrail, dupExclTrail, dupInclTrail, lstflowMain, kdispmode, prectClip); if (lserr != lserrNone) return lserr;
// get to the beginning of the next shade merge
while (FDnodeBeforeCpLim(pdn, cpLim) && !FIsDnodeToShade(pdn, cpLim)) { pdn = AdvanceToNextDnode(pdn, lstflowMain, &pt); } } return lserrNone; }
// %%Function: GetDupUnderline
// %%Contact: victork
//
// Calculate dup of underlined part (of dnode). Deals with situations when upLimUnderline is
// outside of [upStart, upStart + dup]
static long GetDupUnderline(long upStart, long dup, long upLimUnderline)
{ long dupLimUnderline; dupLimUnderline = upLimUnderline - upStart; if (dupLimUnderline >= dup) { dupLimUnderline = dup; } else if (dupLimUnderline < 0) { dupLimUnderline = 0; }
return dupLimUnderline; }
// %%Function: DrawBorders
// %%Contact: victork
LSERR DrawBorders(PLSSUBL plssubl, const POINT* pptOrg, /* (x,y) starting point */ UINT kdispmode, /* transparent or opaque */ const RECT* prectClip, /* clipping rect (x,y) */ long upLimUnderline, long upLeftIndent) { LSERR lserr; LSCP cpLim = plssubl->cpLimDisplay; PLSC plsc = plssubl->plsc; PLSLINE plsline = plsc->plslineDisplay; LSTFLOW lstflowMain = plssubl->lstflow;
HEIGHTS heightsLineWithAddedSpace; HEIGHTS heightsLineWithoutAddedSpace; OBJDIM objdimSubline; HEIGHTS heightsRuns;
long upStart, dupBorder, dupBordered; POINT ptStart; PLSRUN plsrunOpeningBorder, plsrunClosingBorder; POINTUV pt, ptAfterClosingBorder; PLSDNODE pdn, pdnPrev, pdnClosingBorder, pdnAfterClosingBorder;
BOOL fClosingOpeningBorderSequenceFound; PLSDNODE pdnNextOpeningBorder; POINTUV ptStartNextOpeningBorder; BOOL fInterruptBorder;
heightsLineWithAddedSpace.dvAscent = plsline->dvpAbove + plsline->lslinfo.dvpAscent; heightsLineWithAddedSpace.dvDescent = plsline->dvpBelow + plsline->lslinfo.dvpDescent; heightsLineWithAddedSpace.dvMultiLineHeight = dvHeightIgnore; heightsLineWithoutAddedSpace.dvAscent = plsline->lslinfo.dvpAscent; heightsLineWithoutAddedSpace.dvDescent = plsline->lslinfo.dvpDescent; heightsLineWithoutAddedSpace.dvMultiLineHeight = dvHeightIgnore; lserr = LssbGetObjDimSubline(plssubl, &lstflowMain, &objdimSubline); if (lserr != lserrNone) return lserr; pt.u = upLeftIndent; pt.v = 0; pdn = AdvanceToFirstDnode(plssubl, lstflowMain, &pt);
// next loop will draw one border at a run
while (FDnodeBeforeCpLim(pdn, cpLim)) { // first find an opening border
while (FDnodeBeforeCpLim(pdn, cpLim) && !FIsDnodeBorder(pdn)) { pdn = AdvanceToNextDnode(pdn, lstflowMain, &pt); }
if (FDnodeBeforeCpLim(pdn, cpLim)) { // border is found - it must be an opening one
Assert(FIsDnodeOpeningBorder(pdn, lstflowMain));
// remember the starting point and border width
upStart = pt.u; LsPointXYFromPointUV(pptOrg, lstflowMain, &pt, &ptStart); dupBorder = pdn->u.pen.dup;
// take lsrun from the first bordered run
pdn = AdvanceToNextDnode(pdn, lstflowMain, &pt);
Assert(FDnodeBeforeCpLim(pdn, cpLim) && FIsDnodeReal(pdn));
plsrunOpeningBorder = pdn->u.real.plsrun;
// start collecting max run height
heightsRuns = pdn->u.real.objdim.heightsPres;
// now look for an closing border to draw, collecting max run height
// loop will be ended by break
for (;;) { // find a border
pdnPrev = NULL;
while (FDnodeBeforeCpLim(pdn, cpLim) && !FIsDnodeBorder(pdn)) { if (FIsDnodeReal(pdn)) { UpdateMaximum(heightsRuns.dvAscent, pdn->u.real.objdim.heightsPres.dvAscent); UpdateMaximum(heightsRuns.dvDescent, pdn->u.real.objdim.heightsPres.dvDescent); UpdateMaximum(heightsRuns.dvMultiLineHeight, pdn->u.real.objdim.heightsPres.dvMultiLineHeight); } pdnPrev = pdn; pdn = AdvanceToNextDnode(pdn, lstflowMain, &pt); } Assert(FDnodeBeforeCpLim(pdn, cpLim)); // border is found - it must be a closing one
// Sequence opening border - closing border is prohibited by formatting
Assert(pdnPrev != NULL); Assert(FIsDnodeReal(pdnPrev)); Assert(FIsDnodeClosingBorder(pdn, lstflowMain)); Assert(pdn->u.pen.dup == dupBorder);
pdnClosingBorder = pdn; plsrunClosingBorder = pdnPrev->u.real.plsrun; pdn = AdvanceToNextDnode(pdn, lstflowMain, &pt); ptAfterClosingBorder = pt; pdnAfterClosingBorder = pdn;
// check for the "surplus borders" situation: closing border and opening border of the same
// type brought together by submitting sublines. (Hard to check at formatting time)
// It can be more complicated if there are bordered trailing spaces between the two borders
// (Trailing spaces can happen in the middle of the line in Bidi case). The problem is
// that border is moved away from trailing spaces at SetBreak time. We try to restore
// bordering of trailing spaces when they are in the middle of bordered line below.
fClosingOpeningBorderSequenceFound = FGetNeighboringOpeningBorder(pdnClosingBorder, pdn, &pt, cpLim, lstflowMain, &pdnNextOpeningBorder, &ptStartNextOpeningBorder); if (fClosingOpeningBorderSequenceFound) { pdn = pdnNextOpeningBorder; pt = ptStartNextOpeningBorder; pdn = AdvanceToNextDnode(pdn, lstflowMain, &pt);
Assert(FDnodeBeforeCpLim(pdn, cpLim) && FIsDnodeReal(pdn));
lserr = (*plsc->lscbk.pfnFInterruptBorder)(plsc->pols, plsrunClosingBorder, pdn->u.real.plsrun, &fInterruptBorder); if (lserr != lserrNone) return lserr; if (!fInterruptBorder) { // Client decided against interrupting border here. These two border dnodes
// will be ignored. Space reserved for them by formatting will be left empty.
// Continue seeking for closing border starting from pdn
continue; } } // No special situation - we are ready to display
// Well, we are almost ready. Word doesn't normally draw borders in trailing spaces,
// just reserve space for them and leave this space blank. In FE Word, however,
// borders are drawn if underlining of trailing spaces is required.
// We hack in the following way: Borders in trailing area are deleted after formatting.
// If there are a border which opens in text and closes in trailing spaces, it is moved
// to the left to exclude trailing spaces. If the fUnderlineTrailSpacesRM flag is on
// the "moved" border is marked and now have to be displayed up to upLimUnderline.
// Yes, it's bad, it will appear painted over already displayed spaces (queries!) and
// what about a scenario when not all trailing spaces are bordered? We know, we know.
// Word can even get a "negative" border with a negative advance field.
dupBordered = ptAfterClosingBorder.u - upStart; if (pdnClosingBorder->fBorderMovedFromTrailingArea) { Assert(ptAfterClosingBorder.u <= upLimUnderline); dupBordered = upLimUnderline - upStart; } lserr = (*plsc->lscbk.pfnDrawBorder)(plsc->pols, plsrunOpeningBorder, &ptStart, &heightsLineWithAddedSpace, &heightsLineWithoutAddedSpace, &(objdimSubline.heightsPres), &heightsRuns, dupBorder, dupBordered, lstflowMain, kdispmode, prectClip); if (lserr != lserrNone) return lserr; // maybe we peeped ahead checking for the surplus borders - return
pdn = pdnAfterClosingBorder; pt = ptAfterClosingBorder; break; } }
// Previous border is drawn, start looking for the next one from pdn.
} return lserrNone; }
// Find an opening border neighboring pdnClosingBorder broght together by submitting sublines.
// Ignore trailing spaces that lost their borders during SetBreak - their heights will be ignored.
// Input: pdnClosingBorder
// pdnNext - next to pdnClosingBorder (in visual order)
// ptStart - starting poing of pdnNext (in visual order)
// cpLim and lstflowMain
// Output: pdnOpeningBorder and ptStartOpeningBorder
static BOOL FGetNeighboringOpeningBorder(PLSDNODE pdnClosingBorder, PLSDNODE pdnNext, POINTUV* pptStart, LSCP cpLim, LSTFLOW lstflowMain, PLSDNODE* ppdnOpeningBorder, POINTUV* pptStartOpeningBorder) { PLSDNODE pdn; POINTUV pt;
pdn = pdnNext; pt = *pptStart; // skip spaces that were bordered once
// not sure about spaces, but what else could be skipped?
while (FDnodeBeforeCpLim(pdn, cpLim) && FIsDnodeReal(pdn) && pdn->u.real.lschp.fBorder) { pdn = AdvanceToNextDnode(pdn, lstflowMain, &pt); }
if (!FDnodeBeforeCpLim(pdn, cpLim)) { return fFalse; }
// looking for an opening border from another subline
if (FIsDnodeOpeningBorder(pdn, lstflowMain) && pdn->plssubl != pdnClosingBorder->plssubl) { *ppdnOpeningBorder = pdn; *pptStartOpeningBorder = pt; return fTrue; }
return fFalse; }
// N.B.
// Interruption of underlining/shading logic by invisible dnode is OK, because we are sure that no
// underlining/shading is allowed in preprinted forms.
|