You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
634 lines
18 KiB
634 lines
18 KiB
#include "lsqcore.h"
|
|
#include "lsc.h"
|
|
#include "lsqsinfo.h"
|
|
#include "lsdnode.h"
|
|
#include "lssubl.h"
|
|
#include "heights.h"
|
|
#include "lschp.h"
|
|
#include "iobj.h"
|
|
#include "lsqin.h"
|
|
#include "lsqout.h"
|
|
#include "dninfo.h"
|
|
#include "lssubset.h"
|
|
#include "lstfset.h"
|
|
#include "dispmisc.h"
|
|
|
|
|
|
#define FIsInContent(pdn) (!FIsNotInContent(pdn))
|
|
#define FIsZeroWidth(pdn) (FIsDnodeReal(pdn) && (pdn)->u.real.dup == 0)
|
|
#define FIsDnodeClosingBorder(pdn) (FIsDnodeBorder(pdn) && (!(pdn)->fOpenBorder))
|
|
|
|
|
|
static void PrepareQueryCall(PLSSUBL, PLSDNODE, LSQIN*);
|
|
static LSERR FillInQueryResults(PLSC, PLSSUBL, PLSQSUBINFO, PLSDNODE, POINTUV*, LSQOUT*);
|
|
static void FillInTextCellInfo(PLSC, PLSDNODE, POINTUV*, LSQOUT*, PLSTEXTCELL);
|
|
static void TransformPointsOnLowerLevels(PLSQSUBINFO, DWORD, PLSTEXTCELL, PPOINTUV, LSTFLOW, LSTFLOW);
|
|
static void ApplyFormula(PPOINTUV, DWORD[], PPOINTUV);
|
|
|
|
static PLSDNODE BacktrackToPreviousDnode(PLSDNODE pdn, POINTUV* pt);
|
|
static PLSDNODE AdvanceToNextDnodeQuery(PLSDNODE, PPOINTUV);
|
|
|
|
|
|
// %%Function: QuerySublineCpPpointCore
|
|
// %%Contact: victork
|
|
//
|
|
/*
|
|
* Returns dim-info of the cp in the subline.
|
|
*
|
|
* If that cp isn't displayed in the line, take closest to the left that is displayed.
|
|
* If that's impossible, go to the right.
|
|
*
|
|
* Hidden text inside ligature makes it impossible to tell whether a particular cp is hidden or not
|
|
*/
|
|
|
|
LSERR QuerySublineCpPpointCore(
|
|
PLSSUBL plssubl,
|
|
LSCP cp, /* IN: cpQuery */
|
|
DWORD cDepthQueryMax, /* IN: allocated size of results array */
|
|
PLSQSUBINFO plsqsubinfoResults, /* OUT: array[cDepthQueryMax] of results */
|
|
DWORD* pcActualDepth, /* OUT: size of results array (filled) */
|
|
PLSTEXTCELL plstextcell) /* OUT: Text cell info */
|
|
|
|
|
|
{
|
|
PLSC plsc;
|
|
LSERR lserr = lserrNone;
|
|
PLSDNODE pdn, pdnPrev = NULL;
|
|
POINTUV pt;
|
|
LSCP cpLim;
|
|
|
|
LSQIN lsqin;
|
|
LSQOUT lsqout;
|
|
|
|
PLSSUBL plssublLowerLevels;
|
|
POINTUV ptStartLowerLevels;
|
|
PLSQSUBINFO plsqsubinfoLowerLevels;
|
|
DWORD cDepthQueryMaxLowerLevels;
|
|
DWORD cActualDepthLowerLevels;
|
|
|
|
Assert(FIsLSSUBL(plssubl));
|
|
Assert(!plssubl->fDupInvalid);
|
|
|
|
if (cDepthQueryMax == 0)
|
|
{
|
|
return lserrInsufficientQueryDepth;
|
|
}
|
|
|
|
plsc = plssubl->plsc;
|
|
cpLim = plssubl->cpLimDisplay;
|
|
|
|
pt.u = 0;
|
|
pt.v = 0;
|
|
pdn = plssubl->plsdnFirst;
|
|
|
|
/* Skip over autonumbers & starting pens/borders */
|
|
while (FDnodeBeforeCpLim(pdn, cpLim) && (FIsNotInContent(pdn) || !(FIsDnodeReal(pdn))))
|
|
{
|
|
pdn = AdvanceToNextDnodeQuery(pdn, &pt);
|
|
}
|
|
|
|
if (!FDnodeBeforeCpLim(pdn, cpLim))
|
|
{ /* empty subline */
|
|
*pcActualDepth = 0;
|
|
return lserrNone;
|
|
}
|
|
|
|
// if cp <= pdn->cpFirst, pdn is the dnode to query, else...
|
|
|
|
if (cp > pdn->cpFirst)
|
|
{
|
|
/* Skip dnodes before the cp */
|
|
while (FDnodeBeforeCpLim(pdn, cpLim) && pdn->cpFirst + pdn->dcp <= (LSDCP)cp)
|
|
{
|
|
pdnPrev = pdn;
|
|
pdn = AdvanceToNextDnodeQuery(pdn, &pt);
|
|
}
|
|
|
|
/* go back if our cp is in vanished text or pen or border */
|
|
if (!FDnodeBeforeCpLim(pdn, cpLim) || // reached the end
|
|
pdn->cpFirst > cp || // went too far because of hidden text
|
|
!(FIsDnodeReal(pdn))) // our cp points to a pen
|
|
{
|
|
Assert(pdnPrev != NULL); // we made at least one forward step
|
|
pdn = pdnPrev;
|
|
pdnPrev = BacktrackToPreviousDnode(pdnPrev, &pt);
|
|
|
|
// skip all pens/borders
|
|
while (pdn != NULL && FIsInContent(pdn) && !(FIsDnodeReal(pdn)))
|
|
{
|
|
pdn = pdnPrev;
|
|
pdnPrev = BacktrackToPreviousDnode(pdnPrev, &pt);
|
|
}
|
|
|
|
// nothing good to the left situation is impossible
|
|
Assert(pdn != NULL && !FIsNotInContent(pdn));
|
|
}
|
|
}
|
|
|
|
/* we've found the dnode, have pt just before it, ask method for details */
|
|
|
|
if (cp >= (LSCP) (pdn->cpFirst + pdn->dcp)) /* cp in next vanished piece */
|
|
cp = pdn->cpFirst + pdn->dcp - 1; /* query last cp */
|
|
|
|
if (cp < (LSCP) pdn->cpFirst) /* cp in a previous pen */
|
|
cp = pdn->cpFirst; /* query first cp */
|
|
|
|
pt.v += pdn->u.real.lschp.dvpPos; // go to the local baseline
|
|
|
|
PrepareQueryCall(plssubl, pdn, &lsqin);
|
|
|
|
lserr = (*plsc->lsiobjcontext.rgobj[pdn->u.real.lschp.idObj].lsim.pfnQueryCpPpoint)
|
|
(pdn->u.real.pdobj, cp - pdn->cpFirst, &lsqin, &lsqout);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
lserr = FillInQueryResults(plsc, plssubl, plsqsubinfoResults, pdn, &pt, &lsqout);
|
|
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
if (lsqout.plssubl == NULL) // terminal object
|
|
{
|
|
*pcActualDepth = 1;
|
|
|
|
FillInTextCellInfo(plsc, pdn, &pt, &lsqout, plstextcell);
|
|
}
|
|
else // there are more level(s)
|
|
{
|
|
// recursive call to fill lower levels
|
|
plssublLowerLevels = lsqout.plssubl;
|
|
plsqsubinfoLowerLevels = plsqsubinfoResults + 1;
|
|
cDepthQueryMaxLowerLevels = cDepthQueryMax - 1;
|
|
|
|
lserr = QuerySublineCpPpointCore(plssublLowerLevels, cp, cDepthQueryMaxLowerLevels,
|
|
plsqsubinfoLowerLevels, &cActualDepthLowerLevels, plstextcell);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
*pcActualDepth = cActualDepthLowerLevels + 1;
|
|
|
|
ptStartLowerLevels.u = pt.u + lsqout.pointUvStartSubline.u;
|
|
ptStartLowerLevels.v = pt.v + lsqout.pointUvStartSubline.v;
|
|
|
|
TransformPointsOnLowerLevels(plsqsubinfoLowerLevels, cActualDepthLowerLevels, plstextcell,
|
|
&ptStartLowerLevels, plssubl->lstflow, plssublLowerLevels->lstflow);
|
|
}
|
|
|
|
return lserrNone;
|
|
}
|
|
|
|
|
|
// %%Function: QuerySublinePointPcpCore
|
|
// %%Contact: victork
|
|
//
|
|
/*
|
|
* Returns dim-info of the cp in the line, that a) contains given point or
|
|
* b) is closest to it from the left or
|
|
* c) is just closest to it
|
|
*/
|
|
|
|
LSERR QuerySublinePointPcpCore(
|
|
PLSSUBL plssubl,
|
|
PCPOINTUV pptIn,
|
|
DWORD cDepthQueryMax, /* IN: allocated size of results array */
|
|
PLSQSUBINFO plsqsubinfoResults, /* OUT: array[cDepthQueryMax] of results */
|
|
DWORD* pcActualDepth, /* OUT: size of results array (filled) */
|
|
PLSTEXTCELL plstextcell) /* OUT: Text cell info */
|
|
{
|
|
PLSC plsc;
|
|
LSERR lserr = lserrNone;
|
|
PLSDNODE pdn, pdnPrev = NULL;
|
|
POINTUV pt, ptInside, ptInsideLocal;
|
|
LSCP cpLim;
|
|
|
|
LSQIN lsqin;
|
|
LSQOUT lsqout;
|
|
|
|
PLSSUBL plssublLowerLevels;
|
|
POINTUV ptStartLowerLevels;
|
|
PLSQSUBINFO plsqsubinfoLowerLevels;
|
|
DWORD cDepthQueryMaxLowerLevels;
|
|
DWORD cActualDepthLowerLevels;
|
|
long upQuery;
|
|
|
|
Assert(FIsLSSUBL(plssubl));
|
|
Assert(!plssubl->fDupInvalid);
|
|
|
|
if (cDepthQueryMax == 0)
|
|
{
|
|
return lserrInsufficientQueryDepth;
|
|
}
|
|
|
|
plsc = plssubl->plsc;
|
|
cpLim = plssubl->cpLimDisplay;
|
|
|
|
pt.u = 0;
|
|
pt.v = 0;
|
|
pdn = plssubl->plsdnFirst;
|
|
|
|
/* Skip over autonumbers & starting pens & empty dnodes */
|
|
while (FDnodeBeforeCpLim(pdn, cpLim) && (FIsNotInContent(pdn) || !(FIsDnodeReal(pdn)) || FIsZeroWidth(pdn)))
|
|
{
|
|
pdn = AdvanceToNextDnodeQuery(pdn, &pt);
|
|
}
|
|
|
|
if (!FDnodeBeforeCpLim(pdn, cpLim))
|
|
{ /* empty subline */
|
|
*pcActualDepth = 0;
|
|
return lserrNone;
|
|
}
|
|
|
|
upQuery = pptIn->u;
|
|
|
|
/*
|
|
* Find dnode with our point inside.
|
|
*
|
|
* We look only at upQuery to do it.
|
|
*/
|
|
|
|
// if pt.u >= upQuery, pdn is the dnode to query, else...
|
|
|
|
if (pt.u <= upQuery)
|
|
{
|
|
// skip until the end or dnode to the right of our point
|
|
// (That means extra work, but covers zero dup situation without additional if.)
|
|
|
|
while (FDnodeBeforeCpLim(pdn, cpLim) && pt.u <= upQuery)
|
|
{
|
|
pdnPrev = pdn;
|
|
pdn = AdvanceToNextDnodeQuery(pdn, &pt);
|
|
}
|
|
|
|
if (FIsDnodeBorder(pdnPrev))
|
|
{
|
|
if (pdnPrev->fOpenBorder)
|
|
{
|
|
// upQuery was in the previous opening border - pdn is the dnode we need
|
|
|
|
Assert(FDnodeBeforeCpLim(pdn, cpLim));
|
|
}
|
|
else
|
|
{
|
|
// upQuery was in the previous closing border - dnode we need is before the border
|
|
|
|
pdn = pdnPrev;
|
|
Assert(pdn != NULL && !FIsNotInContent(pdn));
|
|
|
|
pdnPrev = BacktrackToPreviousDnode(pdnPrev, &pt);
|
|
|
|
pdn = pdnPrev;
|
|
Assert(pdn != NULL && !FIsNotInContent(pdn));
|
|
|
|
pdnPrev = BacktrackToPreviousDnode(pdnPrev, &pt);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* go back to the previous dnode */
|
|
|
|
pdn = pdnPrev;
|
|
pdnPrev = BacktrackToPreviousDnode(pdnPrev, &pt);
|
|
|
|
// if it is a pen/border or empty dnode (non-req hyphen), skip them all
|
|
// (Border cannot be the previous dnode, but is possble later)
|
|
|
|
while (pdn != NULL && (!(FIsDnodeReal(pdn)) || FIsZeroWidth(pdn)))
|
|
{
|
|
pdn = pdnPrev;
|
|
pdnPrev = BacktrackToPreviousDnode(pdnPrev, &pt);
|
|
}
|
|
|
|
// "nothing good to the left" situation is impossible
|
|
Assert(pdn != NULL && !FIsNotInContent(pdn));
|
|
}
|
|
}
|
|
|
|
// We have found the leftmost dnode with our dup to the right of it
|
|
// pt is just before it, ask method for details
|
|
|
|
pt.v += pdn->u.real.lschp.dvpPos; // go to the local baseline
|
|
|
|
PrepareQueryCall(plssubl, pdn, &lsqin);
|
|
|
|
// get query point relative to the starting point of the dnode
|
|
// we give no guarantee that it is really inside dnode box
|
|
ptInside.u = pptIn->u - pt.u;
|
|
ptInside.v = pptIn->v - pt.v;
|
|
|
|
lserr = (*plsc->lsiobjcontext.rgobj[pdn->u.real.lschp.idObj].lsim.pfnQueryPointPcp)
|
|
(pdn->u.real.pdobj, &ptInside, &lsqin, &lsqout);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
lserr = FillInQueryResults(plsc, plssubl, plsqsubinfoResults, pdn, &pt, &lsqout);
|
|
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
if (lsqout.plssubl == NULL) // terminal object
|
|
{
|
|
*pcActualDepth = 1;
|
|
|
|
FillInTextCellInfo(plsc, pdn, &pt, &lsqout, plstextcell);
|
|
}
|
|
else // there are more level(s)
|
|
{
|
|
// recursive call to fill lower levels
|
|
plssublLowerLevels = lsqout.plssubl;
|
|
plsqsubinfoLowerLevels = plsqsubinfoResults + 1;
|
|
cDepthQueryMaxLowerLevels = cDepthQueryMax - 1;
|
|
|
|
// get query point in lower level subline coordinate system
|
|
|
|
lserr = LsPointUV2FromPointUV1(plssubl->lstflow, &(lsqout.pointUvStartSubline), &ptInside, /* IN: end input point (TF1) */
|
|
plssublLowerLevels->lstflow, &ptInsideLocal);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
lserr = QuerySublinePointPcpCore(plssublLowerLevels, &ptInsideLocal, cDepthQueryMaxLowerLevels,
|
|
plsqsubinfoLowerLevels, &cActualDepthLowerLevels, plstextcell);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
*pcActualDepth = cActualDepthLowerLevels + 1;
|
|
|
|
ptStartLowerLevels.u = pt.u + lsqout.pointUvStartSubline.u;
|
|
ptStartLowerLevels.v = pt.v + lsqout.pointUvStartSubline.v;
|
|
|
|
TransformPointsOnLowerLevels(plsqsubinfoLowerLevels, cActualDepthLowerLevels, plstextcell,
|
|
&ptStartLowerLevels, plssubl->lstflow, plssublLowerLevels->lstflow);
|
|
}
|
|
|
|
return lserrNone;
|
|
}
|
|
|
|
|
|
// %%Function: PrepareQueryCall
|
|
// %%Contact: victork
|
|
//
|
|
static void PrepareQueryCall(PLSSUBL plssubl, PLSDNODE pdn, LSQIN* plsqin)
|
|
{
|
|
plsqin->lstflowSubline = plssubl->lstflow;
|
|
plsqin->plsrun = pdn->u.real.plsrun;
|
|
plsqin->cpFirstRun = pdn->cpFirst;
|
|
plsqin->dcpRun = pdn->dcp;
|
|
plsqin->heightsPresRun = pdn->u.real.objdim.heightsPres;
|
|
plsqin->dupRun = pdn->u.real.dup;
|
|
plsqin->dvpPosRun = pdn->u.real.lschp.dvpPos;
|
|
}
|
|
|
|
|
|
// %%Function: FillInQueryResults
|
|
// %%Contact: victork
|
|
//
|
|
static LSERR FillInQueryResults(
|
|
PLSC plsc,
|
|
PLSSUBL plssubl,
|
|
PLSQSUBINFO plsqsubinfoResults,
|
|
PLSDNODE pdn,
|
|
POINTUV* ppt,
|
|
LSQOUT* plsqout
|
|
)
|
|
{
|
|
OBJDIM objdimSubline;
|
|
LSERR lserr;
|
|
PLSDNODE pdnNext, pdnPrev;
|
|
|
|
// fill in subline info
|
|
|
|
lserr = LssbGetObjDimSubline(plssubl, &(plsqsubinfoResults->lstflowSubline), &objdimSubline);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
lserr = LssbGetDupSubline(plssubl, &(plsqsubinfoResults->lstflowSubline), &plsqsubinfoResults->dupSubline);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
plsqsubinfoResults->cpFirstSubline = plssubl->cpFirst;
|
|
plsqsubinfoResults->dcpSubline = plssubl->cpLimDisplay - plssubl->cpFirst;
|
|
plsqsubinfoResults->pointUvStartSubline.u = 0;
|
|
plsqsubinfoResults->pointUvStartSubline.v = 0;
|
|
|
|
plsqsubinfoResults->heightsPresSubline = objdimSubline.heightsPres;
|
|
|
|
// fill in dnode info
|
|
|
|
if (IdObjFromDnode(pdn) == IobjTextFromLsc(&(plsc->lsiobjcontext)))
|
|
plsqsubinfoResults->idobj = idObjText;
|
|
else
|
|
plsqsubinfoResults->idobj = pdn->u.real.lschp.idObj;
|
|
|
|
plsqsubinfoResults->plsrun = pdn->u.real.plsrun;
|
|
plsqsubinfoResults->cpFirstRun = pdn->cpFirst;
|
|
plsqsubinfoResults->dcpRun = pdn->dcp;
|
|
plsqsubinfoResults->pointUvStartRun = *ppt; // local baseline
|
|
plsqsubinfoResults->heightsPresRun = pdn->u.real.objdim.heightsPres;
|
|
plsqsubinfoResults->dupRun = pdn->u.real.dup;
|
|
plsqsubinfoResults->dvpPosRun = pdn->u.real.lschp.dvpPos;
|
|
|
|
// fill in object info
|
|
|
|
plsqsubinfoResults->pointUvStartObj.u = ppt->u + plsqout->pointUvStartObj.u;
|
|
plsqsubinfoResults->pointUvStartObj.v = ppt->v + plsqout->pointUvStartObj.v;
|
|
plsqsubinfoResults->heightsPresObj = plsqout->heightsPresObj;
|
|
plsqsubinfoResults->dupObj = plsqout->dupObj;
|
|
|
|
// add borders info
|
|
|
|
plsqsubinfoResults->dupBorderAfter = 0;
|
|
plsqsubinfoResults->dupBorderBefore = 0;
|
|
|
|
if (pdn->u.real.lschp.fBorder)
|
|
{
|
|
pdnNext = pdn->plsdnNext;
|
|
|
|
if (pdnNext != NULL && FIsDnodeClosingBorder(pdnNext))
|
|
{
|
|
plsqsubinfoResults->dupBorderAfter = pdnNext->u.pen.dup;
|
|
}
|
|
|
|
pdnPrev = pdn->plsdnPrev;
|
|
|
|
if (pdnPrev != NULL && FIsDnodeOpenBorder(pdnPrev))
|
|
{
|
|
Assert(FIsInContent(pdnPrev));
|
|
|
|
plsqsubinfoResults->dupBorderBefore = pdnPrev->u.pen.dup;
|
|
}
|
|
}
|
|
|
|
return lserrNone;
|
|
}
|
|
|
|
|
|
// %%Function: FillInTextCellInfo
|
|
// %%Contact: victork
|
|
//
|
|
static void FillInTextCellInfo(
|
|
PLSC plsc,
|
|
PLSDNODE pdn,
|
|
POINTUV* ppt,
|
|
LSQOUT* plsqout,
|
|
PLSTEXTCELL plstextcell /* OUT: Text cell info */
|
|
)
|
|
{
|
|
if (IdObjFromDnode(pdn) == IobjTextFromLsc(&(plsc->lsiobjcontext)))
|
|
{
|
|
// text has cell info filled - copy it
|
|
|
|
*plstextcell = plsqout->lstextcell;
|
|
|
|
// but starting point is relative to the begining of dnode - adjust to that of subline
|
|
|
|
plstextcell->pointUvStartCell.u += ppt->u;
|
|
plstextcell->pointUvStartCell.v += ppt->v;
|
|
|
|
// adjust cpEndCell if some hidden text got into last ligature - text is unaware of the issue
|
|
|
|
if (pdn->cpFirst + pdn->dcp < (LSDCP) pdn->cpLimOriginal &&
|
|
(LSDCP) plstextcell->cpEndCell == pdn->cpFirst + pdn->dcp - 1)
|
|
{
|
|
plstextcell->cpEndCell = pdn->cpLimOriginal - 1;
|
|
}
|
|
|
|
// pointer to the dnode to get details quickly - only query manager knows what PCELLDETAILS is
|
|
|
|
plstextcell->pCellDetails = (PCELLDETAILS)pdn;
|
|
}
|
|
else
|
|
{
|
|
// non-text object should not fill lstxtcell, client should not look into it
|
|
// I fill it with object information for debug purposes
|
|
// Consider zapping it in lsqline later (Rick's suggestion)
|
|
|
|
plstextcell->cpStartCell = pdn->cpFirst;
|
|
plstextcell->cpEndCell = pdn->cpFirst + pdn->dcp - 1;
|
|
plstextcell->pointUvStartCell = *ppt;
|
|
plstextcell->dupCell = pdn->u.real.dup;
|
|
plstextcell->cCharsInCell = 0;
|
|
plstextcell->cGlyphsInCell = 0;
|
|
plstextcell->pCellDetails = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// %%Function: TransformPointsOnLowerLevels
|
|
// %%Contact: victork
|
|
//
|
|
// transform all vectors in results array from lstflow2 to lstflow1, adding pointuvStart (lstflow1)
|
|
|
|
static void TransformPointsOnLowerLevels(
|
|
PLSQSUBINFO plsqsubinfo, /* IN/OUT: results array */
|
|
DWORD cDepth, /* IN: size of results array */
|
|
PLSTEXTCELL plstextcell, // IN/OUT: text cell
|
|
PPOINTUV ppointuvStart, // IN: in lstflow1
|
|
LSTFLOW lstflow1, // IN: lstflow1
|
|
LSTFLOW lstflow2) // IN: lstflow2
|
|
|
|
{
|
|
// Have to apply formulas
|
|
// VectorOut.u = k11 * VectorIn.u + k12 * VectorIn.v + pointuvStart.u
|
|
// VectorOut.v = k21 * VectorIn.u + k22 * VectorIn.v + pointuvStart.u
|
|
// to several vectors in results array (all elements in k matrix are zero or +/- 1)
|
|
// Algorithm: find the matrix first, then use it
|
|
|
|
DWORD k[4];
|
|
POINTUV pointuv0, pointuv1, pointuv2;
|
|
|
|
pointuv0.u = 0;
|
|
pointuv0.v = 0;
|
|
|
|
pointuv1.u = 1;
|
|
pointuv1.v = 0;
|
|
|
|
LsPointUV2FromPointUV1(lstflow2, &pointuv0, &pointuv1, lstflow1, &pointuv2);
|
|
|
|
k[0] = pointuv2.u; // k11
|
|
k[1] = pointuv2.v; // k21
|
|
|
|
pointuv1.u = 0;
|
|
pointuv1.v = 1;
|
|
|
|
LsPointUV2FromPointUV1(lstflow2, &pointuv0, &pointuv1, lstflow1, &pointuv2);
|
|
|
|
k[2] = pointuv2.u; // k12
|
|
k[3] = pointuv2.v; // k22
|
|
|
|
|
|
// all points in lower levels are in lstflowLowerLevels (lstflow2) with starting point at the
|
|
// beginning of the top lower levels subline
|
|
// Translate them to lstflowTop (lstflow1) and starting point of our subline.
|
|
|
|
while (cDepth > 0)
|
|
{
|
|
ApplyFormula(&(plsqsubinfo->pointUvStartSubline), k, ppointuvStart);
|
|
ApplyFormula(&(plsqsubinfo->pointUvStartRun), k, ppointuvStart);
|
|
ApplyFormula(&(plsqsubinfo->pointUvStartObj), k, ppointuvStart);
|
|
plsqsubinfo++;
|
|
cDepth--;
|
|
}
|
|
|
|
// StartCell point should be adjusted too
|
|
ApplyFormula(&(plstextcell->pointUvStartCell), k, ppointuvStart);
|
|
|
|
}
|
|
|
|
// %%Function: ApplyFormula
|
|
// %%Contact: victork
|
|
//
|
|
static void ApplyFormula(PPOINTUV ppointuv, DWORD* rgk, PPOINTUV ppointuvStart)
|
|
{
|
|
POINTUV pointuvTemp;
|
|
|
|
pointuvTemp.u = ppointuvStart->u + rgk[0] * ppointuv->u + rgk[2] * ppointuv->v;
|
|
pointuvTemp.v = ppointuvStart->v + rgk[1] * ppointuv->u + rgk[3] * ppointuv->v;
|
|
*ppointuv = pointuvTemp;
|
|
}
|
|
|
|
// %%Function: AdvanceToNextDnodeQuery
|
|
// %%Contact: victork
|
|
//
|
|
/*
|
|
* Advance to the next node and update pen position (never goes into sublines)
|
|
*/
|
|
|
|
static PLSDNODE AdvanceToNextDnodeQuery(PLSDNODE pdn, POINTUV* ppt)
|
|
{
|
|
|
|
if (pdn->klsdn == klsdnReal)
|
|
{
|
|
ppt->u += pdn->u.real.dup;
|
|
}
|
|
else /* case klsdnPen */
|
|
{
|
|
ppt->u += pdn->u.pen.dup;
|
|
ppt->v += pdn->u.pen.dvp;
|
|
}
|
|
|
|
return pdn->plsdnNext;
|
|
}
|
|
|
|
// %%Function: BacktrackToPreviousDnode
|
|
// %%Contact: victork
|
|
//
|
|
// Backtrack and downdate pen position.
|
|
// Both parameters are input/output
|
|
// Input: dnode number N-1 and point at the beginning of the dnode number N
|
|
// Output: point at the beginning of the dnode number N-1
|
|
// Return: dnode number N-2
|
|
|
|
static PLSDNODE BacktrackToPreviousDnode(PLSDNODE pdn, POINTUV* ppt)
|
|
{
|
|
|
|
if (FIsDnodeReal(pdn))
|
|
{
|
|
ppt->u -= pdn->u.real.dup;
|
|
}
|
|
else /* it's Pen */
|
|
{
|
|
ppt->u -= pdn->u.pen.dup;
|
|
ppt->v -= pdn->u.pen.dvp;
|
|
}
|
|
|
|
return pdn->plsdnPrev;
|
|
}
|