WindowsXP-SP1/windows/richedit/lssrc/chnutils.c
2020-09-30 16:53:49 +02:00

2256 lines
73 KiB
C

#include "lsmem.h" /* memset() */
#include "lsidefs.h"
#include "chnutils.h"
#include "iobj.h"
#include "dninfo.h"
#include "locchnk.h"
#include "posichnk.h"
#include "plschcon.h"
#include "lschcon.h"
#include "lscbk.h"
#include "limqmem.h"
#include "lstext.h"
#ifdef DEBUG
#define DebugMemset(a,b,c) if ((a) != NULL) memset(a,b,c); else
#else
#define DebugMemset(a,b,c) (void)(0)
#endif
static LSERR SetChunkArraysSize(PLSCHUNKCONTEXT, DWORD);
static LSERR IncreaseChunkArrays(PLSCHUNKCONTEXT);
static LSERR IncreaseGroupChunkNonTextArrays(PLSCHUNKCONTEXT plschunkcontext);
static LSERR ConvertChunkToGroupChunk(GRCHUNKEXT*, LSCP);
static void LocateChunk(PLSCHUNKCONTEXT plschnukcontext,/* IN: LS chunk context */
PLSDNODE plsdn, /* IN: dnode to collect chunk arround */
LSTFLOW lstflow, /* IN: text flow */
POINTUV* ppoint); /* IN: position of dnode */
static LSERR FExpandBeforeNonTextObject(GRCHUNKEXT* pgrchunkext, DWORD cTextBeforePrevioustNonText,
BOOL* pfExpand);
static LSERR FExpandAfterNonTextObject(GRCHUNKEXT* pgrchunkext, DWORD cTextBeforeLastNonText,
BOOL* pfExpand);
typedef struct groupchunkiterator
{
COLLECTSUBLINES Purpose; /* what sublines to take from a complex object */
PLSDNODE plsdnFirst; /* dnode from which we started collecting */
PLSDNODE plsdnStart; /* dnode where to start search for next, if NULL then
use plsdnFirst as first opportunity */
LSCP cpLim; /* boundary for group chunk if we go forward */
BOOL fForward; /* direction of traversing is forward otherwise it's backward*/
}
GROUPCHUNKITERATOR;
static void CreateGroupChunkIterator(
GROUPCHUNKITERATOR* pgroupchunkiterator, /* handler for iterator */
COLLECTSUBLINES Purpose, /* what sublines to take from a complex object */
PLSDNODE plsdnFirst, /* dnode from which we started collecting */
LSCP cpLim, /* boundary for group chunk if we go forward */
BOOL fForward); /* direction of traversing is forward otherwise it's backward*/
static void DestroyGroupChunkIterator(
GROUPCHUNKITERATOR* pgroupchunkiterator); /* handler for iterator */
static PLSDNODE ContinueGroupChunk(
GROUPCHUNKITERATOR* pgroupchunkiterator, /* handler for iterator */
BOOL* pfSuccessful); /* OUT: do we find dnode */
static PLSDNODE GetNextDnodeInGroupChunk(
GROUPCHUNKITERATOR* pgroupchunkiterator, /* handler for iterator */
BOOL* pfSuccessful); /* OUT: do we find dnode */
#define LschnkeFromDnode(plschnke, plsdn) \
(plschnke)->cpFirst = plsdn->cpFirst; \
(plschnke)->dcp = (plsdn)->dcp; \
(plschnke)->plschp = &((plsdn)->u.real.lschp); \
(plschnke)->plsrun = (plsdn)->u.real.plsrun; \
(plschnke)->pdobj = (plsdn)->u.real.pdobj;
#define FIsGroupChunkBoundary(plsdn, cpLim, cpBase) \
(FIsOutOfBoundary((plsdn), (cpLim)) \
||(FIsDnodePen(plsdn) && (!(plsdn)->fAdvancedPen)) \
|| ((plsdn)->fTab) \
|| (((cpBase) >= 0) ? ((plsdn)->cpFirst < 0) : ((plsdn)->cpFirst >= 0)))
/* last check verifies that we are not crossing boundaries of autonumber */
#define FIsGroupChunkStartBoundary(plsdn, cpBase) \
(((plsdn) == NULL) \
||(FIsDnodePen(plsdn) && (!(plsdn)->fAdvancedPen)) \
|| ((plsdn)->fTab) \
|| (((cpBase) >= 0) ? ((plsdn)->cpFirst < 0) : ((plsdn)->cpFirst >= 0)))
/* last check verifies that we are not crossing boundaries of autonumber */
#define FIsGrchnkExtValid(plschunkcontext, pgrchunkext) \
(((plschunkcontext) == (pgrchunkext)->plschunkcontext) &&\
((pgrchunkext)->lsgrchnk.plschnk == (plschunkcontext)->locchnkCurrent.plschnk) &&\
((pgrchunkext)->lsgrchnk.pcont == (plschunkcontext)->pcont) &&\
((pgrchunkext)->pplsdnNonText == (plschunkcontext)->pplsdnNonText) &&\
((pgrchunkext)->pfNonTextExpandAfter == (plschunkcontext)->pfNonTextExpandAfter) \
)
#define FDnodeInsideSubline(plssubl, plsdn) \
(FDnodeBeforeCpLim(plsdn, (plssubl)->cpLim) \
&& FDnodeAfterCpFirst(plsdn, (plssubl)->cpFirst))
#define FUseForPurpose(plsdn, purpose) \
(*(&((plsdn)->u.real.pinfosubl->fUseForJustification) + (purpose -1)))
#define FIsUsageFlagsCastWorks(plsdn) \
((plsdn)->u.real.pinfosubl->fUseForCompression == \
FUseForPurpose(plsdn, CollectSublinesForCompression) && \
(plsdn)->u.real.pinfosubl->fUseForJustification == \
FUseForPurpose(plsdn, CollectSublinesForJustification) && \
(plsdn)->u.real.pinfosubl->fUseForDisplay == \
FUseForPurpose(plsdn, CollectSublinesForDisplay) && \
(plsdn)->u.real.pinfosubl->fUseForDecimalTab == \
FUseForPurpose(plsdn, CollectSublinesForDecimalTab) && \
(plsdn)->u.real.pinfosubl->fUseForTrailingArea == \
FUseForPurpose(plsdn, CollectSublinesForTrailingArea))
#define GetSubmittedSublines(plsdn, purpose) \
((((purpose) == CollectSublinesNone) || \
(Assert(FIsDnodeReal(plsdn)), (plsdn)->u.real.pinfosubl == NULL) || \
((plsdn)->u.real.pinfosubl->rgpsubl == NULL)) ? \
NULL : (Assert(FIsUsageFlagsCastWorks(plsdn)), \
(FUseForPurpose(plsdn, purpose)) ? \
(plsdn)->u.real.pinfosubl->rgpsubl : NULL))
#define GetNumberSubmittedSublines(plsdn) \
(Assert((plsdn)->u.real.pinfosubl != NULL), (plsdn)->u.real.pinfosubl->cSubline)
#define FColinearTflows(t1, t2) \
(((t1) & fUVertical) == ((t2) & fUVertical))
#define FSameSemiPlaneTflows(t1, t2) \
(((t1) & fUDirection) == ((t2) & fUDirection))
#define FParallelTflows(t1,t2) \
Assert(FColinearTflows(t1, t2)), \
FSameSemiPlaneTflows(t1, t2) // we assume here that they are colinear
/* C O L L E C T C H U N K A R O U N D*/
/*----------------------------------------------------------------------------
%%Function: CollectChunkAround
%%Contact: igorzv
Parameters:
plsc - (IN) chunk context
plsdn - (IN) dnode to collect chunk arround
lstflow - (IN) lstflow
ppoint (IN) starting position of dnode
Fill in cnunk elements array for chunk arround pposinline->plsdn
Calculate location of the chunk
----------------------------------------------------------------------------*/
LSERR CollectChunkAround(PLSCHUNKCONTEXT plschunkcontext, PLSDNODE plsdnInChunk,
LSTFLOW lstflow, POINTUV* ppoint)
{
WORD idObjChnk;
PLSDNODE plsdnNext;
PLSDNODE plsdnCurrent;
PLOCCHNK plocchnk;
LSCHNKE* plschnke;
DWORD clschnk;
LSERR lserr;
LSCP cpInChunk;
Assert(FIsLSDNODE(plsdnInChunk));
plocchnk = &(plschunkcontext->locchnkCurrent);
clschnk = plocchnk->clschnk;
plschnke = plocchnk->plschnk;
plsdnCurrent = plsdnInChunk;
cpInChunk = plsdnInChunk->cpFirst;
/* check: has this chunk already collected? */
/* chunk was already collected if there is some chunk and our dnode is within this chunk
and nothing was added to list after chunk was collected */
/* we turn off optimisation for dnodes with dcp=0 (ex. pens) because of a problem how
to figure out that dnode is within chunk */
if ((!plschunkcontext->FChunkValid) || (plschunkcontext->FGroupChunk)
||(plschnke[0].cpFirst > plsdnCurrent->cpFirst)
|| (plschnke[clschnk - 1].cpFirst < plsdnCurrent->cpFirst)
|| (plsdnCurrent->dcp == 0)
|| (plschnke[0].dcp == 0)
|| ((plschunkcontext->pplsdnChunk[clschnk - 1])->plsdnNext != NULL))
{
/* we need to recollect chunk */
/* we don't allow caller to pass border as a plsdnInChunk */
Assert(!FIsDnodeBorder(plsdnInChunk));
if ( FIsDnodePen(plsdnInChunk) || plsdnInChunk->fTab || FIsDnodeSplat(plsdnInChunk))
{
/* for pens and tabs chunk consists of one element and we collect it right away */
plocchnk->clschnk = 1;
Assert(plocchnk->clschnk <= plschunkcontext->cchnkMax);
LschnkeFromDnode((&(plschnke[0])), plsdnInChunk);
plschunkcontext->pplsdnChunk[0] = plsdnInChunk;
plschunkcontext->FChunkValid = fTrue;
plschunkcontext->FLocationValid = fFalse;
plschunkcontext->FGroupChunk = fFalse;
/* we should here calculate width of border before dnode, the same way it done
in FillChunkArray */
plschunkcontext->pdurOpenBorderBefore[0] = 0;
plschunkcontext->pdurCloseBorderAfter[0] = 0;
plschunkcontext->FBorderInside = fFalse;
plsdnCurrent = plsdnInChunk->plsdnPrev;
if (plsdnCurrent != NULL && FIsDnodeOpenBorder(plsdnCurrent))
{
plschunkcontext->FBorderInside = fTrue;
plschunkcontext->pdurOpenBorderBefore[0] += DurFromDnode(plsdnCurrent);
}
plsdnCurrent = plsdnInChunk->plsdnNext;
if (plsdnCurrent != NULL && FIsDnodeCloseBorder(plsdnCurrent))
{
plschunkcontext->FBorderInside = fTrue;
plschunkcontext->pdurCloseBorderAfter[0] += DurFromDnode(plsdnCurrent);
}
}
else
{
idObjChnk = IdObjFromDnode(plsdnInChunk);
/* go to the end of chunk */
plsdnNext = plsdnCurrent->plsdnNext;
while(!FIsChunkBoundary(plsdnNext, idObjChnk, cpInChunk))
{
plsdnCurrent = plsdnNext;
plsdnNext = plsdnCurrent->plsdnNext;
}
lserr = FillChunkArray(plschunkcontext, plsdnCurrent);
if (lserr != lserrNone)
return lserr;
}
}
/* check: is chunck located */
if (!plschunkcontext->FLocationValid)
{
LocateChunk(plschunkcontext, plsdnInChunk, lstflow, ppoint);
}
return lserrNone;
}
/* L O C A T E C H U N K */
/*----------------------------------------------------------------------------
%%Function: CollectPreviousChunk
%%Contact: igorzv
Parameters:
plsc - (IN) chunk context
plsdn - (IN) dnode to collect chunk arround
lstflow - (IN) lstflow
ppoint (IN) starting position of dnode
Calculates location of the chunk. We assume here that pointUv.u in locchunk
contains before this procedure width of border before dnode.
After procedure we put location there
/*----------------------------------------------------------------------------*/
static void LocateChunk(PLSCHUNKCONTEXT plschunkcontext, PLSDNODE plsdnInChunk,
LSTFLOW lstflow, POINTUV* ppoint)
{
PLSDNODE plsdnFirst;
PLOCCHNK plocchnk;
PLSDNODE* pplsdnChunk;
PLSDNODE plsdnCurrent;
long urPen,vrPen;
LONG i;
PPOINTUV ppointUv;
LONG* pdurOpenBorderBefore;
LONG* pdurCloseBorderAfter;
Assert(!FIsDnodeBorder(plsdnInChunk)); /* we don't allow border as in input */
plocchnk = &(plschunkcontext->locchnkCurrent);
plsdnFirst = plschunkcontext->pplsdnChunk[0];
plocchnk->lsfgi.fFirstOnLine = FIsFirstOnLine(plsdnFirst)
&& FIsSubLineMain(SublineFromDnode(plsdnFirst));
plocchnk->lsfgi.cpFirst = plsdnFirst->cpFirst;
plocchnk->lsfgi.lstflow = lstflow;
/* we can't set urColumnMax here, because during breaking object handler can change it */
/* and we suppose that caller use for this purpose SetUrColumnMaxForChunks */
pplsdnChunk = plschunkcontext->pplsdnChunk;
ppointUv = plocchnk->ppointUvLoc;
pdurOpenBorderBefore = plschunkcontext->pdurOpenBorderBefore;
pdurCloseBorderAfter = plschunkcontext->pdurCloseBorderAfter;
/* calculation of pen position before chunk */
if (plsdnFirst->plsdnPrev == NULL) /* optimization */
{
urPen = plschunkcontext->urFirstChunk;
vrPen = plschunkcontext->vrFirstChunk;
}
else
{
plsdnCurrent = plsdnInChunk;
urPen = ppoint->u;
vrPen = ppoint->v;
for (i = 0; pplsdnChunk[i] != plsdnCurrent; i++)
{
Assert(i < (LONG) plocchnk->clschnk);
urPen -= DurFromDnode(pplsdnChunk[i]);
vrPen -= DvrFromDnode(pplsdnChunk[i]);
/* substract also border before dnode */
urPen -= pdurOpenBorderBefore[i];
urPen -= pdurCloseBorderAfter[i];
}
/* and now open border before plsdnCurrent */
urPen -= pdurOpenBorderBefore[i];
}
plocchnk->lsfgi.urPen = urPen;
plocchnk->lsfgi.vrPen = vrPen;
/* location of all dnodes */
for (i = 0; i < (LONG) plocchnk->clschnk; i++)
{
urPen += pdurOpenBorderBefore[i]; /* count border */
if (i != 0) urPen += pdurCloseBorderAfter[i - 1];
ppointUv[i].u = urPen;
ppointUv[i].v = vrPen;
urPen += DurFromDnode(pplsdnChunk[i]);
vrPen += DvrFromDnode(pplsdnChunk[i]);
}
plschunkcontext->FLocationValid = fTrue;
}
/* C O L L E C T P R E V I O U S C H U N K */
/*----------------------------------------------------------------------------
%%Function: CollectPreviousChunk
%%Contact: igorzv
Parameters:
plschuncontext - (IN) chunk context
pfSuccessful - (OUT) does previous chunk exist
Check that we are in the begining of line,
othewise call CollectChunkAround with the previous dnode
----------------------------------------------------------------------------*/
LSERR CollectPreviousChunk(PLSCHUNKCONTEXT plschunkcontext,
BOOL* pfSuccessful )
{
PLOCCHNK plocchnk;
POINTUV point;
PLSDNODE plsdn;
plocchnk = &(plschunkcontext->locchnkCurrent);
if (FIsFirstOnLine(plschunkcontext->pplsdnChunk[0]))
{
*pfSuccessful = fFalse;
return lserrNone;
}
else
{
plsdn = plschunkcontext->pplsdnChunk[0]->plsdnPrev;
point = plocchnk->ppointUvLoc[0];
while (FIsDnodeBorder(plsdn))
{
point.u -= DurFromDnode(plsdn);
point.v -= DvrFromDnode(plsdn);
plsdn = plsdn->plsdnPrev;
}
point.u -= DurFromDnode(plsdn);
point.v -= DvrFromDnode(plsdn);
*pfSuccessful = fTrue;
return CollectChunkAround(plschunkcontext, plsdn,
plocchnk->lsfgi.lstflow, &point);
}
}
/* C O L L E C T N E X T C H U N K */
/*----------------------------------------------------------------------------
%%Function: CollectNextChunk
%%Contact: igorzv
Parameters:
plschuncontext - (IN) chunk context
pfSuccessful - (OUT) does next chunk exist
Check that we are in the end of list, in this case return *pfSuccessful and don't change chunk
othewise call CollectChunkAround with the next dnode
----------------------------------------------------------------------------*/
LSERR CollectNextChunk(PLSCHUNKCONTEXT plschunkcontext,
BOOL* pfSuccessful )
{
PLOCCHNK plocchnk;
DWORD clschnk;
PLSDNODE* pplsdnChunk;
POINTUV point;
PLSDNODE plsdn;
plocchnk = &(plschunkcontext->locchnkCurrent);
clschnk = plocchnk->clschnk;
Assert(clschnk > 0);
pplsdnChunk = plschunkcontext->pplsdnChunk;
point = plocchnk->ppointUvLoc[clschnk - 1];
point.u += DurFromDnode(pplsdnChunk[clschnk - 1]);
point.v += DvrFromDnode(pplsdnChunk[clschnk - 1]);
plsdn = pplsdnChunk[clschnk - 1]->plsdnNext;
/* skip borders */
while (plsdn != NULL && FIsDnodeBorder(plsdn))
{
point.u += DurFromDnode(plsdn);
point.v += DvrFromDnode(plsdn);
plsdn = plsdn->plsdnNext;
}
if (plsdn == NULL)
{
*pfSuccessful = fFalse;
return lserrNone;
}
else
{
*pfSuccessful = fTrue;
return CollectChunkAround(plschunkcontext, plsdn,
plocchnk->lsfgi.lstflow, &point);
}
}
/* F I L L C H U N K A R R A Y*/
/*----------------------------------------------------------------------------
%%Function: FillChunkArray
%%Contact: igorzv
Parameters:
plschuncontext - (IN) chunk context
plsdnLast - (IN) last dnode in chunk
Fill in chunk elements array for chunk before plsdnLast
----------------------------------------------------------------------------*/
LSERR FillChunkArray(PLSCHUNKCONTEXT plschunkcontext,
PLSDNODE plsdnLast)
{
PLSDNODE plsdnCurrent, plsdnPrev;
WORD idObjChnk;
PLOCCHNK plocchnk;
LSCHNKE* plschnke;
LONG clschnke;
LSERR lserr;
LONG i;
LSCP cpInChunk;
PPOINTUV ppointUv;
LONG* pdurOpenBorderBefore;
LONG* pdurCloseBorderAfter;
Assert(FIsLSDNODE(plsdnLast));
Assert(!plsdnLast->fTab); /* for optimization we assume that caller will resolve */
Assert(! FIsDnodePen(plsdnLast)); /* pen and tabs */
Assert(!FIsDnodeSplat(plsdnLast));
plocchnk = &(plschunkcontext->locchnkCurrent);
/* skip borders in the end of chunk to figure out what idObj this chunk has */
while (FIsDnodeBorder(plsdnLast))
{
plsdnLast = plsdnLast->plsdnPrev;
Assert(FIsLSDNODE(plsdnLast));
}
idObjChnk = IdObjFromDnode(plsdnLast);
cpInChunk = plsdnLast->cpFirst;
/* go to the begining of chunk calculating amount of elements */
plsdnCurrent = plsdnLast;
plsdnPrev = plsdnCurrent->plsdnPrev;
clschnke = 1;
while (!FIsChunkBoundary(plsdnPrev, idObjChnk, cpInChunk))
{
plsdnCurrent = plsdnPrev;
plsdnPrev = plsdnCurrent->plsdnPrev;
if (!FIsDnodeBorder(plsdnCurrent)) clschnke++; /* we don't put borders into array */
}
/* plsdnCurrent is first dnode in chunk, clschnke is amount of chnk elements */
if (clschnke > (LONG) plschunkcontext->cchnkMax)
{
lserr = SetChunkArraysSize(plschunkcontext, clschnke);
if (lserr != lserrNone)
return lserr;
}
/* fill in array of chunk elements */
FlushNominalToIdealState(plschunkcontext);
plschnke = plocchnk->plschnk;
plocchnk->clschnk = clschnke;
ppointUv = plocchnk->ppointUvLoc;
pdurOpenBorderBefore = plschunkcontext->pdurOpenBorderBefore;
pdurCloseBorderAfter = plschunkcontext->pdurCloseBorderAfter;
plschunkcontext->FBorderInside = fFalse;
for (i=0; i < clschnke; i++)
{
Assert(!FIsChunkBoundary(plsdnCurrent, idObjChnk, cpInChunk));
ppointUv[i].u = 0;
pdurOpenBorderBefore[i] = 0;
if (i != 0) pdurCloseBorderAfter[i - 1] = 0;
while (FIsDnodeBorder(plsdnCurrent))
{
/* calculates border widths */
plschunkcontext->FBorderInside = fTrue;
if (FIsDnodeOpenBorder(plsdnCurrent))
{
pdurOpenBorderBefore[i] += DurFromDnode(plsdnCurrent);
}
else
{
if (i != 0) pdurCloseBorderAfter[i - 1] += DurFromDnode(plsdnCurrent);
}
plsdnCurrent = plsdnCurrent->plsdnNext;
}
LschnkeFromDnode(plschnke, plsdnCurrent);
plschunkcontext->pplsdnChunk[i] = plsdnCurrent;
SetNominalToIdealFlags(plschunkcontext, &(plsdnCurrent->u.real.lschp));
plsdnCurrent = plsdnCurrent->plsdnNext;
plschnke++;
}
/* closing border after chunk */
if (plsdnCurrent != NULL && FIsDnodeCloseBorder(plsdnCurrent))
{
plschunkcontext->FBorderInside = fTrue;
pdurCloseBorderAfter[clschnke - 1] = DurFromDnode(plsdnCurrent);
}
else
{
pdurCloseBorderAfter[clschnke - 1] = 0;
}
plschunkcontext->FChunkValid = fTrue;
plschunkcontext->FLocationValid = fFalse; /* chunk we collected is not located and */
plschunkcontext->FGroupChunk = fFalse; /* is not group */
return lserrNone;
}
/* S E T P O S I N C H U N K */
/*----------------------------------------------------------------------------
%%Function: SetPosInChunk
%%Contact: igorzv
Parameters:
plschunkcontext - (IN) LineServices context
PLSDNODE plsdn - (IN) dnode
LSDCP dcp - (IN) dcp
pposichnk - (OUT) position in chunk to fill in
Convert position in line to position in chunk
----------------------------------------------------------------------------*/
void SetPosInChunk(PLSCHUNKCONTEXT plschunkcontext, PLSDNODE plsdn,
LSDCP dcp, PPOSICHNK pposichnk)
{
LONG i;
LONG clschnkMac;
PLSDNODE* pplsdnChunk;
Assert(FIsLSDNODE(plsdn));
pplsdnChunk = plschunkcontext->pplsdnChunk;
clschnkMac = plschunkcontext->locchnkCurrent.clschnk;
for (i=0; (i < clschnkMac) && (plsdn != pplsdnChunk[i]) ; i++);
Assert(i < clschnkMac);
pposichnk->dcp = dcp;
pposichnk->ichnk = i;
}
/* I N I T G R O U P C H U N K E X T */
/*----------------------------------------------------------------------------
%%Function: InitGroupChunkExt
%%Contact: igorzv
Parameters:
plschunkcontext - (IN) chunkcontext context
iobjText - (IN) idobj of text
pgrchunkext - (OUT) structure to initialize
Link GroupChunkExt with state
Fill in default values
----------------------------------------------------------------------------*/
void InitGroupChunkExt(PLSCHUNKCONTEXT plschunkcontext, DWORD iobjText,
GRCHUNKEXT* pgrchunkext)
{
Assert(pgrchunkext != NULL);
pgrchunkext->plschunkcontext = plschunkcontext;
pgrchunkext->iobjText = iobjText;
/* we don't need to flush everything here */
/* we will do this in CollectGroupChunk procedures */
pgrchunkext->lsgrchnk.plschnk = plschunkcontext->locchnkCurrent.plschnk;
pgrchunkext->lsgrchnk.pcont = plschunkcontext->pcont;
pgrchunkext->pfNonTextExpandAfter = plschunkcontext->pfNonTextExpandAfter;
pgrchunkext->pplsdnNonText = plschunkcontext->pplsdnNonText;
}
/* C O L L E C T T E X T G R O U P C H U N K*/
/*----------------------------------------------------------------------------
%%Function: CollectTextGroupChunk
%%Contact: igorzv
Parameters:
plsdnFirst - (IN) start dnode
cpLim - (IN) boundary for group chunk
Purpose - (IN) what subline to take from complex object
pgrchunkext - (OUT) group chunk to fill in
Fill in group chunk structure with text dnodes located from plsdFirst
----------------------------------------------------------------------------*/
LSERR CollectTextGroupChunk(
PLSDNODE plsdnFirst,
LSCP cpLim,
COLLECTSUBLINES Purpose,
GRCHUNKEXT* pgrchunkext)
{
PLSCHUNKCONTEXT plschunkcontext = pgrchunkext->plschunkcontext;
DWORD iobjText = pgrchunkext->iobjText;
PLOCCHNK plocchnk;
DWORD cChunk;
PLSDNODE plsdnCurrent;
BOOL fPreviousIsNonText = fFalse;
LSERR lserr;
LSCHNKE* plschnke;
BOOL fSuccessful;
BOOL fExpand;
DWORD cTextBeforeLastNonText = 0;
GROUPCHUNKITERATOR groupchunkiterator;
PLSDNODE plsdnLastForTrailing;
int cDnodesTrailing;
LSDCP dcpStartTrailing;
PLSDNODE plsdnTrailingObject;
LSDCP dcpTrailingObject;
Assert(FIsLSDNODE(plsdnFirst));
Assert(FIsGrchnkExtValid(plschunkcontext, pgrchunkext));
/* we try to optimize here in a case when group chunk consist of one (last in a line)
chunk and this chunk has been already collected */
plocchnk = &(plschunkcontext->locchnkCurrent);
cChunk = plocchnk->clschnk;
/* if we have text chunk without borders started with plsdnFirst
and going up or beyond cpLim */
if ((cChunk > 0) &&
(plschunkcontext->FChunkValid) &&
(!plschunkcontext->FGroupChunk) &&
(!plschunkcontext->FBorderInside) &&
(IdObjFromChnk(plocchnk) == pgrchunkext->iobjText) &&
(plschunkcontext->pplsdnChunk[0] == plsdnFirst)
&& (!plsdnFirst->fTab)
&& (FIsOutOfBoundary((plschunkcontext->pplsdnChunk[cChunk - 1])->plsdnNext, cpLim)))
{
pgrchunkext->Purpose = Purpose;
return ConvertChunkToGroupChunk(pgrchunkext, cpLim);
}
/* we have to go through general procedure */
/* flush group chunk */
pgrchunkext->plsdnFirst = plsdnFirst;
pgrchunkext->durTotal = 0;
pgrchunkext->durTextTotal = 0;
pgrchunkext->dupNonTextTotal = 0;
pgrchunkext->cNonTextObjects = 0;
pgrchunkext->cNonTextObjectsExpand = 0;
pgrchunkext->lsgrchnk.clsgrchnk = 0;
pgrchunkext->plsdnNext = NULL;
pgrchunkext->plsdnLastUsed = NULL;
plschunkcontext->FGroupChunk = fTrue;
plschunkcontext->FBorderInside = fFalse;
pgrchunkext->Purpose = Purpose;
CreateGroupChunkIterator(&groupchunkiterator,
Purpose, plsdnFirst, cpLim, fTrue);
plsdnCurrent = GetNextDnodeInGroupChunk(&groupchunkiterator, &fSuccessful);
while(fSuccessful)
{
pgrchunkext->plsdnLastUsed = plsdnCurrent;
/* fill in array of elements */
if (FIsDnodeReal(plsdnCurrent) && !FIsDnodeSplat(plsdnCurrent)) /* not a pen border or splat*/
{
if (IdObjFromDnode(plsdnCurrent) == iobjText) /* is text */
{
pgrchunkext->lsgrchnk.clsgrchnk++;
if (pgrchunkext->lsgrchnk.clsgrchnk > plschunkcontext->cchnkMax)
{
lserr = IncreaseChunkArrays(plschunkcontext);
if (lserr != lserrNone)
{
DestroyGroupChunkIterator(&groupchunkiterator);
return lserr;
}
pgrchunkext->lsgrchnk.plschnk = plschunkcontext->locchnkCurrent.plschnk;
pgrchunkext->lsgrchnk.pcont = plschunkcontext->pcont;
Assert(FIsGrchnkExtValid(plschunkcontext, pgrchunkext));
}
/* fill in group chunk element */
plschnke = &(pgrchunkext->lsgrchnk.plschnk[pgrchunkext->lsgrchnk.clsgrchnk - 1]);
LschnkeFromDnode(plschnke, plsdnCurrent);
/* fill in array of dnodes in context */
plschunkcontext->pplsdnChunk[pgrchunkext->lsgrchnk.clsgrchnk - 1] = plsdnCurrent;
/* flash flags */
pgrchunkext->lsgrchnk.pcont[pgrchunkext->lsgrchnk.clsgrchnk - 1] = 0;
/* set flags */
if (fPreviousIsNonText)
{
pgrchunkext->lsgrchnk.pcont[pgrchunkext->lsgrchnk.clsgrchnk - 1] |=
fcontNonTextBefore;
}
fPreviousIsNonText = fFalse;
/* calculate integrated information */
pgrchunkext->durTextTotal += plsdnCurrent->u.real.objdim.dur;
pgrchunkext->durTotal += plsdnCurrent->u.real.objdim.dur;
}
else
{
/* resolve expansion after previous non text */
if (pgrchunkext->cNonTextObjects > 0)
{
lserr = FExpandAfterNonTextObject(pgrchunkext, cTextBeforeLastNonText,
&fExpand);
if (lserr != lserrNone)
{
DestroyGroupChunkIterator(&groupchunkiterator);
return lserr;
}
pgrchunkext->pfNonTextExpandAfter[pgrchunkext->cNonTextObjects - 1] =
fExpand;
if (fExpand)
{
/* increase amount of expandable non text objects */
pgrchunkext->cNonTextObjectsExpand++;
/* it was text between two non texts */
if (!fPreviousIsNonText)
{
Assert(pgrchunkext->lsgrchnk.clsgrchnk > cTextBeforeLastNonText);
pgrchunkext->lsgrchnk.pcont[cTextBeforeLastNonText] |=
fcontExpandBefore;
}
}
}
pgrchunkext->cNonTextObjects++;
if (pgrchunkext->cNonTextObjects > plschunkcontext->cNonTextMax)
{
lserr = IncreaseGroupChunkNonTextArrays(plschunkcontext);
if (lserr != lserrNone)
{
DestroyGroupChunkIterator(&groupchunkiterator);
return lserr;
}
pgrchunkext->pplsdnNonText = plschunkcontext->pplsdnNonText;
pgrchunkext->pfNonTextExpandAfter = plschunkcontext->pfNonTextExpandAfter;
Assert(FIsGrchnkExtValid(plschunkcontext, pgrchunkext));
}
/* fill in array of non text dnodes in context */
plschunkcontext->pplsdnNonText[pgrchunkext->cNonTextObjects - 1] = plsdnCurrent;
/* set flags in previous text */
if (!fPreviousIsNonText && pgrchunkext->lsgrchnk.clsgrchnk >= 1)
{
Assert(pgrchunkext->lsgrchnk.clsgrchnk >= 1);
pgrchunkext->lsgrchnk.pcont[pgrchunkext->lsgrchnk.clsgrchnk - 1] |=
(fcontNonTextAfter);
/* resolve expansion before current non text */
Assert(cTextBeforeLastNonText < pgrchunkext->lsgrchnk.clsgrchnk);
lserr =FExpandBeforeNonTextObject(pgrchunkext, cTextBeforeLastNonText,
&fExpand);
if (lserr != lserrNone)
{
DestroyGroupChunkIterator(&groupchunkiterator);
return lserr;
}
if (fExpand)
{
pgrchunkext->lsgrchnk.pcont[pgrchunkext->lsgrchnk.clsgrchnk - 1] |=
fcontExpandAfter;
}
}
fPreviousIsNonText = fTrue;
cTextBeforeLastNonText = pgrchunkext->lsgrchnk.clsgrchnk;
/* calculate integrated information */
pgrchunkext->durTotal += DurFromRealDnode(plsdnCurrent);
pgrchunkext->dupNonTextTotal += DupFromRealDnode(plsdnCurrent);
} /* non -text */
} /* real dnode */
else
{ /* pen or border*/
Assert(FIsDnodePen(plsdnCurrent) ||
FIsDnodeBorder(plsdnCurrent) || FIsDnodeSplat(plsdnCurrent));
Assert(FIsDnodeBorder(plsdnCurrent) || FIsDnodeSplat(plsdnCurrent) ||
plsdnCurrent->fAdvancedPen); /* only advanced pens are allowed here */
if (FIsDnodeBorder(plsdnCurrent))
plschunkcontext->FBorderInside = fTrue;
pgrchunkext->durTotal += DurFromDnode(plsdnCurrent);
pgrchunkext->dupNonTextTotal += DupFromDnode(plsdnCurrent);
}
/* prepare next iteration */
plsdnCurrent = GetNextDnodeInGroupChunk(&groupchunkiterator, &fSuccessful);
}
/* resolve expansion after previous non text */
if (pgrchunkext->cNonTextObjects > 0)
{
lserr = FExpandAfterNonTextObject(pgrchunkext, cTextBeforeLastNonText,
&fExpand);
if (lserr != lserrNone)
{
DestroyGroupChunkIterator(&groupchunkiterator);
return lserr;
}
pgrchunkext->pfNonTextExpandAfter[pgrchunkext->cNonTextObjects - 1] |=
fExpand;
if (fExpand)
{
/* increase amount of expandable non text objects */
pgrchunkext->cNonTextObjectsExpand++;
/* it was text between two non texts */
if (!fPreviousIsNonText)
{
Assert(pgrchunkext->lsgrchnk.clsgrchnk > cTextBeforeLastNonText);
pgrchunkext->lsgrchnk.pcont[cTextBeforeLastNonText] |=
fcontExpandBefore;
}
}
}
pgrchunkext->plsdnNext = plsdnCurrent;
DestroyGroupChunkIterator(&groupchunkiterator);
/* because collecting of group chunk can be called before SetBreak, dcp of last
dnode, if it come from lower level, should be cut using cpLim */
if ((pgrchunkext->lsgrchnk.clsgrchnk > 0) &&
(plschunkcontext->pplsdnChunk[pgrchunkext->lsgrchnk.clsgrchnk - 1]->cpLimOriginal
> cpLim)
)
{
pgrchunkext->lsgrchnk.plschnk[pgrchunkext->lsgrchnk.clsgrchnk - 1].dcp =
cpLim -
plschunkcontext->pplsdnChunk[pgrchunkext->lsgrchnk.clsgrchnk - 1]->cpFirst;
}
if (Purpose == CollectSublinesForJustification ||
Purpose == CollectSublinesForCompression)
{
/* we should find here last dnode on the upper level before chunk boundary */
if (pgrchunkext->plsdnLastUsed == NULL)
{
/* first dnode is already out of boundary, it can happened with tabs or pens */
Assert(pgrchunkext->plsdnFirst == pgrchunkext->plsdnNext);
plsdnLastForTrailing = pgrchunkext->plsdnFirst;
}
else if (pgrchunkext->plsdnNext != NULL)
{
plsdnLastForTrailing = pgrchunkext->plsdnNext->plsdnPrev;
}
else
{
plsdnLastForTrailing = (SublineFromDnode(pgrchunkext->plsdnFirst))->plsdnLast;
}
lserr = GetTrailingInfoForTextGroupChunk
(plsdnLastForTrailing, plsdnLastForTrailing->dcp,
iobjText, &(pgrchunkext->durTrailing), &(pgrchunkext->dcpTrailing),
&(pgrchunkext->plsdnStartTrailing),
&dcpStartTrailing,
&cDnodesTrailing, &plsdnTrailingObject, &dcpTrailingObject,
&(pgrchunkext->fClosingBorderStartsTrailing));
if (lserr != lserrNone)
{
return lserr;
}
if (cDnodesTrailing == 0)
{
if (pgrchunkext->lsgrchnk.clsgrchnk != 0)
{
pgrchunkext->posichnkBeforeTrailing.ichnk = pgrchunkext->lsgrchnk.clsgrchnk - 1;
pgrchunkext->posichnkBeforeTrailing.dcp = pgrchunkext->lsgrchnk.plschnk
[pgrchunkext->posichnkBeforeTrailing.ichnk].dcp;
}
else
{
/* in this case posichnkBeforeTrailing doesn't make any sense and we can't use
code above not to triger memory violation, so we put zeroes just to put something */
pgrchunkext->posichnkBeforeTrailing.ichnk = 0;
pgrchunkext->posichnkBeforeTrailing.dcp = 0;
}
}
else
{
pgrchunkext->posichnkBeforeTrailing.ichnk = pgrchunkext->lsgrchnk.clsgrchnk
- cDnodesTrailing;
if (FIsDnodeReal(pgrchunkext->plsdnStartTrailing)
&& IdObjFromDnode(pgrchunkext->plsdnStartTrailing) == iobjText)
{
pgrchunkext->posichnkBeforeTrailing.dcp = dcpStartTrailing;
}
else
{
/* trailing area was interupted by non text, we report to text starting of trailing before
previous text */
Assert(pgrchunkext->plsdnStartTrailing->dcp == dcpStartTrailing);
pgrchunkext->posichnkBeforeTrailing.dcp = 0;
}
}
}
return lserrNone;
}
/* C O N T I N U E G R O U P C H U N K*/
/*----------------------------------------------------------------------------
%%Function: ContinueGroupChunk
%%Contact: igorzv
Parameters:
pgroupchunkiterator -(IN) handler for iterator
pfSuccessful - (OUT) do we find dnode in this group chunk
Start traversing list for collecting group chunk
----------------------------------------------------------------------------*/
PLSDNODE ContinueGroupChunk(
GROUPCHUNKITERATOR* pgroupchunkiterator,
BOOL* pfSuccessful)
{
PLSSUBL plssubl;
PLSSUBL* rgpsubl;
PLSDNODE plsdnStart = pgroupchunkiterator->plsdnStart;
BOOL fBoundaryCondition;
int cSublines;
/* we assume here that dnode out of group chunk boundary can happen only on main subline of
the group chunk */
fBoundaryCondition = pgroupchunkiterator->fForward ?
FIsGroupChunkBoundary(plsdnStart, pgroupchunkiterator->cpLim,
pgroupchunkiterator->plsdnFirst->cpFirst) :
FIsGroupChunkStartBoundary(plsdnStart, pgroupchunkiterator->plsdnFirst->cpFirst) ;
if (fBoundaryCondition) /* we out of limits */
{
AssertImplies(plsdnStart != NULL, FIsLSDNODE(plsdnStart));
AssertImplies(plsdnStart != NULL,
SublineFromDnode(plsdnStart) == SublineFromDnode(pgroupchunkiterator->plsdnFirst));
*pfSuccessful = fFalse;
return plsdnStart;
}
Assert(FIsLSDNODE(plsdnStart));
plssubl = SublineFromDnode(plsdnStart);
/* we assume here that here that plsnStart is valid dnode within subline*/
Assert(!FIsOutOfBoundary(plsdnStart, plssubl->cpLim));
*pfSuccessful = fTrue;
if (FIsDnodeBorder(plsdnStart) || FIsDnodePen(plsdnStart))
{
return plsdnStart;
}
rgpsubl = GetSubmittedSublines(plsdnStart, pgroupchunkiterator->Purpose);
if (rgpsubl == NULL)
{
return plsdnStart;
}
else
{
cSublines = GetNumberSubmittedSublines(plsdnStart);
if (cSublines > 0)
{
plssubl = pgroupchunkiterator->fForward ?
rgpsubl[0] : rgpsubl[cSublines - 1];
/* we assume here that empty subline can not be submitted */
Assert(!FIsOutOfBoundary(plssubl->plsdnFirst, plssubl->cpLim));
plssubl->plsdnUpTemp = plsdnStart;
pgroupchunkiterator->plsdnStart = pgroupchunkiterator->fForward ?
plssubl->plsdnFirst : plssubl->plsdnLast;
return ContinueGroupChunk(pgroupchunkiterator, pfSuccessful);
}
else
{
return plsdnStart;
}
}
}
/* G E T N E X T D N O D E I N G R O U P C H U N K*/
/*----------------------------------------------------------------------------
%%Function: GetNextDnodeInGroupChunk
%%Contact: igorzv
Parameters:
pgroupchunkiterator -(IN) handler for iterator
pfSuccessful - (OUT) do we find dnode in this group chunk
Continue traversing list for collecting group chunk
----------------------------------------------------------------------------*/
PLSDNODE GetNextDnodeInGroupChunk(
GROUPCHUNKITERATOR* pgroupchunkiterator,
BOOL* pfSuccessful)
{
LONG i;
PLSSUBL plssubl;
PLSDNODE plsdnNext;
PLSDNODE plsdnUp;
PLSSUBL* rgpsubl;
LONG cSublines;
PLSDNODE plsdnStart = pgroupchunkiterator->plsdnStart;
if (plsdnStart == NULL) /* first iteration */
{
pgroupchunkiterator->plsdnStart = pgroupchunkiterator->plsdnFirst;
return ContinueGroupChunk(pgroupchunkiterator, pfSuccessful);
}
Assert(FIsLSDNODE(plsdnStart));
plssubl = plsdnStart->plssubl;
plsdnNext = pgroupchunkiterator->fForward ?
plsdnStart->plsdnNext : plsdnStart->plsdnPrev;
/* we are in one of submitted sublines and this subline ended */
if (plssubl != SublineFromDnode(pgroupchunkiterator->plsdnFirst) &&
FIsOutOfBoundary(plsdnNext, plssubl->cpLim))
{
plsdnUp = plssubl->plsdnUpTemp;
Assert(FIsLSDNODE(plsdnUp));
/* flush temporary field */
plssubl->plsdnUpTemp = NULL;
rgpsubl = GetSubmittedSublines(plsdnUp, pgroupchunkiterator->Purpose);
cSublines = GetNumberSubmittedSublines(plsdnUp);
Assert(rgpsubl != NULL);
Assert(cSublines > 0);
/* find index in a array of submitted sublines */
for (i=0; i < cSublines && plssubl != rgpsubl[i]; i++);
Assert(i < cSublines);
if ( (pgroupchunkiterator->fForward && i == cSublines - 1) ||
(!pgroupchunkiterator->fForward && i == 0)
)
/* array ended: return to the upper level */
{
pgroupchunkiterator->plsdnStart = plsdnUp;
return GetNextDnodeInGroupChunk(pgroupchunkiterator, pfSuccessful);
}
else
{
plssubl = pgroupchunkiterator->fForward ?
rgpsubl[i + 1] : rgpsubl[i - 1];
/* we assume here that empty subline can not be submitted */
Assert(!FIsOutOfBoundary(plssubl->plsdnFirst, plssubl->cpLim));
plssubl->plsdnUpTemp = plsdnUp;
pgroupchunkiterator->plsdnStart = plssubl->plsdnFirst;
return ContinueGroupChunk(pgroupchunkiterator, pfSuccessful);
}
}
else /* we can continue with the same subline */
{
pgroupchunkiterator->plsdnStart = plsdnNext;
return ContinueGroupChunk(pgroupchunkiterator, pfSuccessful);
}
}
/* C R E A T E G R O U P C H U N K I T E R A T O R*/
/*----------------------------------------------------------------------------
%%Function: CreateGroupChunkIterator
%%Contact: igorzv
Parameters:
pgroupchunkiterator -(IN) handler for iterator
Purpose -(INI what sublines to take from a complex object
plsdnFirst -(IN) dnode from which we started collecting
cpLim -(IN) boundary for group chunk if we go forward
fForward -(IN) direction of traversing is forward otherwise it's backward
----------------------------------------------------------------------------*/
static void CreateGroupChunkIterator(
GROUPCHUNKITERATOR* pgroupchunkiterator,
COLLECTSUBLINES Purpose,
PLSDNODE plsdnFirst,
LSCP cpLim,
BOOL fForward)
{
pgroupchunkiterator->Purpose = Purpose;
pgroupchunkiterator->plsdnFirst = plsdnFirst;
pgroupchunkiterator->plsdnStart = NULL;
pgroupchunkiterator->cpLim = cpLim;
pgroupchunkiterator->fForward = fForward;
}
/* D E S T R O Y G R O U P C H U N K I T E R A T O R*/
/*----------------------------------------------------------------------------
%%Function: DesroyGroupChunkIterator
%%Contact: igorzv
Parameters:
pgroupchunkiterator -(IN) handler for iterator
----------------------------------------------------------------------------*/
static void DestroyGroupChunkIterator(
GROUPCHUNKITERATOR* pgroupchunkiterator)
{
PLSSUBL plssubl;
PLSDNODE plsdn;
if (pgroupchunkiterator->plsdnStart != NULL)
{
plssubl = SublineFromDnode(pgroupchunkiterator->plsdnStart);
while (SublineFromDnode(pgroupchunkiterator->plsdnFirst) != plssubl)
{
plsdn = plssubl->plsdnUpTemp;
Assert(FIsLSDNODE(plsdn));
plssubl->plsdnUpTemp = NULL;
plssubl = SublineFromDnode(plsdn);
}
}
}
/* F E X P A N D B E F O R E N O N T E X T O B J E C T*/
/*----------------------------------------------------------------------------
%%Function: FExpandBeforeNonTextObject
%%Contact: igorzv
Parameters:
pgrchunkext - (IN) group chunk
cTextBeforePreviousNonText - (IN) number of text before previous non text
to calculate contiguous chunk
pfExpand - (OUT) to expand dnode before non text
----------------------------------------------------------------------------*/
static LSERR FExpandBeforeNonTextObject(GRCHUNKEXT* pgrchunkext, DWORD cTextBeforePrevioustNonText,
BOOL* pfExpand)
{
DWORD cTextBetween;
LSERR lserr;
BOOL fSuccessful;
WCHAR wchar;
PLSRUN plsrunText;
HEIGHTS heightsText;
MWCLS mwcls;
DWORD iobj;
LSIMETHODS* plsim;
PLSDNODE plsdnNonText;
*pfExpand = fTrue;
cTextBetween = pgrchunkext->lsgrchnk.clsgrchnk - cTextBeforePrevioustNonText;
if (cTextBetween)
{
lserr = GetLastCharInChunk(cTextBetween,
(pgrchunkext->lsgrchnk.plschnk + cTextBeforePrevioustNonText), &fSuccessful,
&wchar, &plsrunText, &heightsText, &mwcls);
if (lserr != lserrNone)
return lserr;
if (fSuccessful)
{
plsdnNonText = pgrchunkext->pplsdnNonText[pgrchunkext->cNonTextObjects - 1];
iobj = IdObjFromDnode(plsdnNonText);
plsim = PLsimFromLsc(pgrchunkext->plschunkcontext->plsiobjcontext, iobj);
if (plsim->pfnFExpandWithPrecedingChar != NULL)
{
lserr = plsim->pfnFExpandWithPrecedingChar(plsdnNonText->u.real.pdobj,
plsdnNonText->u.real.plsrun, plsrunText, wchar,
mwcls, pfExpand);
if (lserr != lserrNone)
return lserr;
} /* object has this method */
} /* call back from text was successful */
}
return lserrNone;
}
/* F E X P A N D A F T E R N O N T E X T O B J E C T*/
/*----------------------------------------------------------------------------
%%Function: FExpandAfterNonTextObject
%%Contact: igorzv
Parameters:
pgrchunkext - (IN) group chunk
cTextBeforeLastNonText - (IN) number of text before last non text
to calculate contiguous chunk
pfExpand - (OUT) to expand dnode before non text
----------------------------------------------------------------------------*/
static LSERR FExpandAfterNonTextObject(GRCHUNKEXT* pgrchunkext, DWORD cTextBeforeLastNonText,
BOOL* pfExpand)
{
DWORD cTextBetween;
LSERR lserr;
BOOL fSuccessful;
WCHAR wchar;
PLSRUN plsrunText;
HEIGHTS heightsText;
MWCLS mwcls;
DWORD iobj;
LSIMETHODS* plsim;
PLSDNODE plsdnNonText;
*pfExpand = fTrue;
cTextBetween = pgrchunkext->lsgrchnk.clsgrchnk - cTextBeforeLastNonText;
if (cTextBetween)
{
lserr = GetFirstCharInChunk(cTextBetween,
(pgrchunkext->lsgrchnk.plschnk + cTextBeforeLastNonText), &fSuccessful,
&wchar, &plsrunText, &heightsText, &mwcls);
if (lserr != lserrNone)
return lserr;
if (fSuccessful)
{
plsdnNonText = pgrchunkext->pplsdnNonText[pgrchunkext->cNonTextObjects - 1];
iobj = IdObjFromDnode(plsdnNonText);
plsim = PLsimFromLsc(pgrchunkext->plschunkcontext->plsiobjcontext, iobj);
if (plsim->pfnFExpandWithFollowingChar != NULL)
{
lserr = plsim->pfnFExpandWithFollowingChar(plsdnNonText->u.real.pdobj,
plsdnNonText->u.real.plsrun, plsrunText, wchar,
mwcls, pfExpand);
if (lserr != lserrNone)
return lserr;
} /* object has this method */
} /* call back from text was successful */
}
return lserrNone;
}
/* C O L L E C T P R E V I O U S T E X T G R O U P C H U N K*/
/*----------------------------------------------------------------------------
%%Function: CollectPreviousTextGroupChunk
%%Contact: igorzv
Parameters:
plsdnEnd - (IN) end dnode
sublinnesToCollect (IN) what subline to take from complex object
pgrchunkext - (OUT) group chunk to fill in
Fill in group chunk structure with text dnodes located before plsdEnd
----------------------------------------------------------------------------*/
LSERR CollectPreviousTextGroupChunk(
PLSDNODE plsdnEnd,
COLLECTSUBLINES Purpose,
BOOL fAllSimpleText,
GRCHUNKEXT* pgrchunkext)
{
LSCHUNKCONTEXT* plschunkcontext = pgrchunkext->plschunkcontext;
PLOCCHNK plocchnk;
DWORD cChunk;
LSCP cpLim;
PLSDNODE plsdn;
PLSDNODE plsdnPrev;
Assert(FIsLSDNODE(plsdnEnd));
Assert(FIsGrchnkExtValid(plschunkcontext, pgrchunkext));
/* we try to optimize here in a case when there is only text in line */
/* chunk of text has been already collected */
plocchnk = &(plschunkcontext->locchnkCurrent);
cChunk = plocchnk->clschnk;
cpLim = plsdnEnd->cpLimOriginal;
if (fAllSimpleText && cChunk > 0)
{
/* chunk goes up to the end of a line */
Assert((plschunkcontext->pplsdnChunk[cChunk - 1])->plsdnNext == NULL);
pgrchunkext->Purpose = Purpose;
return ConvertChunkToGroupChunk(pgrchunkext, cpLim);
}
/* go backward to the start of group chunk */
plsdn = plsdnEnd;
plsdnPrev = plsdn->plsdnPrev;
while (!FIsGroupChunkStartBoundary(plsdnPrev, plsdnEnd->cpFirst))
{
plsdn = plsdnPrev;
plsdnPrev = plsdn->plsdnPrev;
}
return CollectTextGroupChunk(plsdn, cpLim, Purpose, pgrchunkext);
}
/* C O N V E R T C H U N K T O G R O U P C H U N K*/
/*----------------------------------------------------------------------------
%%Function: ConvertChunkToGroupChunk
%%Contact: igorzv
Parameters:
cpLim - (IN) cpLim
pgrchunkext - (OUT) group chunk to fill in
Fill in group chunk structure with text dnodes located before plsdEnd
We assume here that chunk doesn't contain border.
----------------------------------------------------------------------------*/
static LSERR ConvertChunkToGroupChunk(GRCHUNKEXT* pgrchunkext, LSCP cpLim)
{
DWORD clsgrchnkCollected = 0;
long durTotal = 0;
LSCHUNKCONTEXT* plschunkcontext = pgrchunkext->plschunkcontext;
PLOCCHNK plocchnk;
LONG cChunk;
LONG i;
BOOL fLineEnded;
PLSDNODE plsdn;
long durTrailingDnode;
LSDCP dcpTrailingDnode;
Assert(FIsGrchnkExtValid(plschunkcontext, pgrchunkext));
plocchnk = &(plschunkcontext->locchnkCurrent);
cChunk = (int) plocchnk->clschnk;
fLineEnded = fFalse;
for (i = 0; (i < cChunk) && !fLineEnded; i ++)
{
clsgrchnkCollected++;
pgrchunkext->lsgrchnk.pcont[i] = 0;
plsdn = plschunkcontext->pplsdnChunk[i];
durTotal += DurFromRealDnode(plsdn);
/* if we are in last dnode before cpLim there is possibility
that during break it was changed
so we should rewrite dcp in chunk element and quit */
if ((LSCP)(plsdn->cpLimOriginal) == cpLim)
{
plocchnk->plschnk[i].dcp = plsdn->dcp;
fLineEnded = fTrue;
}
}
/* fill in header of groupchunkext */
pgrchunkext->plsdnFirst = plschunkcontext->pplsdnChunk[0];;
pgrchunkext->plsdnLastUsed = plschunkcontext->pplsdnChunk[clsgrchnkCollected - 1];
pgrchunkext->plsdnNext = pgrchunkext->plsdnLastUsed->plsdnNext;
pgrchunkext->durTotal = durTotal;
pgrchunkext->durTextTotal = durTotal;
pgrchunkext->dupNonTextTotal = 0;
pgrchunkext->cNonTextObjects = 0;
pgrchunkext->cNonTextObjectsExpand = 0;
pgrchunkext->lsgrchnk.clsgrchnk = clsgrchnkCollected;
plschunkcontext->FGroupChunk = fTrue;
if (pgrchunkext->Purpose == CollectSublinesForJustification ||
pgrchunkext->Purpose == CollectSublinesForCompression)
{
Assert(clsgrchnkCollected > 0);
pgrchunkext->durTrailing = 0;
pgrchunkext->dcpTrailing = 0;
plsdn = NULL;
dcpTrailingDnode = 0;
pgrchunkext->fClosingBorderStartsTrailing = fFalse;
for (i = clsgrchnkCollected - 1; i >= 0; i--)
{
plsdn = plschunkcontext->pplsdnChunk[i];
GetTrailInfoText(PdobjFromDnode(plsdn), plsdn->dcp,
&dcpTrailingDnode, &durTrailingDnode);
pgrchunkext->durTrailing += durTrailingDnode;
pgrchunkext->dcpTrailing += dcpTrailingDnode;
/* add opening border before previous dnode */
if (i < (int) (clsgrchnkCollected - 1))
pgrchunkext->durTrailing += plschunkcontext->pdurOpenBorderBefore[i +1];
if (dcpTrailingDnode != 0)
/* add closing border after */
pgrchunkext->durTrailing += plschunkcontext->pdurCloseBorderAfter[i];
else
{
pgrchunkext->fClosingBorderStartsTrailing =
(plschunkcontext->pdurCloseBorderAfter[i] != 0);
}
if (plsdn->dcp != dcpTrailingDnode)
break;
}
pgrchunkext->plsdnStartTrailing = plsdn;
if (i == -1) i = 0;
pgrchunkext->posichnkBeforeTrailing.ichnk = i;
pgrchunkext->posichnkBeforeTrailing.dcp = plsdn->dcp - dcpTrailingDnode;
}
return lserrNone;
}
/* G E T T R A I L I N G I N F O F O R T E X T G R O U P C H U N K */
/*----------------------------------------------------------------------------
%%Function: GetTrailingInfoForTextGroupChunk
%%Contact: igorzv
Parameters:
plsdnLastDnode - (IN) dnode where to start calculation of trailing area
dcpLastDnode - (IN) dcp in this dnode
iobjText - (IN) iobj of text
pdurTrailing - (OUT) dur of trailing area in group chunk
pdcpTrailing - (OUT) dcp of trailing area in chunk
pplsdnStartTrailing - (OUT) dnode where trailing area starts
pdcpStartTrailing- (OUT) with pcDnodesTrailing defines last character in text before
trailing area
pcDnodesTrailing - (OUT) number of text dnodes participates in trailing area
pplsdnStartTrailingObject -(OUT) dnode on the upper level where trailing are starts
pdcpStartTrailingObject -(OUT) dcp in such dnode
pfClosingBorderStartsTrailing - (OUT) closing border located just before trailing area
----------------------------------------------------------------------------*/
LSERR GetTrailingInfoForTextGroupChunk
(PLSDNODE plsdnLast, LSDCP dcpLastDnode, DWORD iobjText,
long* pdurTrailing, LSDCP* pdcpTrailing,
PLSDNODE* pplsdnStartTrailing, LSDCP* pdcpStartTrailing,
int* pcDnodesTrailing, PLSDNODE* pplsdnStartTrailingObject,
LSDCP* pdcpStartTrailingObject, BOOL* pfClosingBorderStartsTrailing)
{
PLSDNODE plsdn;
long durTrailingDnode;
LSDCP dcpTrailingDnode;
BOOL fSuccessful;
LSDCP dcpDnode;
GROUPCHUNKITERATOR groupchunkiterator;
LSCP cpLim;
LSCP cpLimTrail;
LSSUBL* plssubl;
long durPrevClosingBorder = 0;
*pdurTrailing = 0;
*pdcpTrailing = 0;
*pplsdnStartTrailing = plsdnLast;
*pdcpStartTrailing = dcpLastDnode;
*pcDnodesTrailing = 0;
if (plsdnLast->dcp == dcpLastDnode)
cpLim = plsdnLast->cpLimOriginal;
else
cpLim = plsdnLast->cpFirst + dcpLastDnode;
CreateGroupChunkIterator(&groupchunkiterator,
CollectSublinesForTrailingArea, plsdnLast,
cpLim, fFalse);
plsdn = GetNextDnodeInGroupChunk(&groupchunkiterator, &fSuccessful);
while(fSuccessful)
{
*pplsdnStartTrailing = plsdn;
/* this procedure can be called before SetBreak so we should calculate
dcp of last dnode in chunk using cpLim */
if (plsdn->cpLimOriginal > cpLim)
dcpDnode = cpLim - plsdn->cpFirst;
else
dcpDnode = plsdn->dcp;
*pdcpStartTrailing = dcpDnode;
if (FIsDnodeReal(plsdn) && !FIsDnodeSplat(plsdn)) /* not a pen border or splat*/
{
if (IdObjFromDnode(plsdn) == iobjText) /* is text */
{
GetTrailInfoText(PdobjFromDnode(plsdn), dcpDnode,
&dcpTrailingDnode, &durTrailingDnode);
(*pcDnodesTrailing)++;
if (dcpTrailingDnode == 0)
{
break;
}
*pdurTrailing += durTrailingDnode;
*pdcpTrailing += dcpTrailingDnode;
*pdcpStartTrailing -= dcpTrailingDnode;
*pdurTrailing += durPrevClosingBorder;
durPrevClosingBorder = 0;
if (dcpDnode != dcpTrailingDnode)
break;
}
else
{
/* object which did not submit subline for trailing */
break;
}
}
else
{
/* border or splat */
if (FIsDnodeCloseBorder(plsdn))
{
durPrevClosingBorder = DurFromDnode(plsdn);
}
else
{
*pdurTrailing += DurFromDnode(plsdn);
}
*pdcpTrailing += plsdn->dcp;
}
plsdn = GetNextDnodeInGroupChunk(&groupchunkiterator, &fSuccessful);
}
*pfClosingBorderStartsTrailing = (durPrevClosingBorder != 0);
if (*pcDnodesTrailing == 0)
{
*pplsdnStartTrailingObject = plsdnLast;
*pdcpStartTrailingObject = dcpLastDnode;
}
else if (SublineFromDnode(*pplsdnStartTrailing) ==
SublineFromDnode(plsdnLast))
{
*pplsdnStartTrailingObject = *pplsdnStartTrailing;
*pdcpStartTrailingObject = *pdcpStartTrailing;
}
/* the last dnode we've checked was on the lower level */
else if (fSuccessful) /* and we actually stopped on it */
{
if ((*pplsdnStartTrailing)->dcp == *pdcpStartTrailing)
cpLimTrail = (*pplsdnStartTrailing)->cpLimOriginal;
else
cpLimTrail = (*pplsdnStartTrailing)->cpFirst + *pdcpStartTrailing;
plsdn = *pplsdnStartTrailing;
plssubl = SublineFromDnode(plsdn);
while (SublineFromDnode(plsdnLast) != plssubl)
{
plsdn = plssubl->plsdnUpTemp;
Assert(FIsLSDNODE(plsdn));
plssubl = SublineFromDnode(plsdn);
}
*pplsdnStartTrailingObject = plsdn;
if (plsdn->cpLimOriginal > cpLimTrail)
*pdcpStartTrailingObject = cpLimTrail - plsdn->cpFirst;
else
*pdcpStartTrailingObject = plsdn->dcp;
}
else
{
/* we went through all group chunk and the last dnode under investigation was on lower level */
/* plsdn is dnode before group chunk */
if (plsdn == NULL) /* there is nothing before group chunk */
{
*pplsdnStartTrailingObject = (SublineFromDnode(plsdnLast))->plsdnFirst;
}
else
{
*pplsdnStartTrailingObject = plsdn->plsdnNext;
}
Assert(FIsLSDNODE(*pplsdnStartTrailingObject));
*pdcpStartTrailingObject = 0;
}
DestroyGroupChunkIterator(&groupchunkiterator);
return lserrNone;
}
/* A L L O C C H U N K A R R A Y S */
/*----------------------------------------------------------------------------
%%Function: AllocChunkArrays
%%Contact: igorzv
Parameters:
plschunkcontext - (IN) chunk context
plscbk - (IN) callbacks
pols - (IN) pols for callbacks
plsiobjcontext - (IN) pointer to a table of methods
----------------------------------------------------------------------------*/
LSERR AllocChunkArrays(PLSCHUNKCONTEXT plschunkcontext, LSCBK* plscbk, POLS pols,
PLSIOBJCONTEXT plsiobjcontext)
{
plschunkcontext->pplsdnChunk = plscbk->pfnNewPtr(pols,
sizeof(PLSDNODE)*limAllDNodes);
plschunkcontext->pcont = plscbk->pfnNewPtr(pols,
sizeof(DWORD)*limAllDNodes);
plschunkcontext->locchnkCurrent.plschnk = plscbk->pfnNewPtr(pols,
sizeof(LSCHNKE)*limAllDNodes);
plschunkcontext->locchnkCurrent.ppointUvLoc = plscbk->pfnNewPtr(pols,
sizeof(POINTUV)*limAllDNodes);
plschunkcontext->pfNonTextExpandAfter = plscbk->pfnNewPtr(pols,
sizeof(BOOL)*limAllDNodes);
plschunkcontext->pplsdnNonText = plscbk->pfnNewPtr(pols,
sizeof(PLSDNODE)*limAllDNodes);
plschunkcontext->pdurOpenBorderBefore = plscbk->pfnNewPtr(pols,
sizeof(LONG)*limAllDNodes);
plschunkcontext->pdurCloseBorderAfter = plscbk->pfnNewPtr(pols,
sizeof(LONG)*limAllDNodes);
plschunkcontext->cchnkMax = limAllDNodes;
plschunkcontext->cNonTextMax = limAllDNodes;
plschunkcontext->plscbk = plscbk;
plschunkcontext->pols = pols;
plschunkcontext->plsiobjcontext = plsiobjcontext;
if (plschunkcontext->pplsdnChunk == NULL || plschunkcontext->pcont == NULL
|| plschunkcontext->locchnkCurrent.plschnk == NULL
|| plschunkcontext->locchnkCurrent.ppointUvLoc == NULL
|| plschunkcontext->pfNonTextExpandAfter == NULL
|| plschunkcontext->pplsdnNonText == NULL
||plschunkcontext->pdurOpenBorderBefore == NULL
||plschunkcontext->pdurCloseBorderAfter == NULL
)
{
return lserrOutOfMemory;
}
else
{
return lserrNone;
}
}
/* G E T U R P E N A T B E G I N I N G O F L A S T C H U N K */
/*----------------------------------------------------------------------------
%%Function: GetUrPenAtBeginingOfLastChunk
%%Contact: igorzv
Parameters:
plschunkcontext - (IN) chunk context
plsdnFirst - (IN) First dnode in a chunk (used for checks)
plsdnLast - (IN) last dnode in subline
point - (IN) point after last dnode
purPen - (OUT) ur before chunk
----------------------------------------------------------------------------*/
LSERR GetUrPenAtBeginingOfLastChunk(PLSCHUNKCONTEXT plschunkcontext,PLSDNODE plsdnFirst,
PLSDNODE plsdnLast, POINTUV* ppoint,
long* purPen)
{
/* chunk must be already collected and has plsdnFirst as the first element */
Assert(plschunkcontext->locchnkCurrent.clschnk != 0);
Assert(!plschunkcontext->FGroupChunk);
Assert(plschunkcontext->pplsdnChunk[0]== plsdnFirst);
if (plschunkcontext->locchnkCurrent.clschnk == 0 ||
plschunkcontext->FGroupChunk ||
plschunkcontext->pplsdnChunk[0]!= plsdnFirst)
return lserrInvalidParameter;
/* calculate point before the last dnode */
ppoint->u -= DurFromDnode(plsdnLast);
ppoint->v -= DvrFromDnode(plsdnLast);
/* go back until first dnode in chunk */
while(plsdnLast != plsdnFirst)
{
plsdnLast = plsdnLast->plsdnPrev;
Assert(FIsLSDNODE(plsdnLast));
ppoint->u -= DurFromDnode(plsdnLast);
ppoint->v -= DvrFromDnode(plsdnLast);
}
/* locate chunk */
if (!plschunkcontext->FLocationValid)
{
LocateChunk(plschunkcontext, plsdnFirst, LstflowFromDnode(plsdnFirst), ppoint);
}
*purPen = plschunkcontext->locchnkCurrent.lsfgi.urPen;
return lserrNone;
}
/* F I N D P O I N T O F F S E T */
/*----------------------------------------------------------------------------
%%Function: FindPointOffset
%%Contact: igorzv
Parameters:
plsdnFirst - (IN) dnode from the boundaries of which to calculate offset
lsdev - (IN) presentation or reference device
lstflowBase - (IN) text flow to use for calculation
Purpose - (IN) what sublines to take from a complex object
plsdnContainsPoint - (IN) dnode contains point
duInDnode, - (IN) offset in the dnode
pduOffset - (OUT) offset from the starting point
----------------------------------------------------------------------------*/
void FindPointOffset(PLSDNODE plsdnFirst, enum lsdevice lsdev,
LSTFLOW lstflowBase, COLLECTSUBLINES Purpose,
PLSDNODE plsdnContainsPoint, long duInDnode,
long* pduOffset)
{
PLSDNODE plsdnCurrent;
PLSSUBL plssubl;
LSTFLOW lstflow;
LSCP cpFirstDnode;
PLSSUBL* rgpsubl;
long cSublines;
long i;
long duOffsetSubline;
plssubl = SublineFromDnode(plsdnFirst);
lstflow = LstflowFromSubline(plssubl);
cpFirstDnode = plsdnContainsPoint->cpFirst;
*pduOffset = 0;
if (FParallelTflows(lstflow, lstflowBase))
{
for(plsdnCurrent = plsdnFirst;
plsdnCurrent->cpLimOriginal <= cpFirstDnode && (plsdnCurrent != plsdnContainsPoint);
/* second check is to catch situation when plsdnContainsPoint has dcp = 0 */
plsdnCurrent = plsdnCurrent->plsdnNext)
{
Assert(FIsLSDNODE(plsdnCurrent));
if (lsdev == lsdevReference)
{
*pduOffset += DurFromDnode(plsdnCurrent);
}
else
{
Assert(lsdev == lsdevPres);
*pduOffset += DupFromDnode(plsdnCurrent);
}
}
Assert(FIsLSDNODE(plsdnCurrent));
if (FIsDnodeReal(plsdnCurrent))
rgpsubl = GetSubmittedSublines(plsdnCurrent, Purpose);
else
rgpsubl = NULL;
if (rgpsubl == NULL)
{
Assert(plsdnCurrent == plsdnContainsPoint);
*pduOffset += duInDnode;
}
else
{
cSublines = GetNumberSubmittedSublines(plsdnCurrent);
/* if everything is correct we should always find subline in this loop,
check (i < cSublines) is just to avoid infinite loop and catch situation in a Assert */
for (i = 0; (i < cSublines) && !FDnodeInsideSubline(rgpsubl[i], plsdnContainsPoint); i++)
{
plssubl = rgpsubl[i];
Assert(FIsLSSUBL(plssubl));
for (plsdnCurrent = plssubl->plsdnFirst;
FDnodeBeforeCpLim(plsdnCurrent, plssubl->cpLim);
plsdnCurrent = plsdnCurrent->plsdnNext)
{
Assert(FIsLSDNODE(plsdnCurrent));
if (lsdev == lsdevReference)
{
*pduOffset += DurFromDnode(plsdnCurrent);
}
else
{
Assert(lsdev == lsdevPres);
*pduOffset += DupFromDnode(plsdnCurrent);
}
}
}
Assert(i != cSublines);
plssubl = rgpsubl[i];
Assert(FIsLSSUBL(plssubl));
FindPointOffset(plssubl->plsdnFirst, lsdev, lstflowBase,
Purpose, plsdnContainsPoint, duInDnode,
&duOffsetSubline);
*pduOffset += duOffsetSubline;
}
}
else
{
for(plsdnCurrent = plssubl->plsdnLast;
plsdnCurrent->cpFirst > cpFirstDnode && (plsdnCurrent != plsdnContainsPoint);
/* second check is to catch situation when plsdnContainsPoint has dcp = 0 */
plsdnCurrent = plsdnCurrent->plsdnPrev)
{
Assert(FIsLSDNODE(plsdnCurrent));
if (lsdev == lsdevReference)
{
*pduOffset += DurFromDnode(plsdnCurrent);
}
else
{
Assert(lsdev == lsdevPres);
*pduOffset += DupFromDnode(plsdnCurrent);
}
}
Assert(FIsLSDNODE(plsdnCurrent));
if (FIsDnodeReal(plsdnCurrent))
rgpsubl = GetSubmittedSublines(plsdnCurrent, Purpose);
else
rgpsubl = NULL;
if (rgpsubl == NULL)
{
Assert(plsdnCurrent == plsdnContainsPoint);
if (lsdev == lsdevReference)
{
*pduOffset += (DurFromDnode(plsdnCurrent) - duInDnode);
}
else
{
Assert(lsdev == lsdevPres);
*pduOffset += (DupFromDnode(plsdnCurrent) - duInDnode);
}
}
else
{
cSublines = GetNumberSubmittedSublines(plsdnCurrent);
/* if everything is correct we should always find subline in this loop,
check (i >= 0) is just to avoid infinite loop and catch situation in a Assert */
for (i = cSublines - 1; (i >= 0) && !FDnodeInsideSubline(rgpsubl[i], plsdnContainsPoint); i--)
{
plssubl = rgpsubl[i];
Assert(FIsLSSUBL(plssubl));
for (plsdnCurrent = plssubl->plsdnFirst;
FDnodeBeforeCpLim(plsdnCurrent, plssubl->cpLim);
plsdnCurrent = plsdnCurrent->plsdnNext)
{
Assert(FIsLSDNODE(plsdnCurrent));
if (lsdev == lsdevReference)
{
*pduOffset += DurFromDnode(plsdnCurrent);
}
else
{
Assert(lsdev == lsdevPres);
*pduOffset += DupFromDnode(plsdnCurrent);
}
}
}
Assert(i >= 0);
plssubl = rgpsubl[i];
Assert(FIsLSSUBL(plssubl));
FindPointOffset(plssubl->plsdnFirst, lsdev, lstflowBase,
Purpose, plsdnContainsPoint, duInDnode,
&duOffsetSubline);
*pduOffset += duOffsetSubline;
}
}
}
/* D I S P O S E C H U N K A R R A Y S */
/*----------------------------------------------------------------------------
%%Function: AllocChunkArrays
%%Contact: igorzv
Parameters:
plschunkcontext - (IN) chunk context
----------------------------------------------------------------------------*/
void DisposeChunkArrays(PLSCHUNKCONTEXT plschunkcontext)
{
if (plschunkcontext->pplsdnChunk != NULL)
plschunkcontext->plscbk->pfnDisposePtr(plschunkcontext->pols,
plschunkcontext->pplsdnChunk);
if (plschunkcontext->pcont != NULL)
plschunkcontext->plscbk->pfnDisposePtr(plschunkcontext->pols,
plschunkcontext->pcont);
if (plschunkcontext->locchnkCurrent.plschnk != NULL)
plschunkcontext->plscbk->pfnDisposePtr(plschunkcontext->pols,
plschunkcontext->locchnkCurrent.plschnk);
if (plschunkcontext->locchnkCurrent.ppointUvLoc != NULL)
plschunkcontext->plscbk->pfnDisposePtr(plschunkcontext->pols,
plschunkcontext->locchnkCurrent.ppointUvLoc);
if (plschunkcontext->pplsdnNonText != NULL)
plschunkcontext->plscbk->pfnDisposePtr(plschunkcontext->pols,
plschunkcontext->pplsdnNonText);
if (plschunkcontext->pfNonTextExpandAfter != NULL)
plschunkcontext->plscbk->pfnDisposePtr(plschunkcontext->pols,
plschunkcontext->pfNonTextExpandAfter);
if (plschunkcontext->pdurOpenBorderBefore != NULL)
plschunkcontext->plscbk->pfnDisposePtr(plschunkcontext->pols,
plschunkcontext->pdurOpenBorderBefore);
if (plschunkcontext->pdurCloseBorderAfter != NULL)
plschunkcontext->plscbk->pfnDisposePtr(plschunkcontext->pols,
plschunkcontext->pdurCloseBorderAfter);
}
/* S E T C H U N K A R R A Y S S I Z E */
/*----------------------------------------------------------------------------
%%Function: SetChunkArraysSize
%%Contact: igorzv
Parameters:
plschunkcontext - (IN) chunk context
cchnkMax - (IN) new max size for array
----------------------------------------------------------------------------*/
static LSERR SetChunkArraysSize(PLSCHUNKCONTEXT plschunkcontext, DWORD cchnkMax)
{
/* arrays pfNonTextExpandAfter and pplsdnNonText should not be touched here:
they are independable */
plschunkcontext->plscbk->pfnDisposePtr(plschunkcontext->pols,
plschunkcontext->pplsdnChunk);
plschunkcontext->plscbk->pfnDisposePtr(plschunkcontext->pols,
plschunkcontext->pcont);
plschunkcontext->plscbk->pfnDisposePtr(plschunkcontext->pols,
plschunkcontext->locchnkCurrent.plschnk);
plschunkcontext->plscbk->pfnDisposePtr(plschunkcontext->pols,
plschunkcontext->locchnkCurrent.ppointUvLoc);
plschunkcontext->plscbk->pfnDisposePtr(plschunkcontext->pols,
plschunkcontext->pdurOpenBorderBefore);
plschunkcontext->plscbk->pfnDisposePtr(plschunkcontext->pols,
plschunkcontext->pdurCloseBorderAfter);
/* create arrays for chunks */
plschunkcontext->pplsdnChunk = plschunkcontext->plscbk->pfnNewPtr(plschunkcontext->pols,
sizeof(PLSDNODE)*cchnkMax);
plschunkcontext->pcont = plschunkcontext->plscbk->pfnNewPtr(plschunkcontext->pols,
sizeof(DWORD)*cchnkMax);
plschunkcontext->locchnkCurrent.plschnk = plschunkcontext->plscbk->pfnNewPtr(plschunkcontext->pols,
sizeof(LSCHNKE)*cchnkMax);
plschunkcontext->locchnkCurrent.ppointUvLoc = plschunkcontext->plscbk->pfnNewPtr(plschunkcontext->pols,
sizeof(POINTUV)*cchnkMax);
plschunkcontext->pdurOpenBorderBefore = plschunkcontext->plscbk->pfnNewPtr(plschunkcontext->pols,
sizeof(LONG)*cchnkMax);
plschunkcontext->pdurCloseBorderAfter = plschunkcontext->plscbk->pfnNewPtr(plschunkcontext->pols,
sizeof(LONG)*cchnkMax);
if (plschunkcontext->pplsdnChunk == NULL || plschunkcontext->pcont == NULL
|| plschunkcontext->locchnkCurrent.plschnk == NULL
|| plschunkcontext->locchnkCurrent.ppointUvLoc == NULL
|| plschunkcontext->pdurOpenBorderBefore == NULL
|| plschunkcontext->pdurCloseBorderAfter == NULL
)
return lserrOutOfMemory;
plschunkcontext->cchnkMax = cchnkMax;
return lserrNone;
}
/* I N C R E A S E C H U N K A R R A Y S S I Z E */
/*----------------------------------------------------------------------------
%%Function: IncreaseChunkArrays
%%Contact: igorzv
Parameters:
plschunkcontext - (IN) chunk context
The difference from previous function is that we don't now final size
and going to increase size step by step
----------------------------------------------------------------------------*/
static LSERR IncreaseChunkArrays(PLSCHUNKCONTEXT plschunkcontext)
{
/* arrays pfNonTextExpandAfter and pplsdnNonText should not be touched here:
they are independable */
DWORD cchnkMax;
cchnkMax = plschunkcontext->cchnkMax + limAllDNodes;
/* create arrays for chunks */
plschunkcontext->pplsdnChunk = plschunkcontext->plscbk->pfnReallocPtr(plschunkcontext->pols,
plschunkcontext->pplsdnChunk,
sizeof(PLSDNODE)*cchnkMax);
plschunkcontext->pcont = plschunkcontext->plscbk->pfnReallocPtr(plschunkcontext->pols,
plschunkcontext->pcont,
sizeof(DWORD)*cchnkMax);
plschunkcontext->locchnkCurrent.plschnk = plschunkcontext->plscbk->pfnReallocPtr(plschunkcontext->pols,
plschunkcontext->locchnkCurrent.plschnk,
sizeof(LSCHNKE)*cchnkMax);
plschunkcontext->locchnkCurrent.ppointUvLoc = plschunkcontext->plscbk->pfnReallocPtr(plschunkcontext->pols,
plschunkcontext->locchnkCurrent.ppointUvLoc,
sizeof(POINTUV)*cchnkMax);
plschunkcontext->pdurOpenBorderBefore = plschunkcontext->plscbk->pfnReallocPtr(plschunkcontext->pols,
plschunkcontext->pdurOpenBorderBefore,
sizeof(LONG)*cchnkMax);
plschunkcontext->pdurCloseBorderAfter = plschunkcontext->plscbk->pfnReallocPtr(plschunkcontext->pols,
plschunkcontext->pdurCloseBorderAfter,
sizeof(LONG)*cchnkMax);
if (plschunkcontext->pplsdnChunk == NULL || plschunkcontext->pcont == NULL
|| plschunkcontext->locchnkCurrent.plschnk == NULL
|| plschunkcontext->locchnkCurrent.ppointUvLoc == NULL
|| plschunkcontext->pdurOpenBorderBefore == NULL
|| plschunkcontext->pdurCloseBorderAfter == NULL
)
return lserrOutOfMemory;
plschunkcontext->cchnkMax = cchnkMax;
return lserrNone;
}
/* D U P L I C A T E C H U N K C O N T E X T */
/*----------------------------------------------------------------------------
%%Function: DuplicateChunkContext
%%Contact: igorzv
Parameters:
plschunkcontextOld - (IN) chunk context to duplicate
pplschunkcontextNew - (OUT) new chunk context
----------------------------------------------------------------------------*/
LSERR DuplicateChunkContext(PLSCHUNKCONTEXT plschunkcontextOld,
PLSCHUNKCONTEXT* pplschunkcontextNew)
{
*pplschunkcontextNew = plschunkcontextOld->plscbk->pfnNewPtr(plschunkcontextOld->pols,
sizeof(LSCHUNKCONTEXT));
if (*pplschunkcontextNew == NULL)
return lserrOutOfMemory;
memcpy(*pplschunkcontextNew, plschunkcontextOld, sizeof(LSCHUNKCONTEXT));
/* but we need to use new arrays */
/* create arrays for chunks */
(*pplschunkcontextNew)->pplsdnChunk = (*pplschunkcontextNew)->plscbk->pfnNewPtr((*pplschunkcontextNew)->pols,
sizeof(PLSDNODE) * ((*pplschunkcontextNew)->cchnkMax));
(*pplschunkcontextNew)->pcont = (*pplschunkcontextNew)->plscbk->pfnNewPtr((*pplschunkcontextNew)->pols,
sizeof(DWORD) * ((*pplschunkcontextNew)->cchnkMax));
(*pplschunkcontextNew)->locchnkCurrent.plschnk =
(*pplschunkcontextNew)->plscbk->pfnNewPtr((*pplschunkcontextNew)->pols,
sizeof(LSCHNKE) * ((*pplschunkcontextNew)->cchnkMax));
(*pplschunkcontextNew)->locchnkCurrent.ppointUvLoc =
(*pplschunkcontextNew)->plscbk->pfnNewPtr((*pplschunkcontextNew)->pols,
sizeof(POINTUV) * ((*pplschunkcontextNew)->cchnkMax));
(*pplschunkcontextNew)->pfNonTextExpandAfter =
(*pplschunkcontextNew)->plscbk->pfnNewPtr((*pplschunkcontextNew)->pols,
sizeof(BOOL) * ((*pplschunkcontextNew)->cNonTextMax));
(*pplschunkcontextNew)->pplsdnNonText =
(*pplschunkcontextNew)->plscbk->pfnNewPtr((*pplschunkcontextNew)->pols,
sizeof(PLSDNODE) * ((*pplschunkcontextNew)->cNonTextMax));
(*pplschunkcontextNew)->pdurOpenBorderBefore =
(*pplschunkcontextNew)->plscbk->pfnNewPtr((*pplschunkcontextNew)->pols,
sizeof(LONG) * ((*pplschunkcontextNew)->cchnkMax));
(*pplschunkcontextNew)->pdurCloseBorderAfter =
(*pplschunkcontextNew)->plscbk->pfnNewPtr((*pplschunkcontextNew)->pols,
sizeof(LONG) * ((*pplschunkcontextNew)->cchnkMax));
if ((*pplschunkcontextNew)->pplsdnChunk == NULL || (*pplschunkcontextNew)->pcont == NULL
|| (*pplschunkcontextNew)->locchnkCurrent.plschnk == NULL
|| (*pplschunkcontextNew)->locchnkCurrent.ppointUvLoc == NULL
|| (*pplschunkcontextNew)->pfNonTextExpandAfter == NULL
|| (*pplschunkcontextNew)->pplsdnNonText == NULL
|| (*pplschunkcontextNew)->pdurOpenBorderBefore == NULL
|| (*pplschunkcontextNew)->pdurCloseBorderAfter == NULL
)
return lserrOutOfMemory;
/* copy valid parts of the arrays */
memcpy ((*pplschunkcontextNew)->pplsdnChunk, plschunkcontextOld->pplsdnChunk,
plschunkcontextOld->locchnkCurrent.clschnk * sizeof(PLSDNODE));
memcpy ((*pplschunkcontextNew)->pcont, plschunkcontextOld->pcont,
plschunkcontextOld->locchnkCurrent.clschnk * sizeof(DWORD));
memcpy ((*pplschunkcontextNew)->locchnkCurrent.plschnk, plschunkcontextOld->locchnkCurrent.plschnk,
plschunkcontextOld->locchnkCurrent.clschnk * sizeof(LSCHNKE));
memcpy ((*pplschunkcontextNew)->locchnkCurrent.ppointUvLoc, plschunkcontextOld->locchnkCurrent.ppointUvLoc,
plschunkcontextOld->locchnkCurrent.clschnk * sizeof(POINTUV));
memcpy ((*pplschunkcontextNew)->pfNonTextExpandAfter, plschunkcontextOld->pfNonTextExpandAfter,
plschunkcontextOld->cNonTextMax * sizeof(BOOL));
memcpy ((*pplschunkcontextNew)->pplsdnNonText, plschunkcontextOld->pplsdnNonText,
plschunkcontextOld->cNonTextMax * sizeof(PLSDNODE));
memcpy ((*pplschunkcontextNew)->pdurOpenBorderBefore, plschunkcontextOld->pdurOpenBorderBefore,
plschunkcontextOld->locchnkCurrent.clschnk * sizeof(LONG));
memcpy ((*pplschunkcontextNew)->pdurCloseBorderAfter, plschunkcontextOld->pdurCloseBorderAfter,
plschunkcontextOld->locchnkCurrent.clschnk * sizeof(LONG));
return lserrNone;
}
/* D E S T R O Y C H U N K C O N T E X T */
/*----------------------------------------------------------------------------
%%Function: DestroyChunkContext
%%Contact: igorzv
Parameters:
plschunkcontext - (IN) chunk context to destroy
----------------------------------------------------------------------------*/
void DestroyChunkContext(PLSCHUNKCONTEXT plschunkcontext)
{
POLS pols = plschunkcontext->pols;
LSCBK* plscbk = plschunkcontext->plscbk;
DisposeChunkArrays(plschunkcontext);
DebugMemset(plschunkcontext, 0xE9, sizeof(LSCHUNKCONTEXT));
plscbk->pfnDisposePtr(pols, plschunkcontext);
}
/* I N C R E A S E G R O U P C H U N K N O N T E X T A R R A Y S S I Z E */
/*----------------------------------------------------------------------------
%%Function: SetGroupChunkNonTextArraysSize
%%Contact: igorzv
Parameters:
plschunkcontext - (IN) chunk context
The difference from previous function is that we don't now final size
and going to increase size step by step
----------------------------------------------------------------------------*/
static LSERR IncreaseGroupChunkNonTextArrays(PLSCHUNKCONTEXT plschunkcontext)
{
DWORD cNonTextMax;
cNonTextMax = plschunkcontext->cNonTextMax + limAllDNodes;
/* create arrays for chunks */
plschunkcontext->pplsdnNonText = plschunkcontext->plscbk->pfnReallocPtr(plschunkcontext->pols,
plschunkcontext->pplsdnNonText,
sizeof(PLSDNODE)*cNonTextMax);
plschunkcontext->pfNonTextExpandAfter = plschunkcontext->plscbk->pfnReallocPtr(plschunkcontext->pols,
plschunkcontext->pfNonTextExpandAfter,
sizeof(BOOL)*cNonTextMax);
if (plschunkcontext->pplsdnNonText == NULL || plschunkcontext->pfNonTextExpandAfter == NULL)
return lserrOutOfMemory;
plschunkcontext->cNonTextMax = cNonTextMax;
return lserrNone;
}