544 lines
14 KiB
C
544 lines
14 KiB
C
#include "dispmisc.h"
|
|
#include "lsdnode.h"
|
|
#include "lssubl.h"
|
|
|
|
static long AddSublineAdvanceWidth(PLSSUBL plssubl);
|
|
static PLSDNODE AdvanceToNextVisualDnodeCore(PLSDNODE, LSTFLOW, POINTUV*);
|
|
static PLSDNODE NextVisualDnodeOnTheLevel(PLSDNODE pdn, LSTFLOW lstflowMain);
|
|
|
|
#define fUVerticalPlusVDirection (fUVertical|fVDirection) // see comments in lstfset.c
|
|
|
|
// Has this dnode submitted subline(s) for display?
|
|
#define FIsSubmittingDnode(pdn) (FIsDnodeReal(pdn) && (pdn)->u.real.pinfosubl != NULL && \
|
|
(pdn)->u.real.pinfosubl->fUseForDisplay)
|
|
|
|
// Has this dnode accepted subline(s) for display?
|
|
#define FIsAcceptingDnode(pdn) (FIsDnodeReal(pdn) && (pdn)->u.real.pinfosubl != NULL && \
|
|
((pdn)->u.real.pinfosubl->rgpsubl)[0]->fAcceptedForDisplay)
|
|
|
|
|
|
// %%Function: CreateDisplayTree
|
|
// %%Contact: victork
|
|
//
|
|
/* CreateDisplayTree sets plsdnUpTemp in sublines to be displayed with given subline,
|
|
* rejects wrong sublines, submitted for display, sets fAcceptedForDisplay in good ones
|
|
*/
|
|
|
|
void CreateDisplayTree(PLSSUBL plssubl)
|
|
{
|
|
LSTFLOW lstflowMain = plssubl->lstflow;
|
|
|
|
PLSDNODE pdn = plssubl->plsdnFirst;
|
|
|
|
long dupSum;
|
|
BOOL fAccept;
|
|
DWORD i;
|
|
LSTFLOW lstflowSubline;
|
|
|
|
while (pdn != NULL) /* don't care about break */
|
|
{
|
|
if (FIsSubmittingDnode(pdn))
|
|
{
|
|
|
|
Assert(pdn->u.real.pinfosubl->cSubline > 0);
|
|
|
|
fAccept = fTrue;
|
|
|
|
lstflowSubline = ((pdn->u.real.pinfosubl->rgpsubl)[0])->lstflow;
|
|
|
|
// reject if one tflow is vertical, another is horizontal or v-directions are not the same
|
|
// (see explanation of bits meaning in lstfset.c)
|
|
|
|
if ((lstflowSubline ^ lstflowMain) & fUVerticalPlusVDirection)
|
|
{
|
|
fAccept = fFalse;
|
|
}
|
|
|
|
dupSum = 0;
|
|
|
|
for (i = 0; i < pdn->u.real.pinfosubl->cSubline; i++)
|
|
{
|
|
dupSum += AddSublineAdvanceWidth((pdn->u.real.pinfosubl->rgpsubl)[i]);
|
|
|
|
// all tflows should be the same
|
|
|
|
if (((pdn->u.real.pinfosubl->rgpsubl)[i])->lstflow != lstflowSubline)
|
|
{
|
|
fAccept = fFalse;
|
|
}
|
|
|
|
// Submitting empty sublines is prohibited
|
|
|
|
if (((pdn->u.real.pinfosubl->rgpsubl)[i])->plsdnFirst == NULL)
|
|
{
|
|
fAccept = fFalse;
|
|
}
|
|
}
|
|
|
|
// reject if sublines don't sum up to the dnode width
|
|
|
|
if (dupSum != pdn->u.real.dup)
|
|
{
|
|
fAccept = fFalse;
|
|
}
|
|
|
|
if (fAccept)
|
|
{
|
|
for (i = 0; i < pdn->u.real.pinfosubl->cSubline; i++)
|
|
{
|
|
((pdn->u.real.pinfosubl->rgpsubl)[i])->plsdnUpTemp = pdn;
|
|
((pdn->u.real.pinfosubl->rgpsubl)[i])->fAcceptedForDisplay = fTrue;
|
|
CreateDisplayTree((pdn->u.real.pinfosubl->rgpsubl)[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
pdn = pdn->plsdnNext;
|
|
}
|
|
}
|
|
|
|
|
|
// %%Function: DestroyDisplayTree
|
|
// %%Contact: victork
|
|
//
|
|
/*
|
|
* DestroyDisplayTree nulls plsdnUpTemp in sublines displayed with given subline.
|
|
*/
|
|
|
|
void DestroyDisplayTree(PLSSUBL plssubl)
|
|
{
|
|
PLSDNODE pdn = plssubl->plsdnFirst;
|
|
DWORD i;
|
|
|
|
while (pdn != NULL) /* don't care about break */
|
|
{
|
|
if (FIsAcceptingDnode(pdn))
|
|
{
|
|
for (i = 0; i < pdn->u.real.pinfosubl->cSubline; i++)
|
|
{
|
|
((pdn->u.real.pinfosubl->rgpsubl)[i])->plsdnUpTemp = NULL;
|
|
((pdn->u.real.pinfosubl->rgpsubl)[i])->fAcceptedForDisplay = fFalse;
|
|
DestroyDisplayTree((pdn->u.real.pinfosubl->rgpsubl)[i]);
|
|
}
|
|
}
|
|
|
|
pdn = pdn->plsdnNext;
|
|
}
|
|
}
|
|
|
|
|
|
// %%Function: AdvanceToNextDnode
|
|
// %%Contact: victork
|
|
//
|
|
/*
|
|
* Advance to the next (visual) node and update pen position, skipping submitting dnodes.
|
|
*/
|
|
|
|
PLSDNODE AdvanceToNextDnode(PLSDNODE pdn, LSTFLOW lstflowMain, POINTUV* pptpen)
|
|
{
|
|
// move to the next
|
|
|
|
pdn = AdvanceToNextVisualDnodeCore(pdn, lstflowMain, pptpen);
|
|
|
|
// skip submitting dnodes
|
|
|
|
while (pdn != NULL && FIsAcceptingDnode(pdn))
|
|
{
|
|
pdn = AdvanceToNextVisualDnodeCore(pdn, lstflowMain, pptpen);
|
|
}
|
|
|
|
return pdn;
|
|
}
|
|
|
|
// %%Function: AdvanceToFirstDnode
|
|
// %%Contact: victork
|
|
//
|
|
PLSDNODE AdvanceToFirstDnode(PLSSUBL plssubl, LSTFLOW lstflowMain, POINTUV* pptpen)
|
|
{
|
|
PLSDNODE pdn = plssubl->plsdnFirst;
|
|
|
|
if (pdn != NULL && FIsAcceptingDnode(pdn))
|
|
{
|
|
pdn = AdvanceToNextDnode(pdn, lstflowMain, pptpen);
|
|
}
|
|
|
|
return pdn;
|
|
}
|
|
|
|
|
|
// %%Function: AdvanceToNextSubmittingDnode
|
|
// %%Contact: victork
|
|
//
|
|
/*
|
|
* Advance to the next (visual) node and update pen position, stopping only at submitting dnodes.
|
|
*/
|
|
|
|
PLSDNODE AdvanceToNextSubmittingDnode(PLSDNODE pdn, LSTFLOW lstflowMain, POINTUV* pptpen)
|
|
{
|
|
// move to the next
|
|
|
|
pdn = AdvanceToNextVisualDnodeCore(pdn, lstflowMain, pptpen);
|
|
|
|
// skip non-submitting dnodes
|
|
|
|
while (pdn != NULL && !FIsAcceptingDnode(pdn))
|
|
{
|
|
pdn = AdvanceToNextVisualDnodeCore(pdn, lstflowMain, pptpen);
|
|
}
|
|
|
|
return pdn;
|
|
}
|
|
|
|
// %%Function: AdvanceToFirstSubmittingDnode
|
|
// %%Contact: victork
|
|
//
|
|
PLSDNODE AdvanceToFirstSubmittingDnode(PLSSUBL plssubl, LSTFLOW lstflowMain, POINTUV* pptpen)
|
|
{
|
|
PLSDNODE pdn = plssubl->plsdnFirst;
|
|
|
|
if (pdn != NULL && !FIsAcceptingDnode(pdn))
|
|
{
|
|
pdn = AdvanceToNextSubmittingDnode(pdn, lstflowMain, pptpen);
|
|
}
|
|
|
|
return pdn;
|
|
}
|
|
|
|
|
|
// %%Function: AdvanceToNextVisualDnodeCore
|
|
// %%Contact: victork
|
|
//
|
|
/*
|
|
* Advance to the next node and update pen position
|
|
* Goes into sublines, submitted for display, traversing the whole display tree.
|
|
* Stops at dnodes that submitted subline on the way down, skips them going up, so that
|
|
* every dnode is visited once with pen position at the start of it in visual order.
|
|
*/
|
|
|
|
static PLSDNODE AdvanceToNextVisualDnodeCore(PLSDNODE pdn, LSTFLOW lstflowMain, POINTUV* pptpen)
|
|
{
|
|
|
|
PLSDNODE pdnNextVisual, pdnTop;
|
|
PLSSUBL plssublCurrent;
|
|
long cSublines, i;
|
|
PLSSUBL* rgpsubl;
|
|
|
|
if (FIsAcceptingDnode(pdn))
|
|
{
|
|
|
|
// Last time we stopped at submitting dnode -
|
|
// now don't move pen point, go down to the VisualStart of the VisualFirst subline.
|
|
|
|
rgpsubl = pdn->u.real.pinfosubl->rgpsubl;
|
|
cSublines = pdn->u.real.pinfosubl->cSubline;
|
|
|
|
if (rgpsubl[0]->lstflow == lstflowMain)
|
|
{
|
|
pdnNextVisual = rgpsubl[0]->plsdnFirst;
|
|
}
|
|
else
|
|
{
|
|
pdnNextVisual = rgpsubl[cSublines - 1]->plsdnLastDisplay;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// update pen position - we always move to the (visual) right, all vs are the same tflow
|
|
|
|
if (pdn->klsdn == klsdnReal)
|
|
{
|
|
pptpen->u += pdn->u.real.dup;
|
|
}
|
|
else
|
|
{
|
|
pptpen->u += pdn->u.pen.dup;
|
|
pptpen->v += pdn->u.pen.dvp;
|
|
}
|
|
|
|
plssublCurrent = pdn->plssubl;
|
|
|
|
// go to the next dnode of the current subline in visual order
|
|
|
|
pdnNextVisual = NextVisualDnodeOnTheLevel(pdn, lstflowMain);
|
|
|
|
// If current subline is ended, (try) change subline.
|
|
|
|
if (pdnNextVisual == NULL)
|
|
{
|
|
// Change subline
|
|
//
|
|
// In the loop: pdnNextVisual != NULL signals that next dnode is successfully found.
|
|
// If pdnNextVisual == NULL, plssublCurrent is the subline just exhausted.
|
|
// One run of the loop replaces current subline with another subline on the same level
|
|
// (such change always ends the loop) or with parent subline.
|
|
|
|
while (pdnNextVisual == NULL && plssublCurrent->plsdnUpTemp != NULL)
|
|
{
|
|
|
|
// find (the index of) the current subline in the list of submitted sublines
|
|
|
|
pdnTop = plssublCurrent->plsdnUpTemp;
|
|
rgpsubl = pdnTop->u.real.pinfosubl->rgpsubl;
|
|
cSublines = pdnTop->u.real.pinfosubl->cSubline;
|
|
|
|
for (i=0; i < cSublines && plssublCurrent != rgpsubl[i]; i++);
|
|
|
|
Assert(i < cSublines);
|
|
|
|
// do we have "next" subline? If we do, pdnNextVisual we seek "starts" it.
|
|
|
|
if (pdnTop->plssubl->lstflow == lstflowMain)
|
|
{
|
|
i++;
|
|
if (i < cSublines)
|
|
{
|
|
plssublCurrent = rgpsubl[i];
|
|
pdnNextVisual = plssublCurrent->plsdnFirst;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
i--;
|
|
if (i >= 0)
|
|
{
|
|
plssublCurrent = rgpsubl[i];
|
|
pdnNextVisual = plssublCurrent->plsdnLastDisplay;
|
|
}
|
|
}
|
|
|
|
// We don't, let's try next dnode on the upper level.
|
|
|
|
if (pdnNextVisual == NULL)
|
|
{
|
|
plssublCurrent = pdnTop->plssubl;
|
|
pdnNextVisual = NextVisualDnodeOnTheLevel(pdnTop, lstflowMain);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return pdnNextVisual;
|
|
}
|
|
|
|
|
|
// %%Function: NextVisualDnodeOnTheLevel
|
|
// %%Contact: victork
|
|
//
|
|
// find next dnode on the level moving right or left, signalling end with a NULL
|
|
|
|
static PLSDNODE NextVisualDnodeOnTheLevel(PLSDNODE pdn, LSTFLOW lstflowMain)
|
|
{
|
|
if (pdn->plssubl->lstflow == lstflowMain)
|
|
{
|
|
if (pdn == pdn->plssubl->plsdnLastDisplay)
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
return pdn->plsdnNext;
|
|
}
|
|
}
|
|
return pdn->plsdnPrev;
|
|
}
|
|
|
|
|
|
// %%Function: AddSublineAdvanceWidth
|
|
// %%Contact: victork
|
|
//
|
|
// Note: It is not subline width as calculated in GetObjDimSubline
|
|
|
|
static long AddSublineAdvanceWidth(PLSSUBL plssubl)
|
|
{
|
|
long dupSum;
|
|
PLSDNODE pdn;
|
|
|
|
pdn = plssubl->plsdnFirst;
|
|
dupSum = 0;
|
|
|
|
while (pdn != NULL)
|
|
{
|
|
if (pdn->klsdn == klsdnReal)
|
|
{
|
|
dupSum += pdn->u.real.dup;
|
|
}
|
|
else /* pen, border */
|
|
{
|
|
dupSum += pdn->u.pen.dup;
|
|
}
|
|
|
|
if (pdn == plssubl->plsdnLastDisplay)
|
|
{
|
|
pdn = NULL;
|
|
}
|
|
else
|
|
{
|
|
pdn = pdn->plsdnNext;
|
|
Assert(pdn != NULL); // plsdnLastDisplay should prevent this
|
|
}
|
|
}
|
|
|
|
return dupSum;
|
|
}
|
|
|
|
|
|
// NB Victork - following functions were used only for upClipLeft, upClipRight optimization.
|
|
// If we'll decide that we do need that optimization after Word integration - I'll uncomment.
|
|
|
|
#ifdef NEVER
|
|
// %%Function: RectUVFromRectXY
|
|
// %%Contact: victork
|
|
//
|
|
// There is an assymetry in the definition of the rectangle.
|
|
// (Left, Top) belongs to rectangle and (Right, Bottom) doesn't,
|
|
// It makes following procedures hard to understand and write.
|
|
// So I first cut off the points that don't belong, then turn the rectangle, then add extra
|
|
// points again and hope compiler will make it fast.
|
|
|
|
// RectUVFromRectXY calculates (clip) rectangle in local (u,v) coordinates given
|
|
// (clip) rectangle in (x,y) and point of origin
|
|
|
|
void RectUVFromRectXY(const POINT* pptXY, /* IN: point of origin for local coordinates (x,y) */
|
|
const RECT* prectXY, /* IN: input rectangle (x,y) */
|
|
LSTFLOW lstflow, /* IN: local text flow */
|
|
RECTUV* prectUV) /* OUT: output rectangle (u,v) */
|
|
{
|
|
switch (lstflow)
|
|
{
|
|
case lstflowES: /* latin */
|
|
prectUV->upLeft = (prectXY->left - pptXY->x);
|
|
prectUV->upRight = (prectXY->right - 1 - pptXY->x) + 1;
|
|
prectUV->vpTop = -(prectXY->top - pptXY->y);
|
|
prectUV->vpBottom = -(prectXY->bottom - 1 - pptXY->y) - 1;
|
|
return;
|
|
|
|
case lstflowSW: /* vertical FE */
|
|
prectUV->upLeft = (prectXY->top - pptXY->y);
|
|
prectUV->upRight = (prectXY->bottom - 1 - pptXY->y) + 1;
|
|
prectUV->vpTop = (prectXY->right - 1 - pptXY->x);
|
|
prectUV->vpBottom = (prectXY->left - pptXY->x) - 1;
|
|
return;
|
|
|
|
case lstflowWS: /* BiDi */
|
|
prectUV->upLeft = -(prectXY->right - 1 - pptXY->x);
|
|
prectUV->upRight = -(prectXY->left - pptXY->x) + 1;
|
|
prectUV->vpTop = -(prectXY->top - pptXY->y);
|
|
prectUV->vpBottom = -(prectXY->bottom - 1 - pptXY->y) - 1;
|
|
return;
|
|
|
|
case lstflowEN:
|
|
prectUV->upLeft = (prectXY->left - pptXY->x);
|
|
prectUV->upRight = (prectXY->right - 1 - pptXY->x) + 1;
|
|
prectUV->vpTop = (prectXY->bottom - 1 - pptXY->y);
|
|
prectUV->vpBottom = (prectXY->top - pptXY->y) - 1;
|
|
return;
|
|
|
|
case lstflowSE:
|
|
prectUV->upLeft = (prectXY->top - pptXY->y);
|
|
prectUV->upRight = (prectXY->bottom - 1 - pptXY->y) + 1;
|
|
prectUV->vpTop = -(prectXY->left - pptXY->x);
|
|
prectUV->vpBottom = -(prectXY->right - 1 - pptXY->x) - 1;
|
|
return;
|
|
|
|
case lstflowWN:
|
|
prectUV->upLeft = -(prectXY->right - 1 - pptXY->x);
|
|
prectUV->upRight = -(prectXY->left - pptXY->x) + 1;
|
|
prectUV->vpTop = (prectXY->bottom - 1 - pptXY->y);
|
|
prectUV->vpBottom = (prectXY->top - pptXY->y) - 1;
|
|
return;
|
|
|
|
case lstflowNE:
|
|
prectUV->upLeft = -(prectXY->bottom - 1 - pptXY->y);
|
|
prectUV->upRight = -(prectXY->top - pptXY->y) + 1;
|
|
prectUV->vpTop = -(prectXY->left - pptXY->x);
|
|
prectUV->vpBottom = -(prectXY->right - 1 - pptXY->x) - 1;
|
|
return;
|
|
|
|
case lstflowNW:
|
|
prectUV->upLeft = -(prectXY->bottom - 1 - pptXY->y);
|
|
prectUV->upRight = -(prectXY->top - pptXY->y) + 1;
|
|
prectUV->vpTop = (prectXY->right - 1 - pptXY->x);
|
|
prectUV->vpBottom = (prectXY->left - pptXY->x) - 1;
|
|
return;
|
|
default:
|
|
NotReached();
|
|
}
|
|
}
|
|
|
|
|
|
// %%Function: RectXYFromRectUV
|
|
// %%Contact: victork
|
|
//
|
|
// RectXYFromRectUV calculates rectangle in (x,y) coordinates given rectangle in local (u,v)
|
|
// and point of origin (x,y) for local coordinate system
|
|
|
|
|
|
void RectXYFromRectUV(const POINT* pptXY, /* IN: point of origin for local coordinates (x,y) */
|
|
PCRECTUV prectUV, /* IN: input rectangle (u,v) */
|
|
LSTFLOW lstflow, /* IN: local text flow */
|
|
RECT* prectXY) /* OUT: output rectangle (x,y) */
|
|
{
|
|
switch (lstflow)
|
|
{
|
|
case lstflowES: /* latin */
|
|
prectXY->left = pptXY->x + prectUV->upLeft;
|
|
prectXY->right = pptXY->x + (prectUV->upRight - 1) + 1;
|
|
prectXY->top = pptXY->y - (prectUV->vpTop);
|
|
prectXY->bottom = pptXY->y - (prectUV->vpBottom + 1) + 1;
|
|
return;
|
|
|
|
case lstflowSW: /* vertical FE */
|
|
prectXY->left = pptXY->x + (prectUV->vpBottom + 1);
|
|
prectXY->right = pptXY->x + (prectUV->vpTop) + 1;
|
|
prectXY->top = pptXY->y + prectUV->upLeft;
|
|
prectXY->bottom = pptXY->y + (prectUV->upRight - 1) + 1;
|
|
return;
|
|
|
|
case lstflowWS: /* BiDi */
|
|
prectXY->left = pptXY->x - (prectUV->upRight - 1);
|
|
prectXY->right = pptXY->x - prectUV->upLeft + 1;
|
|
prectXY->top = pptXY->y - (prectUV->vpTop);
|
|
prectXY->bottom = pptXY->y - (prectUV->vpBottom + 1) + 1;
|
|
return;
|
|
|
|
case lstflowEN:
|
|
prectXY->left = pptXY->x + prectUV->upLeft;
|
|
prectXY->right = pptXY->x + (prectUV->upRight - 1) + 1;
|
|
prectXY->top = pptXY->y + (prectUV->vpBottom + 1);
|
|
prectXY->bottom = pptXY->y + (prectUV->vpTop) + 1;
|
|
return;
|
|
|
|
case lstflowSE:
|
|
prectXY->left = pptXY->x - (prectUV->vpTop);
|
|
prectXY->right = pptXY->x - (prectUV->vpBottom + 1) + 1;
|
|
prectXY->top = pptXY->y + prectUV->upLeft;
|
|
prectXY->bottom = pptXY->y + (prectUV->upRight - 1) + 1;
|
|
return;
|
|
|
|
case lstflowWN:
|
|
prectXY->left = pptXY->x - (prectUV->upRight - 1);
|
|
prectXY->right = pptXY->x - prectUV->upLeft + 1;
|
|
prectXY->top = pptXY->y + (prectUV->vpBottom + 1);
|
|
prectXY->bottom = pptXY->y + (prectUV->vpTop) + 1;
|
|
return;
|
|
|
|
case lstflowNE:
|
|
prectXY->left = pptXY->x - (prectUV->vpTop);
|
|
prectXY->right = pptXY->x - (prectUV->vpBottom + 1) + 1;
|
|
prectXY->top = pptXY->y - (prectUV->upRight - 1);
|
|
prectXY->bottom = pptXY->y - prectUV->upLeft + 1;
|
|
return;
|
|
|
|
case lstflowNW:
|
|
prectXY->left = pptXY->x + (prectUV->vpBottom + 1);
|
|
prectXY->right = pptXY->x + (prectUV->vpTop) + 1;
|
|
prectXY->top = pptXY->y - (prectUV->upRight - 1);
|
|
prectXY->bottom = pptXY->y - prectUV->upLeft + 1;
|
|
return;
|
|
|
|
default:
|
|
NotReached();
|
|
}
|
|
}
|
|
#endif /* NEVER */
|