1940 lines
58 KiB
C
1940 lines
58 KiB
C
#include <limits.h>
|
|
#include "lsmem.h" /* memset() */
|
|
|
|
|
|
#include "break.h"
|
|
#include "dnutils.h"
|
|
#include "iobj.h"
|
|
#include "iobjln.h"
|
|
#include "lsc.h"
|
|
#include "lschp.h"
|
|
#include "lscrline.h"
|
|
#include "lsdevres.h"
|
|
#include "lskysr.h"
|
|
#include "lsffi.h"
|
|
#include "lsidefs.h"
|
|
#include "lsline.h"
|
|
#include "lsfetch.h"
|
|
#include "lstext.h"
|
|
#include "prepdisp.h"
|
|
#include "tlpr.h"
|
|
#include "qheap.h"
|
|
#include "sublutil.h"
|
|
#include "zqfromza.h"
|
|
#include "lscfmtfl.h"
|
|
#include "limqmem.h"
|
|
#include "ntiman.h"
|
|
|
|
|
|
|
|
typedef struct
|
|
{
|
|
long urLeft;
|
|
BOOL fAutoDecimalTab;
|
|
long durAutoDecimalTab;
|
|
LSCP cpFirstVis;
|
|
BOOL fAutonumber;
|
|
BOOL fStopped;
|
|
BOOL fYsrChangeAfter;
|
|
WCHAR wchYsr; /* we need memory to keep wchYsr for kysrChangeAfter */
|
|
|
|
} LINEGEOMETRY;
|
|
|
|
static LSERR CreateLineCore(PLSC, /* IN: ptr to line services context */
|
|
LSCP, /* IN: starting cp in line */
|
|
long, /* IN: column width in twips */
|
|
const BREAKREC*, /* IN: previous line's break records */
|
|
DWORD, /* IN: number of previous line's break records */
|
|
DWORD, /* IN: size of the array of current line's break records */
|
|
BREAKREC*, /* OUT: current line's break records */
|
|
DWORD*, /* OUT: actual number of current line's break records */
|
|
LSLINFO*, /* OUT: visible line info to fill in */
|
|
PLSLINE*, /* OUT: ptr to line opaque to client */
|
|
BOOL*); /* OUT fSuccessful: false means insufficient fetch */
|
|
|
|
static BOOL FRoundingOK(void);
|
|
static LSERR CannotCreateLine(PLSLINE*, /* IN: ponter to a line structure to be deleted */
|
|
LSERR); /* IN: code of an error */
|
|
|
|
static LSERR ErrReleasePreFetchedRun (PLSC, /* IN: ptr to line services context */
|
|
PLSRUN, /* IN: ponter to a run structure to be deleted */
|
|
LSERR); /* IN: code of an error */
|
|
|
|
static LSERR EndFormatting(PLSC, /* IN: ptr to line services context */
|
|
enum endres, /* IN: type of line ending to put in lslinfo */
|
|
LSCP, /* IN: cpLim to put in lslinfo */
|
|
LSDCP, /* IN: dcpDepend to put in lslinfo*/
|
|
LSLINFO*); /* OUT: lslinfo to fill in, output of LsCreateLine*/
|
|
static LSERR FiniFormatGeneralCase (
|
|
PLSC, /* IN: ptr to line services context */
|
|
const BREAKREC*,/* IN: input array of break records */
|
|
DWORD, /* IN: number of records in input array */
|
|
DWORD, /* IN: size of the output array */
|
|
BREAKREC*, /* OUT: output array of break records */
|
|
DWORD*, /* OUT:actual number of records in array*/
|
|
LSLINFO*, /* OUT: lslinfo to fill in, output of LsCreateLine*/
|
|
BOOL*); /* OUT fSuccessful: false means insufficient fetch */
|
|
|
|
static LSERR FiniEndLine(PLSC, /* IN: ptr to line services context */
|
|
ENDRES, /* IN: how the line ended */
|
|
LSCP /* IN: cpLim of a line as a result of breaking,
|
|
can be changed in this procedure*/,
|
|
LSDCP, /* IN: dcpDepend (amount of characters after breaking point
|
|
that has participated in breaking decision)
|
|
can be changed in this procedure */
|
|
LSLINFO*); /* OUT: lslinfo to fill in, output of LsCreateLine*/
|
|
|
|
static LSERR FetchUntilVisible(
|
|
PLSC, /* IN: ptr to line services context */
|
|
LSPAP*, /* IN/OUT current lspap before and after */
|
|
LSCP*, /* IN/OUT current cp before and after */
|
|
LSFRUN*, /* IN/OUT current lsfrun before and after */
|
|
PLSCHP, /* IN/OUT current lschp before and after */
|
|
BOOL*, /* OUT fStopped: procedure stopped fetching because has not been allowed
|
|
to go across paragraph boundaries (result CheckPara Boundaries) */
|
|
BOOL*); /* OUT fNewPara: procedure crossed paragraph boundaries */
|
|
|
|
static LSERR InitTextParams(PLSC, /* IN: ptr to line services context */
|
|
LSCP, /* IN: cp to start fetch */
|
|
long, /* IN: duaColumn */
|
|
LSFRUN*, /* OUT: lsfrun of the first run */
|
|
PLSCHP, /* OUT: lsfrun of the first run */
|
|
LINEGEOMETRY*); /* OUT: set of flags and parameters about a line */
|
|
|
|
static LSERR FiniAuto(PLSC , /* IN: ptr to line services context */
|
|
BOOL , /* IN: fAutonumber */
|
|
BOOL , /* IN: fAutoDecimalTab */
|
|
PLSFRUN , /* IN: first run of the main text */
|
|
long, /* IN: durAutoDecimalTab */
|
|
const BREAKREC*, /* IN: input array of break records */
|
|
DWORD, /* IN: number of records in input array */
|
|
DWORD, /* IN: size of the output array */
|
|
BREAKREC*, /* OUT: output array of break records */
|
|
DWORD*, /* OUT:actual number of records in array*/
|
|
LSLINFO*, /* OUT: lslinfo to fill in, output of LsCreateLine*/
|
|
BOOL*); /* OUT fSuccessful: false means insufficient fetch */
|
|
|
|
static LSERR InitCurLine(PLSC plsc, /* IN: ptr to line services context */
|
|
LSCP cpFirst); /* IN: first cp in al line */
|
|
|
|
static LSERR RemoveLineObjects(PLSLINE plsline); /* IN: ponter to a line structure */
|
|
|
|
static LSERR GetYsrChangeAfterRun(
|
|
PLSC plsc, /* IN: ptr to line services context */
|
|
LSCP cp, /* IN: cp to start fetch */
|
|
BOOL* pfYsrChangeAfter, /* OUT: is it hyphenation of the previous line */
|
|
PLSFRUN plsfrun, /* OUT: lsfrun of modified first run */
|
|
PLSCHP plschp, /* OUT: lschp of modified first run */
|
|
LINEGEOMETRY*); /* OUT: to put wchYsr */
|
|
|
|
static LSERR FillTextParams(
|
|
PLSC plsc, /* IN: ptr to line services context */
|
|
LSCP cp, /* IN: cp to start fetch */
|
|
long duaCol, /* IN: duaColumn */
|
|
PLSPAP plspap, /* IN: paragraph properties */
|
|
BOOL fFirstLineInPara, /* IN: flag fFirstLineInPara */
|
|
BOOL fStopped, /* IN: flag fStopped */
|
|
LINEGEOMETRY*); /* OUT: set of flags and parameters about a line */
|
|
|
|
static LSERR FiniChangeAfter(
|
|
PLSC plsc, /* IN: ptr to line services context */
|
|
LSFRUN* plsfrun, /* IN: lsfrun of modified first run */
|
|
const BREAKREC*, /* IN: input array of break records */
|
|
DWORD, /* IN: number of records in input array */
|
|
DWORD, /* IN: size of the output array */
|
|
BREAKREC*, /* OUT: output array of break records */
|
|
DWORD*, /* OUT:actual number of records in array*/
|
|
LSLINFO*, /* OUT: lslinfo to fill in, output of LsCreateLine*/
|
|
BOOL*); /* OUT fSuccessful: false means insufficient fetch */
|
|
|
|
|
|
|
|
|
|
|
|
/* L I M R G */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: LimRg
|
|
%%Contact: lenoxb
|
|
|
|
Returns # of elements in an array.
|
|
----------------------------------------------------------------------------*/
|
|
#define LimRg(rg) (sizeof(rg)/sizeof((rg)[0]))
|
|
|
|
|
|
|
|
|
|
|
|
#define fFmiAdvancedFormatting (fFmiPunctStartLine | fFmiHangingPunct)
|
|
|
|
|
|
#define FBreakJustSimple(lsbrj) (lsbrj == lsbrjBreakJustify || lsbrj == lsbrjBreakThenSqueeze)
|
|
|
|
#define FAdvancedTypographyEnabled(plsc, cbreakrec) \
|
|
(FNominalToIdealBecauseOfParagraphProperties(plsc->grpfManager, \
|
|
plsc->lsadjustcontext.lskj) || \
|
|
!FBreakJustSimple((plsc)->lsadjustcontext.lsbrj) ||\
|
|
cbreakrec != 0 \
|
|
)
|
|
|
|
#define fFmiSpecialSpaceBreaking (fFmiWrapTrailingSpaces | fFmiWrapAllSpaces)
|
|
|
|
#define fFmiQuickBreakProhibited (fFmiSpecialSpaceBreaking | fFmiDoHyphenation)
|
|
|
|
/* F T R Y Q U I C K B R E A K */
|
|
/*----------------------------------------------------------------------------
|
|
%%Macro: FTryQuickBreak
|
|
%%Contact: igorzv
|
|
|
|
"Returns" fTrue when the formatter flags indicate that it it may be
|
|
possible to use QuickBreakText() instead of the more expensive
|
|
BreakGeneralCase().
|
|
----------------------------------------------------------------------------*/
|
|
#define FTryQuickBreak(plsc) ((((plsc)->grpfManager & fFmiQuickBreakProhibited) == 0) && \
|
|
((plsc)->lMarginIncreaseCoefficient == LONG_MIN) \
|
|
)
|
|
|
|
|
|
#define GetMainSubline(plsc) \
|
|
(Assert(FWorkWithCurrentLine(plsc)),\
|
|
&((plsc)->plslineCur->lssubl))
|
|
|
|
#define FPapInconsistent(plspap) \
|
|
((((plspap)->lsbrj == lsbrjBreakJustify || \
|
|
(plspap)->lsbrj == lsbrjBreakWithCompJustify) \
|
|
&& (plspap)->uaRightBreak < uLsInfiniteRM \
|
|
&& (plspap)->uaRightBreak != (plspap)->uaRightJustify) \
|
|
|| ((plspap)->lsbrj == lsbrjBreakThenExpand \
|
|
&& (plspap)->uaRightBreak < (plspap)->uaRightJustify) \
|
|
|| ((plspap)->lsbrj == lsbrjBreakThenSqueeze \
|
|
&& (plspap)->uaRightBreak > (plspap)->uaRightJustify) \
|
|
|| ((plspap)->lsbrj != lsbrjBreakWithCompJustify \
|
|
&& (plspap)->grpf & fFmiHangingPunct) \
|
|
|| ((plspap)->lsbrj == lsbrjBreakWithCompJustify \
|
|
&& (plspap)->lskj == lskjFullGlyphs))
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/* L S C R E A T E L I N E */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: LsCreateLine
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) ptr to line services context
|
|
cpFirst - (IN) starting cp in line
|
|
duaColumn - (IN) column width in twips
|
|
pbreakrecPrev - (IN) previous line's break records
|
|
breakrecMacPrev - (IN) number of previous line's break records
|
|
breakrecMaxCurrent- (IN) size of the array of current line's break records
|
|
pbreakrecCurrent- (OUT) current line's break records
|
|
pbreakrecMacCurrent-(OUT) actual number of current line's break records
|
|
plsinfo - (OUT) visible line info to fill in
|
|
pplsline - (OUT) ptr to line opaque to client
|
|
|
|
An exported LineServices API.
|
|
----------------------------------------------------------------------------*/
|
|
|
|
LSERR WINAPI LsCreateLine(PLSC plsc,
|
|
LSCP cpFirst,
|
|
long duaColumn,
|
|
const BREAKREC* pbreakrecPrev,
|
|
DWORD breakrecMacPrev,
|
|
DWORD breakrecMaxCurrent,
|
|
BREAKREC* pbreakrecCurrent,
|
|
DWORD* pbreakrecMacCurrent,
|
|
LSLINFO* plslinfo,
|
|
PLSLINE* pplsline)
|
|
{
|
|
|
|
|
|
LSERR lserr;
|
|
BOOL fSuccessful;
|
|
|
|
|
|
/* Check parameters and enviroment */
|
|
|
|
|
|
Assert(FRoundingOK());
|
|
|
|
if (plslinfo == NULL || pplsline == NULL || pbreakrecMacCurrent == NULL)
|
|
return lserrNullOutputParameter;
|
|
|
|
*pplsline = NULL;
|
|
*pbreakrecMacCurrent = 0; /* it's very important to initialize number of break records
|
|
because for example quick break doesn't work with break records */
|
|
|
|
if (!FIsLSC(plsc))
|
|
return lserrInvalidContext;
|
|
|
|
if (plsc->lsstate != LsStateFree)
|
|
return lserrContextInUse;
|
|
|
|
Assert(FIsLsContextValid(plsc));
|
|
|
|
if (pbreakrecPrev == NULL && breakrecMacPrev != 0)
|
|
return lserrInvalidParameter;
|
|
|
|
if (pbreakrecCurrent == NULL && breakrecMaxCurrent != 0)
|
|
return lserrInvalidParameter;
|
|
|
|
if (duaColumn < 0)
|
|
return lserrInvalidParameter;
|
|
|
|
if (duaColumn > uLsInfiniteRM)
|
|
duaColumn = uLsInfiniteRM;
|
|
|
|
/* if we have current line we must prepare it for display before creating of new line */
|
|
/* can change context. We've delayed this untill last moment because of optimisation reasons */
|
|
if (plsc->plslineCur != NULL)
|
|
{
|
|
lserr = PrepareLineForDisplayProc(plsc->plslineCur);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
plsc->plslineCur = NULL;
|
|
}
|
|
|
|
plsc->lMarginIncreaseCoefficient = LONG_MIN;
|
|
|
|
do /* loop allowing change of exceeded right margin if it's not sufficient */
|
|
{
|
|
lserr = CreateLineCore(plsc, cpFirst, duaColumn, pbreakrecPrev, breakrecMacPrev,
|
|
breakrecMaxCurrent, pbreakrecCurrent, pbreakrecMacCurrent,
|
|
plslinfo, pplsline, &fSuccessful);
|
|
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
if (!fSuccessful)
|
|
{ /* coefficient has not been sufficient before so increase it */
|
|
if (plsc->lMarginIncreaseCoefficient == LONG_MIN)
|
|
plsc->lMarginIncreaseCoefficient = 1;
|
|
else
|
|
{
|
|
if (plsc->lMarginIncreaseCoefficient >= uLsInfiniteRM / 2 )
|
|
plsc->lMarginIncreaseCoefficient = uLsInfiniteRM;
|
|
else
|
|
plsc->lMarginIncreaseCoefficient *= 2;
|
|
}
|
|
}
|
|
}
|
|
while (!fSuccessful);
|
|
|
|
|
|
#ifdef DEBUG
|
|
#ifdef LSTEST_GETMINDUR
|
|
|
|
/* Test LsGetMinDurBreaks () */
|
|
|
|
if ((lserr == lserrNone) && (plslinfo->endr != endrNormal) &&
|
|
(plslinfo->endr != endrHyphenated) && (! (plsc->grpfManager & fFmiDoHyphenation)) )
|
|
{
|
|
/* Line was ended with hard break / stopped */
|
|
|
|
long durMinInclTrail;
|
|
long durMinExclTrail;
|
|
|
|
lserr = LsGetMinDurBreaks ( plsc, *pplsline, &durMinInclTrail,
|
|
&durMinExclTrail );
|
|
};
|
|
|
|
#endif /* LSTEST_GETMINDUR */
|
|
#endif /* DEBUG */
|
|
|
|
|
|
return lserr;
|
|
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/* C R E A T E L I N E C O R E*/
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: CreateLineCore
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) ptr to line services context
|
|
cpFirst - (IN) starting cp in line
|
|
duaColumn - (IN) column width in twips
|
|
pbreakrecPrev - (IN) previous line's break records
|
|
breakrecMacPrev - (IN) number of previous line's break records
|
|
breakrecMaxCurrent- (IN) size of the array of current line's break records
|
|
pbreakrecCurrent- (OUT) current line's break records
|
|
pbreakrecMacCurrent-(OUT) actual number of current line's break records
|
|
plsinfo - (OUT) visible line info to fill in
|
|
pplsline - (OUT) ptr to line opaque to client
|
|
pfSuccessful - (OUT) fSuccessful: false means insufficient fetch
|
|
|
|
Internal procedure organized to handle error in choosing extended right margin
|
|
----------------------------------------------------------------------------*/
|
|
|
|
static LSERR CreateLineCore(PLSC plsc,
|
|
LSCP cpFirst,
|
|
long duaColumn,
|
|
const BREAKREC* pbreakrecPrev,
|
|
DWORD breakrecMacPrev,
|
|
DWORD breakrecMaxCurrent,
|
|
BREAKREC* pbreakrecCurrent,
|
|
DWORD* pbreakrecMacCurrent,
|
|
LSLINFO* plslinfo,
|
|
PLSLINE* pplsline,
|
|
BOOL* pfSuccessful)
|
|
{
|
|
|
|
|
|
PLSLINE plsline;
|
|
LINEGEOMETRY lgeom;
|
|
LSCHP lschp;
|
|
LSERR lserr;
|
|
BOOL fGeneral = fFalse;
|
|
BOOL fHardStop;
|
|
BOOL fSuccessfulQuickBreak;
|
|
LSCP cpLimLine;
|
|
LSDCP dcpDepend = 0;
|
|
LSFRUN lsfrun;
|
|
long urFinalPen;
|
|
long urColumnMaxIncreased;
|
|
ENDRES endr = endrNormal;
|
|
|
|
|
|
/*Initialization; */
|
|
|
|
*pfSuccessful = fTrue;
|
|
|
|
lsfrun.plschp = &lschp; /* we use the same area for lschips */
|
|
/* because we pasing pointer to const nobody can change it */
|
|
|
|
|
|
plsline= PvNewQuick(plsc->pqhLines, cbRep(struct lsline, rgplnobj, plsc->lsiobjcontext.iobjMac));
|
|
if (plsline == NULL)
|
|
return lserrOutOfMemory;
|
|
|
|
plsc->lsstate = LsStateFormatting; /* We start here forwating line. After this momemt we must
|
|
free context before return. We do this either in CannotCreateLine (error)
|
|
or EndFormatting (success) */
|
|
|
|
plsc->plslineCur = plsline;
|
|
*pplsline = plsline;
|
|
|
|
lserr = InitCurLine (plsc, cpFirst);
|
|
if (lserr != lserrNone)
|
|
return CannotCreateLine(pplsline, lserr);
|
|
|
|
|
|
/* check initial value of flags */
|
|
Assert(FAllSimpleText(plsc));
|
|
Assert(!FNonRealDnodeEncounted(plsc));
|
|
Assert(!FNonZeroDvpPosEncounted(plsc));
|
|
Assert(AggregatedDisplayFlags(plsc) == 0);
|
|
Assert(!FNominalToIdealEncounted(plsc));
|
|
Assert(!FForeignObjectEncounted(plsc));
|
|
Assert(!FTabEncounted(plsc));
|
|
Assert(!FNonLeftTabEncounted(plsc));
|
|
Assert(!FSubmittedSublineEncounted(plsc));
|
|
Assert(!FAutodecimalTabPresent(plsc));
|
|
|
|
plsc->cLinesActive += 1;
|
|
|
|
|
|
lserr = InitTextParams(plsc, cpFirst, duaColumn, &lsfrun, &lschp, &lgeom);
|
|
if (lserr != lserrNone)
|
|
return CannotCreateLine(pplsline,lserr);
|
|
|
|
/* prepare starting set for formatting */
|
|
InitFormattingContext(plsc, lgeom.urLeft, lgeom.cpFirstVis);
|
|
|
|
|
|
/* REVIEW comments */
|
|
if (lgeom.fStopped)
|
|
{
|
|
plsc->lsstate = LsStateBreaking; /* we now in a stage of breaking */
|
|
|
|
lserr = FiniEndLine(plsc, endrStopped, lgeom.cpFirstVis, 0, plslinfo);
|
|
if (lserr != lserrNone)
|
|
return CannotCreateLine(pplsline,lserr);
|
|
else
|
|
return lserrNone;
|
|
}
|
|
|
|
/* change first character because of hyphenation */
|
|
if (lgeom.fYsrChangeAfter)
|
|
{
|
|
Assert(!(lgeom.fAutonumber) || (lgeom.fAutoDecimalTab));
|
|
|
|
lserr = FiniChangeAfter(plsc, &lsfrun, pbreakrecPrev,
|
|
breakrecMacPrev, breakrecMaxCurrent,
|
|
pbreakrecCurrent, pbreakrecMacCurrent, plslinfo, pfSuccessful);
|
|
|
|
if (lserr != lserrNone || !*pfSuccessful)
|
|
return CannotCreateLine(pplsline, lserr);
|
|
else
|
|
return lserrNone;
|
|
}
|
|
/* important note to understand code flow : The situation below can happened
|
|
only for first line in a paragraph, the situation above never can happened
|
|
for such line. */
|
|
|
|
/* if autonumbering or auto-decimal tab */
|
|
if ((lgeom.fAutonumber) || (lgeom.fAutoDecimalTab))
|
|
{
|
|
Assert(!lgeom.fYsrChangeAfter);
|
|
|
|
TurnOffAllSimpleText(plsc);
|
|
|
|
/* we will release plsrun in FiniAuto */
|
|
|
|
lserr = FiniAuto(plsc, lgeom.fAutonumber, lgeom.fAutoDecimalTab, &lsfrun,
|
|
lgeom.durAutoDecimalTab, pbreakrecPrev,
|
|
breakrecMacPrev, breakrecMaxCurrent,
|
|
pbreakrecCurrent, pbreakrecMacCurrent, plslinfo, pfSuccessful);
|
|
|
|
if (lserr != lserrNone || !*pfSuccessful)
|
|
return CannotCreateLine(pplsline, lserr);
|
|
else
|
|
return lserrNone;
|
|
}
|
|
|
|
if (FAdvancedTypographyEnabled(plsc, breakrecMacPrev ))
|
|
{
|
|
/* we should release run here, in general procedure we will fetch it again */
|
|
if (!plsc->fDontReleaseRuns)
|
|
{
|
|
lserr = plsc->lscbk.pfnReleaseRun(plsc->pols, lsfrun.plsrun);
|
|
if (lserr != lserrNone)
|
|
return CannotCreateLine(pplsline,lserr);
|
|
}
|
|
|
|
lserr = FiniFormatGeneralCase(plsc, pbreakrecPrev,
|
|
breakrecMacPrev, breakrecMaxCurrent,
|
|
pbreakrecCurrent, pbreakrecMacCurrent, plslinfo, pfSuccessful);
|
|
|
|
if (lserr != lserrNone || !*pfSuccessful)
|
|
return CannotCreateLine(pplsline,lserr);
|
|
else
|
|
return lserrNone;
|
|
}
|
|
|
|
/* it is possible that width of column is negative: in such scase we'll
|
|
use another right margin*/
|
|
if (plsc->urRightMarginBreak <= 0 && plsc->lMarginIncreaseCoefficient == LONG_MIN)
|
|
plsc->lMarginIncreaseCoefficient = 1;
|
|
|
|
if (plsc->lMarginIncreaseCoefficient != LONG_MIN)
|
|
{
|
|
urColumnMaxIncreased = RightMarginIncreasing(plsc, plsc->urRightMarginBreak);
|
|
}
|
|
else
|
|
{
|
|
urColumnMaxIncreased = plsc->urRightMarginBreak;
|
|
}
|
|
|
|
lserr = QuickFormatting(plsc, &lsfrun, urColumnMaxIncreased,
|
|
&fGeneral, &fHardStop, &cpLimLine, &urFinalPen);
|
|
|
|
if (lserr != lserrNone)
|
|
return CannotCreateLine(pplsline,lserr);
|
|
|
|
|
|
if (fGeneral)
|
|
{
|
|
lserr = FiniFormatGeneralCase(plsc, pbreakrecPrev,
|
|
breakrecMacPrev, breakrecMaxCurrent,
|
|
pbreakrecCurrent, pbreakrecMacCurrent,
|
|
plslinfo, pfSuccessful);
|
|
|
|
if (lserr != lserrNone || !*pfSuccessful)
|
|
return CannotCreateLine(pplsline, lserr);
|
|
else
|
|
return lserrNone;
|
|
}
|
|
|
|
plsc->lsstate = LsStateBreaking; /* we now in a stage of breaking */
|
|
if (FTryQuickBreak(plsc))
|
|
{
|
|
lserr = BreakQuickCase(plsc, fHardStop, &dcpDepend, &cpLimLine,
|
|
&fSuccessfulQuickBreak, &endr);
|
|
if (lserr != lserrNone)
|
|
return CannotCreateLine(pplsline,lserr);
|
|
}
|
|
else
|
|
{
|
|
fSuccessfulQuickBreak = fFalse;
|
|
}
|
|
|
|
if (fSuccessfulQuickBreak)
|
|
{
|
|
if (endr == endrNormal || endr == endrAltEndPara ||
|
|
(endr == endrEndPara && !plsc->fLimSplat))
|
|
{
|
|
lserr = EndFormatting(plsc, endr, cpLimLine,
|
|
dcpDepend, plslinfo);
|
|
if (lserr != lserrNone)
|
|
return CannotCreateLine(pplsline,lserr);
|
|
else
|
|
return lserrNone;
|
|
}
|
|
else /* there is splat that is handled in FiniEndLine */
|
|
{
|
|
lserr = FiniEndLine(plsc, endr, cpLimLine, dcpDepend, plslinfo);
|
|
if (lserr != lserrNone)
|
|
return CannotCreateLine(pplsline, lserr);
|
|
else
|
|
return lserrNone;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* here we should use BreakGeneralCase */
|
|
lserr = BreakGeneralCase(plsc, fHardStop, breakrecMaxCurrent,
|
|
pbreakrecCurrent, pbreakrecMacCurrent,&dcpDepend,
|
|
&cpLimLine, &endr, pfSuccessful);
|
|
if (lserr != lserrNone || !*pfSuccessful)
|
|
return CannotCreateLine(pplsline,lserr);
|
|
|
|
lserr = FiniEndLine(plsc, endr, cpLimLine, dcpDepend, plslinfo);
|
|
if (lserr != lserrNone)
|
|
return CannotCreateLine(pplsline, lserr);
|
|
else
|
|
return lserrNone;
|
|
}
|
|
|
|
|
|
} /* end LsCreateLine */
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/* F I N I F O R M A T G E N E R A L C A S E*/
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: FiniFormatGeneralCase
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) ptr to line services context
|
|
pbreakrecPrev - (IN) previous line's break records
|
|
breakrecMacPrev - (IN) number of previous line's break records
|
|
breakrecMaxCurrent- (IN) size of the array of current line's break records
|
|
pbreakrecCurrent- (OUT) current line's break records
|
|
pbreakrecMacCurrent-(OUT) actual number of current line's break records
|
|
plsinfo - (OUT) visible line info to fill in
|
|
pfSuccessful - (OUT) fSuccessful: false means insufficient fetch
|
|
|
|
Formatting and breaking in a case when "quick formatting" is prohibit
|
|
----------------------------------------------------------------------------*/
|
|
static LSERR FiniFormatGeneralCase (PLSC plsc,
|
|
const BREAKREC* pbreakrecPrev,
|
|
DWORD breakrecMacPrev,
|
|
DWORD breakrecMaxCurrent,
|
|
BREAKREC* pbreakrecCurrent,
|
|
DWORD* pbreakrecMacCurrent,
|
|
LSLINFO* plslinfo, BOOL* pfSuccessful)
|
|
|
|
|
|
|
|
{
|
|
long urColumnMaxIncreased;
|
|
FMTRES fmtres;
|
|
LSERR lserr;
|
|
LSCP cpLimLine;
|
|
LSDCP dcpDepend;
|
|
PLSDNODE plsdnFirst, plsdnLast;
|
|
long urFinal;
|
|
ENDRES endr;
|
|
|
|
|
|
Assert(FIsLSC(plsc));
|
|
Assert(FFormattingAllowed(plsc));
|
|
Assert(plslinfo != NULL);
|
|
|
|
*pfSuccessful = fTrue;
|
|
|
|
if (plsc->lMarginIncreaseCoefficient == LONG_MIN) /* we are here for the first time */
|
|
{
|
|
/* increase right margin for nominal to ideal and compression */
|
|
if (!FBreakJustSimple(plsc->lsadjustcontext.lsbrj))
|
|
plsc->lMarginIncreaseCoefficient = 2;
|
|
else
|
|
plsc->lMarginIncreaseCoefficient = 1;
|
|
}
|
|
|
|
urColumnMaxIncreased = RightMarginIncreasing(plsc, plsc->urRightMarginBreak);
|
|
|
|
if (FNominalToIdealBecauseOfParagraphProperties(plsc->grpfManager,
|
|
plsc->lsadjustcontext.lskj))
|
|
TurnOnNominalToIdealEncounted(plsc);
|
|
|
|
if (breakrecMacPrev != 0)
|
|
lserr = FetchAppendEscResumeCore(plsc, urColumnMaxIncreased, NULL, 0,
|
|
pbreakrecPrev, breakrecMacPrev,
|
|
&fmtres, &cpLimLine, &plsdnFirst,
|
|
&plsdnLast, &urFinal);
|
|
else
|
|
lserr = FetchAppendEscCore(plsc, urColumnMaxIncreased, NULL, 0,
|
|
&fmtres, &cpLimLine, &plsdnFirst,
|
|
&plsdnLast, &urFinal);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
|
|
/* fetch append esc can be stopped because of tab */
|
|
/* so we have loop for tabs here */
|
|
while (fmtres == fmtrTab)
|
|
{
|
|
lserr = HandleTab(plsc);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
if (FBreakthroughLine(plsc))
|
|
{
|
|
urColumnMaxIncreased = RightMarginIncreasing(plsc, plsc->urRightMarginBreak);
|
|
}
|
|
|
|
lserr = FetchAppendEscCore(plsc, urColumnMaxIncreased, NULL, 0,
|
|
&fmtres, &cpLimLine, &plsdnFirst,
|
|
&plsdnLast, &urFinal);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
}
|
|
|
|
Assert(fmtres == fmtrStopped || fmtres == fmtrExceededMargin);
|
|
|
|
/* skip back pen dnodes */
|
|
while (plsdnLast != NULL && FIsDnodePen(plsdnLast))
|
|
{
|
|
plsdnLast = plsdnLast->plsdnPrev;
|
|
}
|
|
|
|
/* close last border */
|
|
if (FDnodeHasBorder(plsdnLast) && !FIsDnodeCloseBorder(plsdnLast))
|
|
{
|
|
lserr = CloseCurrentBorder(plsc);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
}
|
|
|
|
if (fmtres == fmtrExceededMargin
|
|
&& (urFinal <= plsc->urRightMarginBreak /* it's important for truncation to have <= here */
|
|
|| plsdnLast == NULL || FIsNotInContent(plsdnLast) /* this can happen if in nominal
|
|
to ideal (dcpMaxContext) we deleted everything
|
|
in content, but starting point
|
|
of content is already behind right margin */
|
|
)
|
|
)
|
|
{
|
|
/* return unsuccessful */
|
|
*pfSuccessful = fFalse;
|
|
return lserrNone;
|
|
}
|
|
else
|
|
{
|
|
plsc->lsstate = LsStateBreaking; /* we now in a stage of breaking */
|
|
lserr = BreakGeneralCase(plsc, (fmtres == fmtrStopped), breakrecMaxCurrent,
|
|
pbreakrecCurrent, pbreakrecMacCurrent,
|
|
&dcpDepend, &cpLimLine, &endr, pfSuccessful);
|
|
|
|
if (lserr != lserrNone || !*pfSuccessful)
|
|
return lserr;
|
|
|
|
/* because, we work with increased margin we can resolve pending tab only after break */
|
|
/* we use here that after breaking decision we set state after break point*/
|
|
lserr = HandleTab(plsc);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
return FiniEndLine(plsc, endr, cpLimLine, dcpDepend, plslinfo);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/* F I N I E N D L I N E */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: FiniEndLine
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) ptr to line services context
|
|
endr - (IN) how the line ended
|
|
cpLimLine - (IN) cpLim of a line as a result of breaking,
|
|
can be changed in this procedure
|
|
dcpDepend - (IN) amount of characters after breaking point
|
|
that has participated in breaking decision,
|
|
can be changed in this procedure
|
|
plsinfo - (OUT) visible line info to fill in
|
|
|
|
Handles splat, calculates heights, special effects
|
|
----------------------------------------------------------------------------*/
|
|
|
|
static LSERR FiniEndLine(PLSC plsc, ENDRES endr, LSCP cpLimLine,
|
|
LSDCP dcpDepend, LSLINFO* plslinfo)
|
|
|
|
{
|
|
LSLINFO* plslinfoState;
|
|
OBJDIM objdim;
|
|
LSERR lserr;
|
|
PLSLINE plsline;
|
|
BOOL fEmpty;
|
|
ENDRES endrOld;
|
|
|
|
Assert(FIsLSC(plsc));
|
|
Assert(plslinfo != NULL);
|
|
|
|
plsline = plsc->plslineCur;
|
|
plslinfoState = &(plsline->lslinfo);
|
|
|
|
|
|
endrOld = endr;
|
|
if (endr == endrEndPara && plsc->fLimSplat)
|
|
{
|
|
endr = endrEndParaSection;
|
|
cpLimLine++;
|
|
}
|
|
|
|
/* handling splat */
|
|
if (endr == endrEndColumn || endr == endrEndSection ||
|
|
endr == endrEndParaSection|| endr == endrEndPage)
|
|
{
|
|
|
|
if (plsc->grpfManager & fFmiVisiSplats)
|
|
{
|
|
switch (endr)
|
|
{
|
|
case endrEndColumn: plsline->kspl = ksplColumnBreak; break;
|
|
case endrEndSection: plsline->kspl = ksplSectionBreak; break;
|
|
case endrEndParaSection: plsline->kspl = ksplSectionBreak; break;
|
|
case endrEndPage: plsline->kspl = ksplPageBreak; break;
|
|
}
|
|
}
|
|
|
|
lserr = FIsSublineEmpty(GetMainSubline(plsc), &fEmpty);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
if (!fEmpty && (plsc->grpfManager & fFmiAllowSplatLine))
|
|
{
|
|
cpLimLine--;
|
|
dcpDepend++;
|
|
plsline->kspl = ksplNone;
|
|
if (endrOld == endrEndPara)
|
|
{
|
|
endr = endrEndPara;
|
|
}
|
|
else
|
|
{
|
|
endr = endrNormal;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Height calculation; */
|
|
|
|
lserr = GetObjDimSublineCore(GetMainSubline(plsc), &objdim);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
plslinfoState->dvrAscent = objdim.heightsRef.dvAscent;
|
|
plslinfoState->dvpAscent = objdim.heightsPres.dvAscent;
|
|
plslinfoState->dvrDescent = objdim.heightsRef.dvDescent;
|
|
plslinfoState->dvpDescent = objdim.heightsPres.dvDescent;
|
|
plslinfoState->dvpMultiLineHeight = objdim.heightsPres.dvMultiLineHeight;
|
|
plslinfoState->dvrMultiLineHeight = objdim.heightsRef.dvMultiLineHeight;
|
|
|
|
/* calculation plslinfoState->EffectsFlags*/
|
|
if (plslinfoState->EffectsFlags) /* some run with special effects happend during formating */
|
|
{
|
|
lserr = GetSpecialEffectsSublineCore(GetMainSubline(plsc),
|
|
&plsc->lsiobjcontext, &plslinfoState->EffectsFlags);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
}
|
|
|
|
|
|
return EndFormatting(plsc, endr, cpLimLine, dcpDepend, plslinfo);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* F I N I A U T O */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: FiniAuto
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) ptr to line services context
|
|
fAutonumber - (IN) does this line containes autonimber
|
|
fAutoDecimaltab - (IN) does this line containes autodecimal tab
|
|
plsfrunMainText - (IN) first run of main text
|
|
durAutoDecimalTab- (IN) tab stop for autodecimal tab
|
|
pbreakrecPrev - (IN) previous line's break records
|
|
breakrecMacPrev - (IN) number of previous line's break records
|
|
breakrecMaxCurrent- (IN) size of the array of current line's break records
|
|
pbreakrecCurrent- (OUT) current line's break records
|
|
pbreakrecMacCurrent-(OUT) actual number of current line's break records
|
|
plsinfo - (OUT) visible line info to fill in
|
|
pfSuccessful - (OUT) fSuccessful: false means insufficient fetch
|
|
|
|
Completes CreateLine logic for autonumbering and auto-decimal tab
|
|
----------------------------------------------------------------------------*/
|
|
static LSERR FiniAuto(
|
|
PLSC plsc,
|
|
BOOL fAutonumber,
|
|
BOOL fAutoDecimalTab,
|
|
PLSFRUN plsfrunMainText,
|
|
long durAutoDecimalTab,
|
|
const BREAKREC* pbreakrecPrev,
|
|
DWORD breakrecMacPrev,
|
|
DWORD breakrecMaxCurrent,
|
|
BREAKREC* pbreakrecCurrent,
|
|
DWORD* pbreakrecMacCurrent,
|
|
LSLINFO* plslinfo, BOOL* pfSuccessful)
|
|
{
|
|
LSERR lserr;
|
|
|
|
|
|
if (plsc->lMarginIncreaseCoefficient == LONG_MIN)
|
|
plsc->lMarginIncreaseCoefficient = 1;
|
|
|
|
if (fAutonumber) /*autonumbering */
|
|
{
|
|
lserr = FormatAnm(plsc, plsfrunMainText);
|
|
if (lserr != lserrNone)
|
|
{
|
|
return ErrReleasePreFetchedRun(plsc, plsfrunMainText->plsrun, lserr);
|
|
}
|
|
}
|
|
|
|
if (fAutoDecimalTab)
|
|
{
|
|
lserr = InitializeAutoDecTab(plsc, durAutoDecimalTab);
|
|
if (lserr != lserrNone)
|
|
{
|
|
return ErrReleasePreFetchedRun(plsc, plsfrunMainText->plsrun, lserr);
|
|
}
|
|
}
|
|
|
|
/* we should release run here, in general procedure we will fetch it again */
|
|
if (!plsc->fDontReleaseRuns)
|
|
{
|
|
lserr = plsc->lscbk.pfnReleaseRun(plsc->pols, plsfrunMainText->plsrun);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
}
|
|
|
|
return FiniFormatGeneralCase(plsc, pbreakrecPrev,
|
|
breakrecMacPrev, breakrecMaxCurrent,
|
|
pbreakrecCurrent, pbreakrecMacCurrent, plslinfo, pfSuccessful);
|
|
}
|
|
|
|
/* F I N I C H A N G E A F T E R */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: FiniChangeAfter
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) ptr to line services context
|
|
plsfrun, - (IN) lsfrun of modified first run
|
|
pbreakrecPrev - (IN) previous line's break records
|
|
breakrecMacPrev - (IN) number of previous line's break records
|
|
breakrecMaxCurrent- (IN) size of the array of current line's break records
|
|
pbreakrecCurrent- (OUT) current line's break records
|
|
pbreakrecMacCurrent-(OUT) actual number of current line's break records
|
|
plsinfo - (OUT) visible line info to fill in
|
|
pfSuccessful - (OUT) fSuccessful: false means insufficient fetch
|
|
|
|
Completes CreateLine logic for change after because of hyphenation
|
|
----------------------------------------------------------------------------*/
|
|
|
|
static LSERR FiniChangeAfter(PLSC plsc, LSFRUN* plsfrun, const BREAKREC* pbreakrecPrev,
|
|
DWORD breakrecMacPrev,
|
|
DWORD breakrecMaxCurrent,
|
|
BREAKREC* pbreakrecCurrent,
|
|
DWORD* pbreakrecMacCurrent,
|
|
LSLINFO* plslinfo, BOOL* pfSuccessful)
|
|
{
|
|
|
|
LSERR lserr;
|
|
FMTRES fmtres;
|
|
|
|
lserr = ProcessOneRun(plsc, plsc->urRightMarginBreak, plsfrun, NULL, 0, &fmtres);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
return FiniFormatGeneralCase(plsc, pbreakrecPrev,
|
|
breakrecMacPrev, breakrecMaxCurrent,
|
|
pbreakrecCurrent, pbreakrecMacCurrent, plslinfo, pfSuccessful);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/* E N D F O R M A T T I N G*/
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: EndFormatting
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) ptr to line services context
|
|
endres - (IN) how line ends
|
|
cpLimLine - (IN) cpLim of a line as a result of breaking,
|
|
can be changed in this procedure
|
|
dcpDepend - (IN) amount of characters after breaking point
|
|
that has participated in breaking decision,
|
|
can be changed in this procedure
|
|
plsinfo - (OUT) visible line info to fill in
|
|
|
|
Filles in lslinfo
|
|
----------------------------------------------------------------------------*/
|
|
|
|
|
|
static LSERR EndFormatting (PLSC plsc, enum endres endr,
|
|
LSCP cpLimLine, LSDCP dcpDepend, LSLINFO* plslinfo)
|
|
|
|
{
|
|
|
|
PLSLINE plsline = plsc->plslineCur;
|
|
LSLINFO* plslinfoContext = &(plsline->lslinfo);
|
|
|
|
|
|
Assert(FIsLSC(plsc));
|
|
Assert(plslinfo != NULL);
|
|
|
|
|
|
plslinfoContext->cpLim = cpLimLine;
|
|
plslinfoContext->dcpDepend = dcpDepend;
|
|
plslinfoContext->endr = endr;
|
|
|
|
|
|
*plslinfo = *plslinfoContext;
|
|
plsc->lsstate = LsStateFree; /* we always return through this procedure (in a case of success )
|
|
so we free context here */
|
|
return lserrNone;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
/* L S M O D I F Y L I N E H E I G H T */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: LsModifyLineHeight
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) ptr to line services context
|
|
psline - (IN) ptr to a line to be modified
|
|
dvpAbove - (IN) dvpAbove to set in plsline
|
|
dvpAscent - (IN) dvpAscent to set in plsline
|
|
dvpDescent - (IN) dvpDescent to set in plsline
|
|
dvpBelow - (IN) dvpBelow to set in plsline
|
|
|
|
An exported LineServices API.
|
|
Modifies heights in a plsline structure
|
|
----------------------------------------------------------------------------*/
|
|
LSERR WINAPI LsModifyLineHeight(PLSC plsc,
|
|
PLSLINE plsline,
|
|
long dvpAbove,
|
|
long dvpAscent,
|
|
long dvpDescent,
|
|
long dvpBelow)
|
|
{
|
|
if (!FIsLSC(plsc))
|
|
return lserrInvalidContext;
|
|
|
|
if (!FIsLSLINE(plsline))
|
|
return lserrInvalidLine;
|
|
|
|
if (plsline->lssubl.plsc != plsc)
|
|
return lserrMismatchLineContext;
|
|
|
|
if (plsc->lsstate != LsStateFree)
|
|
return lserrContextInUse;
|
|
|
|
|
|
|
|
plsline->dvpAbove = dvpAbove;
|
|
plsline->lslinfo.dvpAscent = dvpAscent;
|
|
plsline->lslinfo.dvpDescent = dvpDescent;
|
|
plsline->dvpBelow = dvpBelow;
|
|
return lserrNone;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
/* L S D E S T R O Y L I N E */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: LsDestroyLine
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) ptr to line services context
|
|
psline - (IN) ptr to a line to be deleted
|
|
|
|
An exported LineServices API.
|
|
Removed plsline structure , dnode list, line objects structures
|
|
----------------------------------------------------------------------------*/
|
|
|
|
LSERR WINAPI LsDestroyLine(PLSC plsc, /* IN: ptr to line services context */
|
|
PLSLINE plsline) /* IN: ptr to line -- opaque to client */
|
|
{
|
|
POLS pols;
|
|
LSERR lserrNew, lserr = lserrNone;
|
|
|
|
if (!FIsLSC(plsc))
|
|
return lserrInvalidContext;
|
|
|
|
if (!FIsLSLINE(plsline))
|
|
return lserrInvalidLine;
|
|
|
|
if (plsline->lssubl.plsc != plsc)
|
|
return lserrMismatchLineContext;
|
|
|
|
if (plsc->lsstate != LsStateFree)
|
|
return lserrContextInUse;
|
|
|
|
Assert(FIsLsContextValid(plsc));
|
|
Assert(plsc->cLinesActive > 0);
|
|
|
|
plsc->lsstate = LsStateDestroyingLine;
|
|
|
|
pols = plsc->pols;
|
|
|
|
/* optimization */
|
|
/* we use here that text doesn't have pinfosubl and DestroyDobj is actually empty for text */
|
|
if (!plsc->fDontReleaseRuns || !plsline->fAllSimpleText)
|
|
{
|
|
|
|
lserrNew = DestroyDnodeList(&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
|
|
plsline->lssubl.plsdnFirst, plsc->fDontReleaseRuns);
|
|
if (lserrNew != lserrNone && lserr == lserrNone)
|
|
lserr = lserrNew;
|
|
}
|
|
|
|
if (plsline == plsc->plslineCur)
|
|
plsc->plslineCur = NULL;
|
|
|
|
|
|
lserrNew = RemoveLineObjects(plsline);
|
|
if (lserrNew != lserrNone && lserr == lserrNone)
|
|
lserr = lserrNew;
|
|
|
|
/* flush heap of dnodes */
|
|
if (plsline->pqhAllDNodes != NULL)
|
|
FlushQuickHeap(plsline->pqhAllDNodes);
|
|
|
|
if (plsc->pqhAllDNodesRecycled != NULL)
|
|
DestroyQuickHeap(plsc->pqhAllDNodesRecycled);
|
|
|
|
/* recycle quick heap of dnodes */
|
|
plsc->pqhAllDNodesRecycled = plsline->pqhAllDNodes;
|
|
|
|
|
|
plsline->tag = tagInvalid;
|
|
DisposeQuickPv(plsc->pqhLines, plsline,
|
|
cbRep(struct lsline, rgplnobj, plsc->lsiobjcontext.iobjMac));
|
|
|
|
plsc->cLinesActive -= 1;
|
|
|
|
plsc->lsstate = LsStateFree;
|
|
return lserr;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/* L S G E T L I N E D U R */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: LsGetLineDur
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) LS context
|
|
plsline - (IN) ptr to a line
|
|
pdurInclTrail - (OUT) dur of line incl. trailing area
|
|
pdurExclTrail - (OUT) dur of line excl. trailing area
|
|
|
|
----------------------------------------------------------------------------*/
|
|
LSERR WINAPI LsGetLineDur (PLSC plsc, PLSLINE plsline,
|
|
long* pdurInclTrail, long* pdurExclTrail)
|
|
{
|
|
LSERR lserr;
|
|
|
|
if (!FIsLSC(plsc))
|
|
return lserrInvalidContext;
|
|
|
|
if (!FIsLSLINE(plsline))
|
|
return lserrInvalidLine;
|
|
|
|
if (plsline->lssubl.plsc != plsc)
|
|
return lserrMismatchLineContext;
|
|
|
|
if (plsc->lsstate != LsStateFree)
|
|
return lserrContextInUse;
|
|
|
|
Assert(FIsLsContextValid(plsc));
|
|
Assert(plsc->cLinesActive > 0);
|
|
|
|
/* check that the line is active */
|
|
if (plsline != plsc->plslineCur)
|
|
return lserrLineIsNotActive;
|
|
|
|
/* set breaking state */
|
|
plsc->lsstate = LsStateBreaking;
|
|
|
|
lserr = GetLineDurCore(plsc, pdurInclTrail, pdurExclTrail);
|
|
|
|
plsc->lsstate = LsStateFree;
|
|
|
|
return lserr;
|
|
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/* L S G E T M I N D U R B R E A K S */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: LsGetMinDurBreaks
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) LS context
|
|
plsline - (IN) ptr to a line
|
|
pdurMinInclTrail - (OUT) min dur between breaks including trailing area
|
|
pdurMinExclTrail - (OUT) min dur between breaks excluding trailing area
|
|
|
|
----------------------------------------------------------------------------*/
|
|
|
|
LSERR WINAPI LsGetMinDurBreaks (PLSC plsc, PLSLINE plsline,
|
|
long* pdurMinInclTrail, long* pdurMinExclTrail)
|
|
{
|
|
LSERR lserr;
|
|
|
|
if (!FIsLSC(plsc))
|
|
return lserrInvalidContext;
|
|
|
|
if (!FIsLSLINE(plsline))
|
|
return lserrInvalidLine;
|
|
|
|
if (plsline->lssubl.plsc != plsc)
|
|
return lserrMismatchLineContext;
|
|
|
|
if (plsc->lsstate != LsStateFree)
|
|
return lserrContextInUse;
|
|
|
|
Assert(FIsLsContextValid(plsc));
|
|
Assert(plsc->cLinesActive > 0);
|
|
|
|
/* check that the line is active */
|
|
if (plsline != plsc->plslineCur)
|
|
return lserrLineIsNotActive;
|
|
|
|
/* set breaking state */
|
|
plsc->lsstate = LsStateBreaking;
|
|
|
|
lserr = GetMinDurBreaksCore(plsc, pdurMinInclTrail, pdurMinExclTrail);
|
|
|
|
plsc->lsstate = LsStateFree;
|
|
|
|
return lserr;
|
|
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
#define grpfTextMask ( \
|
|
fFmiVisiCondHyphens | \
|
|
fFmiVisiParaMarks | \
|
|
fFmiVisiSpaces | \
|
|
fFmiVisiTabs | \
|
|
fFmiVisiBreaks | \
|
|
fFmiDoHyphenation | \
|
|
fFmiWrapTrailingSpaces | \
|
|
fFmiWrapAllSpaces | \
|
|
fFmiPunctStartLine | \
|
|
fFmiHangingPunct | \
|
|
fFmiApplyBreakingRules | \
|
|
fFmiFCheckTruncateBefore | \
|
|
fFmiDrawInCharCodes | \
|
|
fFmiSpacesInfluenceHeight | \
|
|
fFmiIndentChangesHyphenZone | \
|
|
fFmiNoPunctAfterAutoNumber | \
|
|
fFmiTreatHyphenAsRegular \
|
|
)
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/* I N I T T E X T P A R A M S */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: InitTextParams
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) ptr to line services context
|
|
cp, - (IN) cp to start fetch
|
|
duaCol - (IN) duaColumn
|
|
plsfrun - (IN) lsfrun of the first run
|
|
plschp - (OUT) lsfrun of the first run
|
|
plgeom - (OUT) set of flags and parameters about a line
|
|
|
|
|
|
LsCreateLine calls this function at the beginning of the line in order
|
|
to skip over vanished text, fetch an LSPAP, and invoke the text APIs
|
|
SetTextLineParams().
|
|
----------------------------------------------------------------------------*/
|
|
static LSERR InitTextParams(PLSC plsc, LSCP cp, long duaCol,
|
|
LSFRUN* plsfrun, PLSCHP plschp, LINEGEOMETRY* plgeom)
|
|
{
|
|
LSERR lserr;
|
|
LSPAP lspap;
|
|
POLS pols = plsc->pols;
|
|
BOOL fFirstLineInPara;
|
|
BOOL fHidden;
|
|
BOOL fStopped = fFalse;
|
|
BOOL fNoLinesParaBefore;
|
|
BOOL fNewPara;
|
|
|
|
plsfrun->lpwchRun = NULL;
|
|
plsfrun->plsrun = NULL;
|
|
plsfrun->cwchRun = 0;
|
|
|
|
plgeom->fYsrChangeAfter = fFalse;
|
|
|
|
Assert(cp >= 0);
|
|
|
|
lserr = plsc->lscbk.pfnFetchPap(pols, cp, &lspap);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
if (FPapInconsistent(&lspap))
|
|
return lserrInvalidPap;
|
|
|
|
/* N.B. lspap.cpFirstContent may be negative, which indicates
|
|
* "no content in this paragraph".
|
|
*/
|
|
|
|
fNoLinesParaBefore = lspap.cpFirstContent < 0 || cp <= lspap.cpFirstContent;
|
|
|
|
if (!fNoLinesParaBefore && (lspap.grpf & fFmiDoHyphenation))
|
|
{
|
|
lserr = GetYsrChangeAfterRun(plsc, cp, &plgeom->fYsrChangeAfter, plsfrun, plschp, plgeom);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
if (plgeom->fYsrChangeAfter)
|
|
{
|
|
fFirstLineInPara = fFalse;
|
|
fStopped = fFalse;
|
|
lserr = FillTextParams(plsc, cp, duaCol, &lspap, fFirstLineInPara,
|
|
fStopped, plgeom);
|
|
if (lserr != lserrNone)
|
|
return ErrReleasePreFetchedRun(plsc, plsfrun->plsrun, lserr);
|
|
else
|
|
return lserrNone;
|
|
}
|
|
}
|
|
|
|
lserr = plsc->lscbk.pfnFetchRun(pols, cp,&plsfrun->lpwchRun, &plsfrun->cwchRun,
|
|
&fHidden, plschp, &plsfrun->plsrun);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
|
|
if (fHidden) /* vanished text */
|
|
{
|
|
lserr = FetchUntilVisible(plsc, &lspap, &cp, plsfrun, plschp,
|
|
&fStopped, &fNewPara);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
if (fNewPara)
|
|
fNoLinesParaBefore = fTrue;
|
|
}
|
|
|
|
fFirstLineInPara = fNoLinesParaBefore && FBetween(lspap.cpFirstContent, 0, cp);
|
|
lserr = FillTextParams(plsc, cp, duaCol, &lspap, fFirstLineInPara,
|
|
fStopped, plgeom);
|
|
if (lserr != lserrNone)
|
|
return ErrReleasePreFetchedRun(plsc, plsfrun->plsrun, lserr);
|
|
else
|
|
return lserrNone;
|
|
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/* G E T Y S R C H A N G E A F T E R R U N */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: GetYsrChangeAfterRun
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) ptr to line services context
|
|
cp, - (IN) cp to start fetch
|
|
pfYsrChangeAfter (OUT) is it hyphenation of the previous line
|
|
plsfrun, (OUT) lsfrun of modified first run
|
|
plschp (OUT) lschp of modified first run
|
|
plsgeom (OUT) to put wchYsr
|
|
|
|
|
|
InitTextParams calls this procedure if there is a possibility
|
|
for previous line to be hyphenated.
|
|
If previous line has been hyphenated with ysr change after procedure returns
|
|
modified first run for a line
|
|
----------------------------------------------------------------------------*/
|
|
|
|
static LSERR GetYsrChangeAfterRun(PLSC plsc, LSCP cp, BOOL* pfYsrChangeAfter,
|
|
PLSFRUN plsfrun, PLSCHP plschp, LINEGEOMETRY* plgeom)
|
|
{
|
|
LSFRUN lsfrunPrev;
|
|
LSCHP lschpPrev;
|
|
BOOL fHidden;
|
|
LSERR lserr;
|
|
|
|
lsfrunPrev.plschp = &lschpPrev;
|
|
*pfYsrChangeAfter = fFalse;
|
|
|
|
/* Fetch run at cp-1 to handle ysrChangeAfter from previous line.
|
|
*/
|
|
lserr = plsc->lscbk.pfnFetchRun(plsc->pols, cp-1, &lsfrunPrev.lpwchRun,
|
|
&lsfrunPrev.cwchRun, &fHidden,
|
|
&lschpPrev, &lsfrunPrev.plsrun);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
/* previous run is hyphenated text */
|
|
if (!fHidden && ((lsfrunPrev.plschp)->idObj == idObjTextChp)
|
|
&& (lsfrunPrev.plschp)->fHyphen)
|
|
{
|
|
DWORD kysr;
|
|
WCHAR wchYsr;
|
|
Assert(lsfrunPrev.cwchRun == 1);
|
|
|
|
lserr = plsc->lscbk.pfnGetHyphenInfo(plsc->pols, lsfrunPrev.plsrun, &kysr, &wchYsr);
|
|
if (lserr != lserrNone)
|
|
return ErrReleasePreFetchedRun(plsc, lsfrunPrev.plsrun, lserr);
|
|
|
|
if ((kysr == kysrChangeAfter) &&
|
|
(wchYsr != 0))
|
|
{
|
|
lserr = plsc->lscbk.pfnFetchRun(plsc->pols, cp, &plsfrun->lpwchRun,
|
|
&plsfrun->cwchRun, &fHidden,
|
|
plschp, &plsfrun->plsrun);
|
|
if (lserr != lserrNone)
|
|
return ErrReleasePreFetchedRun(plsc, lsfrunPrev.plsrun, lserr);
|
|
|
|
if (!fHidden)
|
|
{
|
|
Assert((plsfrun->plschp)->idObj == idObjTextChp);
|
|
plgeom->wchYsr = wchYsr;
|
|
/* Synthesize a 1-byte run */
|
|
plsfrun->lpwchRun = &plgeom->wchYsr; /* here is the only reason to keep wchrChar in lgeom
|
|
we cann't use local memory to keep it */
|
|
plsfrun->cwchRun = 1;
|
|
plschp->fHyphen = kysrNil;
|
|
|
|
*pfYsrChangeAfter = fTrue;
|
|
}
|
|
else
|
|
{
|
|
if (!plsc->fDontReleaseRuns)
|
|
{
|
|
lserr = plsc->lscbk.pfnReleaseRun(plsc->pols, plsfrun->plsrun);
|
|
if (lserr != lserrNone)
|
|
return ErrReleasePreFetchedRun(plsc, lsfrunPrev.plsrun, lserr);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* Release run from previous line */
|
|
if (!plsc->fDontReleaseRuns)
|
|
{
|
|
|
|
lserr = plsc->lscbk.pfnReleaseRun(plsc->pols, lsfrunPrev.plsrun);
|
|
if (lserr != lserrNone)
|
|
return ErrReleasePreFetchedRun(plsc, plsfrun->plsrun, lserr);
|
|
}
|
|
return lserrNone;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/* F I L L T E X T P A R A M S */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: FillTextParamsTextParams
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) ptr to line services context
|
|
cp, - (IN) cp to start fetch
|
|
duaCol - (IN) duaColumn
|
|
plspap - (IN) paragraph properties
|
|
fFirstLineInPara- (IN) flag fFirstLineInPara
|
|
fStopped - (IN) flag fStopped
|
|
plgeom - (OUT) set of flags and parameters about a line
|
|
|
|
|
|
LsCreateLine calls this function at the beginning of the line in order
|
|
to skip over vanished text, fetch an LSPAP, and invoke the text APIs
|
|
SetTextLineParams().
|
|
----------------------------------------------------------------------------*/
|
|
|
|
static LSERR FillTextParams(PLSC plsc, LSCP cp, long duaCol, PLSPAP plspap,
|
|
BOOL fFirstLineInPara, BOOL fStopped, LINEGEOMETRY* plgeom)
|
|
{
|
|
LSERR lserr;
|
|
TLPR tlpr;
|
|
DWORD iobjText;
|
|
PILSOBJ pilsobjText;
|
|
PLNOBJ plnobjText;
|
|
long uaLeft;
|
|
PLSLINE plsline = plsc->plslineCur;
|
|
long duaColumnMaxBreak;
|
|
long duaColumnMaxJustify;
|
|
long urLeft;
|
|
|
|
/* Copy information from lspap to context current line and local for LsCreateLine structure lgeom */
|
|
|
|
uaLeft = plspap->uaLeft;
|
|
if (fFirstLineInPara)
|
|
uaLeft += plspap->duaIndent;
|
|
urLeft = UrFromUa(LstflowFromSubline(GetMainSubline(plsc)),
|
|
&plsc->lsdocinf.lsdevres, uaLeft);
|
|
|
|
|
|
/* line */
|
|
plsline->lslinfo.fFirstLineInPara = fFirstLineInPara;
|
|
plsline->lslinfo.cpFirstVis = cp;
|
|
plsline->lssubl.lstflow = plspap->lstflow;
|
|
|
|
if (duaCol != uLsInfiniteRM && plspap->uaRightBreak < uLsInfiniteRM
|
|
&& plspap->uaRightJustify < uLsInfiniteRM)
|
|
{
|
|
duaColumnMaxBreak = duaCol - plspap->uaRightBreak;
|
|
duaColumnMaxJustify = duaCol - plspap->uaRightJustify;
|
|
}
|
|
else{
|
|
if (duaCol == uLsInfiniteRM)
|
|
{
|
|
duaColumnMaxBreak = uLsInfiniteRM;
|
|
duaColumnMaxJustify = uLsInfiniteRM;
|
|
}
|
|
else
|
|
{
|
|
if (plspap->uaRightBreak >= uLsInfiniteRM)
|
|
duaColumnMaxBreak = uLsInfiniteRM;
|
|
else
|
|
duaColumnMaxBreak = duaCol - plspap->uaRightBreak;
|
|
if (plspap->uaRightJustify >= uLsInfiniteRM)
|
|
duaColumnMaxJustify = uLsInfiniteRM;
|
|
else
|
|
duaColumnMaxJustify = duaCol - plspap->uaRightJustify;
|
|
}
|
|
}
|
|
|
|
|
|
/* fill in context for adjustment */
|
|
SetLineLineContainsAutoNumber(plsc, (plspap->grpf & fFmiAnm) && fFirstLineInPara);
|
|
SetUnderlineTrailSpacesRM(plsc, plspap->grpf & fFmiUnderlineTrailSpacesRM);
|
|
SetForgetLastTabAlignment(plsc, plspap->grpf & fFmiForgetLastTabAlignment);
|
|
plsc->lsadjustcontext.lskj = plspap->lskj;
|
|
plsc->lsadjustcontext.lskalign = plspap->lskal;
|
|
plsc->lsadjustcontext.lsbrj = plspap->lsbrj;
|
|
plsc->lsadjustcontext.urLeftIndent = urLeft;
|
|
plsc->lsadjustcontext.urStartAutonumberingText =0;
|
|
plsc->lsadjustcontext.urStartMainText = urLeft; /* autonumber can change it later */
|
|
if (duaColumnMaxJustify != uLsInfiniteRM)
|
|
{
|
|
plsc->lsadjustcontext.urRightMarginJustify = UrFromUa(
|
|
LstflowFromSubline(GetMainSubline(plsc)),
|
|
&(plsc->lsdocinf.lsdevres), duaColumnMaxJustify);
|
|
}
|
|
else
|
|
{
|
|
plsc->lsadjustcontext.urRightMarginJustify = uLsInfiniteRM;
|
|
}
|
|
if (duaColumnMaxBreak != uLsInfiniteRM)
|
|
{
|
|
plsc->urRightMarginBreak = UrFromUa(LstflowFromSubline(GetMainSubline(plsc)),
|
|
&(plsc->lsdocinf.lsdevres), duaColumnMaxBreak);
|
|
}
|
|
else
|
|
{
|
|
plsc->urRightMarginBreak = uLsInfiniteRM;
|
|
}
|
|
plsc->fIgnoreSplatBreak = plspap->grpf & fFmiIgnoreSplatBreak;
|
|
plsc->grpfManager = plspap->grpf;
|
|
plsc->fLimSplat = plspap->grpf & fFmiLimSplat;
|
|
plsc->urHangingTab = UrFromUa(LstflowFromSubline(GetMainSubline(plsc)),
|
|
&(plsc->lsdocinf.lsdevres), plspap->uaLeft);
|
|
|
|
/* snap grid */
|
|
if (plspap->lskj == lskjSnapGrid)
|
|
{
|
|
if (duaCol != uLsInfiniteRM)
|
|
{
|
|
plsc->lsgridcontext.urColumn = UrFromUa(
|
|
LstflowFromSubline(GetMainSubline(plsc)),
|
|
&(plsc->lsdocinf.lsdevres), duaCol);
|
|
}
|
|
else
|
|
{
|
|
plsc->lsgridcontext.urColumn = uLsInfiniteRM;
|
|
}
|
|
}
|
|
|
|
/* lgeom */
|
|
plgeom->cpFirstVis = cp;
|
|
plgeom->urLeft = urLeft;
|
|
plgeom->fAutonumber = (plspap->grpf & fFmiAnm) && fFirstLineInPara;
|
|
if (plspap->grpf & fFmiAutoDecimalTab)
|
|
{
|
|
plgeom->fAutoDecimalTab = fTrue;
|
|
plgeom->durAutoDecimalTab = UrFromUa(LstflowFromSubline(GetMainSubline(plsc)),
|
|
&(plsc->lsdocinf.lsdevres), plspap->duaAutoDecimalTab);
|
|
}
|
|
else
|
|
{
|
|
plgeom->fAutoDecimalTab = fFalse;
|
|
plgeom->durAutoDecimalTab = LONG_MIN;
|
|
}
|
|
plgeom->fStopped = fStopped;
|
|
|
|
|
|
/* prepare tlpr for text */
|
|
|
|
tlpr.grpfText = (plspap->grpf & grpfTextMask);
|
|
tlpr.fSnapGrid = (plspap->lskj == lskjSnapGrid);
|
|
tlpr.duaHyphenationZone = plspap->duaHyphenationZone;
|
|
tlpr.lskeop = plspap->lskeop;
|
|
|
|
|
|
/* we know that here is the first place we need plnobjText and we are creating it */
|
|
iobjText = IobjTextFromLsc(&(plsc->lsiobjcontext));
|
|
Assert( PlnobjFromLsline(plsline,iobjText) == NULL);
|
|
pilsobjText = PilsobjFromLsc(&(plsc->lsiobjcontext), iobjText);
|
|
lserr = CreateLNObjText(pilsobjText, &(plsline->rgplnobj[iobjText]));
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
plnobjText = PlnobjFromLsline(plsline, iobjText);
|
|
|
|
lserr = SetTextLineParams(plnobjText, &tlpr);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
return lserrNone;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
/* F E T C H U N T I L V I S I B L E */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: FetchUntilVisible
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) ptr to line services context
|
|
plspap - (IN/OUT) current lspap before and after
|
|
pcp - (IN/OUT) current cp before and after
|
|
plsfrun - (IN/OUT) current lsfrun before and after
|
|
plschp - (IN/OUT) current lschp before and after
|
|
pfStopped - (OUT) fStopped: procedure stopped fetching because has not been allowed
|
|
to go across paragraph boundaries (result CheckPara Boundaries)
|
|
pfNewPara - (OUT) fNewPara: procedure crossed paragraph boundaries
|
|
|
|
Releases the supplied PLSRUN, if any, and fetches runs, starting at
|
|
the supplied cp, until a non-vanished run is fetched. As paragraph
|
|
boundaries are crossed, the LSPAP is updated.
|
|
|
|
----------------------------------------------------------------------------*/
|
|
static LSERR FetchUntilVisible(PLSC plsc, LSPAP* plspap, LSCP* pcp,
|
|
LSFRUN* plsfrun, PLSCHP plschp,
|
|
BOOL* pfStopped, BOOL* pfNewPara)
|
|
{
|
|
LSERR lserr;
|
|
LSCP dcpPrevRun = plsfrun->cwchRun;
|
|
BOOL fHidden;
|
|
*pfStopped = fFalse;
|
|
*pfNewPara = fFalse;
|
|
|
|
/* we assume here that this finction is called only after hidden run has been fetched
|
|
and such run is passed as an input parameter */
|
|
|
|
do
|
|
{
|
|
const PLSRUN plsrunT = plsfrun->plsrun;
|
|
|
|
|
|
*pcp += dcpPrevRun;
|
|
lserr = plsc->lscbk.pfnCheckParaBoundaries(plsc->pols, *pcp - dcpPrevRun, *pcp, pfStopped);
|
|
if (lserr != lserrNone)
|
|
return ErrReleasePreFetchedRun(plsc, plsrunT, lserr);
|
|
if (*pfStopped)
|
|
return lserrNone;
|
|
|
|
lserr = plsc->lscbk.pfnFetchPap(plsc->pols, *pcp, plspap);
|
|
if (lserr != lserrNone)
|
|
return ErrReleasePreFetchedRun(plsc, plsrunT, lserr);
|
|
if (FPapInconsistent(plspap))
|
|
return ErrReleasePreFetchedRun(plsc, plsrunT, lserrInvalidPap);
|
|
|
|
if ((*pcp - dcpPrevRun) < plspap->cpFirst)
|
|
*pfNewPara = fTrue;
|
|
|
|
|
|
plsfrun->plsrun = NULL;
|
|
if (plsrunT != NULL && !plsc->fDontReleaseRuns)
|
|
{
|
|
lserr = plsc->lscbk.pfnReleaseRun(plsc->pols, plsrunT);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
}
|
|
|
|
|
|
lserr = plsc->lscbk.pfnFetchRun(plsc->pols, *pcp,
|
|
&plsfrun->lpwchRun,
|
|
&plsfrun->cwchRun,
|
|
&fHidden,
|
|
plschp,
|
|
&plsfrun->plsrun);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
dcpPrevRun = plsfrun->cwchRun;
|
|
}
|
|
while (fHidden);
|
|
|
|
return lserrNone;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* I N I T C U R L I N E */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: InitCurLine
|
|
%%Contact: igorzv
|
|
|
|
Parameters:
|
|
plsc - (IN) ptr to line services context
|
|
cpFirst - (IN) starting cp for a line
|
|
|
|
Set default value in lsline
|
|
----------------------------------------------------------------------------*/
|
|
|
|
static LSERR InitCurLine(PLSC plsc, LSCP cpFirst)
|
|
{
|
|
PLSLINE plsline = plsc->plslineCur;
|
|
|
|
memset(plsline, 0, cbRep(struct lsline, rgplnobj, plsc->lsiobjcontext.iobjMac));
|
|
plsline->tag = tagLSLINE;
|
|
plsline->lssubl.tag = tagLSSUBL;
|
|
plsline->lssubl.plsc = plsc;
|
|
plsline->lssubl.cpFirst = cpFirst;
|
|
|
|
/* reuse quick heap for dnodes if it possible */
|
|
if (plsc->pqhAllDNodesRecycled != NULL)
|
|
{
|
|
plsline->pqhAllDNodes = plsc->pqhAllDNodesRecycled;
|
|
plsc->pqhAllDNodesRecycled = NULL;
|
|
}
|
|
else
|
|
{
|
|
plsline->pqhAllDNodes = CreateQuickHeap(plsc, limAllDNodes,
|
|
sizeof (struct lsdnode), fTrue);
|
|
if (plsline->pqhAllDNodes == NULL )
|
|
return lserrOutOfMemory;
|
|
|
|
}
|
|
|
|
plsline->lssubl.fDupInvalid = fTrue;
|
|
plsline->lssubl.fContiguous = fTrue;
|
|
plsline->lssubl.plschunkcontext = &(plsc->lschunkcontextStorage);
|
|
plsline->lssubl.fMain = fTrue;
|
|
TurnOnAllSimpleText(plsc);
|
|
plsline->lslinfo.nDepthFormatLineMax = 1;
|
|
TurnOffLineCompressed(plsc);
|
|
TurnOffNominalToIdealEncounted(plsc);
|
|
TurnOffForeignObjectEncounted(plsc);
|
|
TurnOffTabEncounted(plsc);
|
|
TurnOffNonLeftTabEncounted(plsc);
|
|
TurnOffSubmittedSublineEncounted(plsc);
|
|
TurnOffAutodecimalTabPresent(plsc);
|
|
plsc->fHyphenated = fFalse;
|
|
plsc->fAdvanceBack = fFalse;
|
|
|
|
|
|
/* we use memset to set default value, below we check that after memset we really have
|
|
correct defaults */
|
|
Assert(plsline->lssubl.plsdnFirst == NULL);
|
|
Assert(plsline->lssubl.urColumnMax == 0);
|
|
Assert(plsline->lssubl.cpLim == 0);
|
|
Assert(plsline->lssubl.plsdnLast == NULL);
|
|
Assert(plsline->lssubl.urCur == 0);
|
|
Assert(plsline->lssubl.vrCur == 0);
|
|
Assert(plsline->lssubl.fAcceptedForDisplay == fFalse);
|
|
Assert(plsline->lssubl.fRightMarginExceeded == fFalse);
|
|
Assert(plsline->lssubl.plsdnUpTemp == NULL);
|
|
Assert(plsline->lssubl.pbrkcontext == NULL);
|
|
|
|
Assert(plsline->lslinfo.dvpAscent == 0); /* lslinfo */
|
|
Assert(plsline->lslinfo.dvrAscent == 0);
|
|
Assert(plsline->lslinfo.dvpDescent == 0);
|
|
Assert(plsline->lslinfo.dvrDescent == 0);
|
|
Assert(plsline->lslinfo.dvpMultiLineHeight == 0);
|
|
Assert(plsline->lslinfo.dvrMultiLineHeight == 0);
|
|
Assert(plsline->lslinfo.dvpAscentAutoNumber == 0);
|
|
Assert(plsline->lslinfo.dvrAscentAutoNumber == 0);
|
|
Assert(plsline->lslinfo.dvpDescentAutoNumber == 0);
|
|
Assert(plsline->lslinfo.dvrDescentAutoNumber == 0);
|
|
Assert(plsline->lslinfo.cpLim == 0);
|
|
Assert(plsline->lslinfo.dcpDepend == 0);
|
|
Assert(plsline->lslinfo.cpFirstVis == 0);
|
|
Assert(plsline->lslinfo.endr == endrNormal);
|
|
Assert(plsline->lslinfo.fAdvanced == fFalse);
|
|
Assert(plsline->lslinfo.vaAdvance == 0);
|
|
Assert(plsline->lslinfo.fFirstLineInPara == fFalse);
|
|
Assert(plsline->lslinfo.EffectsFlags == 0);
|
|
Assert(plsline->lslinfo.fTabInMarginExLine == fFalse);
|
|
Assert(plsline->lslinfo.fForcedBreak == fFalse);
|
|
|
|
Assert(plsline->upStartAutonumberingText == 0);
|
|
Assert(plsline->upLimAutonumberingText == 0);
|
|
Assert(plsline->upStartMainText == 0);
|
|
Assert(plsline->upLimLine == 0);
|
|
Assert(plsline->dvpAbove == 0);
|
|
Assert(plsline->dvpBelow == 0);
|
|
Assert(plsline->upRightMarginJustify == 0);
|
|
Assert(plsline->upLimUnderline == 0);
|
|
Assert(plsline->kspl == ksplNone);
|
|
Assert(!plsline->fCollectVisual);
|
|
Assert(!plsline->fNonRealDnodeEncounted);
|
|
Assert(!plsline->fNonZeroDvpPosEncounted);
|
|
Assert(plsline->AggregatedDisplayFlags == 0);
|
|
Assert(plsline->pad == 0);
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
DWORD i;
|
|
for (i=0; i < plsc->lsiobjcontext.iobjMac; i++)
|
|
{
|
|
Assert(plsline->rgplnobj[i] == NULL);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return lserrNone;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
/* C A N N O T C R E A T E L I N E */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: CannotCreateLine
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
pplsline - (IN) ponter to a line structure to be deleted
|
|
lserr - (IN) code of an error
|
|
|
|
Called when LsCreateLine needs to return for an error condition.
|
|
----------------------------------------------------------------------------*/
|
|
static LSERR CannotCreateLine(PLSLINE* pplsline, LSERR lserr)
|
|
{
|
|
LSERR lserrIgnore;
|
|
PLSLINE plsline = *pplsline;
|
|
PLSC plsc = plsline->lssubl.plsc;
|
|
|
|
plsc->plslineCur = NULL;
|
|
plsc->lsstate = LsStateFree; /* we need free context to destroy line */
|
|
|
|
lserrIgnore = LsDestroyLine(plsc, plsline);
|
|
|
|
*pplsline = NULL;
|
|
return lserr;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
/* E R R R E L E A S E P R E F E T C H E D R U N */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: ErrReleasePreFetchedRun
|
|
%%Contact: igorzv
|
|
Parameters:
|
|
plsc - (IN) ptr to line services context
|
|
plsrun - (IN) ponter to a run structure to be deleted
|
|
lserr - (IN) code of an error
|
|
|
|
Called in a error situation when fist run of main text has been prefetched .
|
|
----------------------------------------------------------------------------*/
|
|
static LSERR ErrReleasePreFetchedRun(PLSC plsc, PLSRUN plsrun, LSERR lserr)
|
|
{
|
|
LSERR lserrIgnore;
|
|
|
|
if (!plsc->fDontReleaseRuns)
|
|
lserrIgnore = plsc->lscbk.pfnReleaseRun(plsc->pols, plsrun);
|
|
|
|
return lserr;
|
|
}
|
|
|
|
|
|
/* R E M O V E L I N E O B J E C T S */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: RemoveLineObjects
|
|
%%Contact: igorzv
|
|
Parameter:
|
|
plsc - (IN) ponter to a line structure
|
|
|
|
Removes a line context of installed objects from an line.
|
|
----------------------------------------------------------------------------*/
|
|
LSERR RemoveLineObjects(PLSLINE plsline)
|
|
{
|
|
DWORD iobjMac;
|
|
PLSC plsc;
|
|
LSERR lserr, lserrFinal = lserrNone;
|
|
DWORD iobj;
|
|
PLNOBJ plnobj;
|
|
|
|
Assert(FIsLSLINE(plsline));
|
|
|
|
plsc = plsline->lssubl.plsc;
|
|
Assert(FIsLSC(plsc));
|
|
Assert(plsc->lsstate == LsStateDestroyingLine);
|
|
|
|
iobjMac = plsc->lsiobjcontext.iobjMac;
|
|
|
|
for (iobj = 0; iobj < iobjMac; iobj++)
|
|
{
|
|
plnobj = plsline->rgplnobj[iobj];
|
|
if (plnobj != NULL)
|
|
{
|
|
lserr = plsc->lsiobjcontext.rgobj[iobj].lsim.pfnDestroyLNObj(plnobj);
|
|
plsline->rgplnobj[iobj] = NULL;
|
|
if (lserr != lserrNone)
|
|
lserrFinal = lserr;
|
|
}
|
|
}
|
|
|
|
return lserrFinal;
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
/* F R O U N D I N G O K */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: FRoundingOK
|
|
%%Contact: lenoxb
|
|
|
|
Checks for correctness of rounding algorithm in converting absolute to
|
|
device units, to agree with Word 6.0.
|
|
|
|
Checks that:
|
|
0.5 rounds up to 1.0,
|
|
1.4 rounds down to 1.4,
|
|
-0.5 rounds down to -1.0, and
|
|
-1.4 rounds up to -1.0.
|
|
|
|
----------------------------------------------------------------------------*/
|
|
static BOOL FRoundingOK(void)
|
|
{
|
|
LSDEVRES devresT;
|
|
|
|
Assert((czaUnitInch % 10) == 0);
|
|
|
|
devresT.dxpInch = czaUnitInch / 10;
|
|
|
|
if (UpFromUa(lstflowDefault, &devresT, 5) != 1)
|
|
return fFalse;
|
|
if (UpFromUa(lstflowDefault, &devresT, 14) != 1)
|
|
return fFalse;
|
|
if (UpFromUa(lstflowDefault, &devresT, -5) != -1)
|
|
return fFalse;
|
|
if (UpFromUa(lstflowDefault, &devresT, -14) != -1)
|
|
return fFalse;
|
|
|
|
return fTrue;
|
|
}
|
|
#endif /* DEBUG */
|
|
|