719 lines
22 KiB
C
719 lines
22 KiB
C
|
#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.
|
||
|
|
||
|
|