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

1190 lines
37 KiB
C

#include "lsmem.h"
#include <limits.h>
#include "lstxtfmt.h"
#include "lsstring.h"
#include "lstxtffi.h"
#include "lsdnfin.h"
#include "lsdnfinp.h"
#include "lsdntext.h"
#include "zqfromza.h"
#include "txtobj.h"
#include "lskysr.h"
#include "lschp.h"
#include "fmti.h"
#include "objdim.h"
#include "txtils.h"
#include "txtln.h"
#include "txtobj.h"
#include "txtconst.h"
#define cwchLocalMax 120
/* Internal Functions Prototypes */
static LSERR FormatRegularCharacters(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr);
static LSERR CreateFillTextDobj(PLNOBJ plnobj, long txtkind, PCFMTIN pfmtin, BOOL fIgnoreGlyphs,
TXTOBJ** ppdobjText);
static LSERR GetTextDobj(PLNOBJ plnobj, TXTOBJ** ppdobjText);
static LSERR FillRealFmtOut(PILSOBJ pilsobj, LSDCP dcp, long dur, TXTOBJ* pdobjText, PCFMTIN pfmtin,
BOOL fIgnoreHeights);
static LSERR AppendTrailingSpaces(PLNOBJ plnobj, TXTOBJ* pdobjText, WCHAR* rgwchGlobal,
long iwchGlobal, long cwchGlobal,
long* iwchGlobalNew, long* pddur);
static LSERR FormatStartEmptyDobj(PLNOBJ plnobj, PCFMTIN pfmtin, long txtkind, DWORD fTxtVisi,
WCHAR wchVisi, FMTRES* pfmtr);
static LSERR FormatStartTab(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr);
static LSERR FormatStartOneRegularChar(PLNOBJ plnobj, PCFMTIN pfmtin, long txtkind, FMTRES* pfmtr);
static LSERR FormatStartToReplace(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr);
static LSERR FormatStartEol(PLNOBJ plnobj, PCFMTIN pfmtin, WCHAR wch, STOPRES stopr, FMTRES* pfmtr);
static LSERR FormatStartDelete(PLNOBJ plnobj, LSDCP dcp, FMTRES* pfmtr);
static LSERR FormatStartSplat(PLNOBJ plnobj, PCFMTIN pfmtin, STOPRES stopr, FMTRES* pfmtr);
static LSERR FormatStartBorderedSpaces(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr);
static LSERR FormatSpecial(PLNOBJ plnobj, WCHAR wchRef, WCHAR wchPres, BOOL fVisible,
long txtkind, PCFMTIN pfmtin, FMTRES* pfmtr);
static STOPRES StoprHardBreak(CLABEL clab);
static CLABEL ClabFromChar(PILSOBJ pilsobj, WCHAR wch);
/* Export Functions Implementation */
/* L S T X T F M T */
/*----------------------------------------------------------------------------
%%Function: LsTxtFmt
%%Contact: sergeyge
The top-level function of the text formatter.
It checks for the first character and state
and redirects the program flow accordingly.
----------------------------------------------------------------------------*/
LSERR WINAPI FmtText(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr)
{
LSERR lserr;
PILSOBJ pilsobj;
WCHAR wchFirst;
CLABEL clab;
BOOL fInChildList;
pilsobj = plnobj->pilsobj;
wchFirst = pfmtin->lsfrun.lpwchRun[0];
clab = pilsobj->rgbSwitch[wchFirst & 0x00FF]; /* REVIEW sergeyge */
if (clab != clabRegular)
{
clab = ClabFromChar(pilsobj, wchFirst);
}
/* check for the YSR-character */
if (pfmtin->lsfrun.plschp->fHyphen && clab == clabRegular)
{
return FormatStartOneRegularChar(plnobj, pfmtin, txtkindYsrChar, pfmtr);
}
else
{
switch (clab)
{
case clabRegular:
return FormatRegularCharacters(plnobj, pfmtin, pfmtr);
case clabSpace:
if (pfmtin->lsfrun.plschp->fBorder)
return FormatStartBorderedSpaces(plnobj, pfmtin, pfmtr);
else
return FormatRegularCharacters(plnobj, pfmtin, pfmtr);
case clabEOP1:
switch (pilsobj->lskeop)
{
case lskeopEndPara1:
return FormatStartEol(plnobj, pfmtin, pilsobj->wchVisiEndPara, stoprEndPara, pfmtr);
case lskeopEndPara12:
return FormatStartDelete(plnobj, 1, pfmtr);
default:
return FormatStartOneRegularChar(plnobj, pfmtin, txtkindRegular, pfmtr);
}
case clabEOP2:
switch (pilsobj->lskeop)
{
case lskeopEndPara2:
case lskeopEndPara12:
return FormatStartEol(plnobj, pfmtin, pilsobj->wchVisiEndPara, stoprEndPara, pfmtr);
default:
return FormatStartOneRegularChar(plnobj, pfmtin, txtkindRegular, pfmtr);
}
break;
case clabAltEOP:
switch (pilsobj->lskeop)
{
case lskeopEndParaAlt:
return FormatStartEol(plnobj, pfmtin, pilsobj->wchVisiAltEndPara, stoprAltEndPara, pfmtr);
default:
return FormatStartOneRegularChar(plnobj, pfmtin, txtkindRegular, pfmtr);
}
case clabEndLineInPara:
return FormatStartEol(plnobj, pfmtin, pilsobj->wchVisiEndLineInPara, stoprSoftCR, pfmtr);
case clabTab:
return FormatStartTab(plnobj, pfmtin, pfmtr);
case clabNull:
if (pilsobj->grpf & fTxtVisiSpaces)
return FormatSpecial(plnobj, wchFirst, pilsobj->wchVisiNull, fTrue, txtkindRegular, pfmtin, pfmtr);
else
return FormatSpecial(plnobj, wchFirst, wchFirst, fFalse, txtkindRegular, pfmtin, pfmtr);
case clabNonReqHyphen:
return FormatStartEmptyDobj(plnobj, pfmtin, txtkindNonReqHyphen, fTxtVisiCondHyphens,
pilsobj->wchVisiNonReqHyphen, pfmtr);
case clabNonBreakHyphen:
if (pilsobj->grpf & fTxtVisiCondHyphens)
return FormatSpecial(plnobj, pilsobj->wchHyphen, pilsobj->wchVisiNonBreakHyphen, fTrue, txtkindNonBreakHyphen, pfmtin, pfmtr);
else
return FormatSpecial(plnobj, pilsobj->wchHyphen, pilsobj->wchHyphen, fFalse, txtkindNonBreakHyphen, pfmtin, pfmtr);
case clabNonBreakSpace:
if (pilsobj->grpf & fTxtVisiSpaces)
return FormatSpecial(plnobj, pilsobj->wchSpace, pilsobj->wchVisiNonBreakSpace, fTrue, txtkindNonBreakSpace, pfmtin, pfmtr);
else
return FormatSpecial(plnobj, pilsobj->wchSpace, pilsobj->wchSpace, fFalse, txtkindNonBreakSpace, pfmtin, pfmtr);
case clabHardHyphen:
if (pilsobj->grpf & fTxtTreatHyphenAsRegular)
return FormatSpecial(plnobj, wchFirst, wchFirst, fFalse, txtkindRegular, pfmtin, pfmtr);
else
return FormatSpecial(plnobj, wchFirst, wchFirst, fFalse, txtkindHardHyphen, pfmtin, pfmtr);
case clabSectionBreak:
case clabColumnBreak:
case clabPageBreak:
lserr = LsdnFInChildList(pilsobj->plsc, pfmtin->plsdnTop, &fInChildList);
if (lserr != lserrNone) return lserr;
if (fInChildList)
return FormatStartDelete(plnobj, 1, pfmtr);
else
return FormatStartSplat(plnobj, pfmtin, StoprHardBreak(clab), pfmtr);
case clabEmSpace:
if (pilsobj->grpf & fTxtVisiSpaces)
return FormatSpecial(plnobj, wchFirst, pilsobj->wchVisiEmSpace, fTrue, txtkindSpecSpace, pfmtin, pfmtr);
else
return FormatSpecial(plnobj, wchFirst, wchFirst, fFalse, txtkindSpecSpace, pfmtin, pfmtr);
case clabEnSpace:
if (pilsobj->grpf & fTxtVisiSpaces)
return FormatSpecial(plnobj, wchFirst, pilsobj->wchVisiEnSpace, fTrue, txtkindSpecSpace, pfmtin, pfmtr);
else
return FormatSpecial(plnobj, wchFirst, wchFirst, fFalse, txtkindSpecSpace, pfmtin, pfmtr);
case clabNarrowSpace:
if (pilsobj->grpf & fTxtVisiSpaces)
return FormatSpecial(plnobj, wchFirst, pilsobj->wchVisiNarrowSpace, fTrue, txtkindSpecSpace, pfmtin, pfmtr);
else
return FormatSpecial(plnobj, wchFirst, wchFirst, fFalse, txtkindSpecSpace, pfmtin, pfmtr);
case clabOptBreak:
return FormatStartEmptyDobj(plnobj, pfmtin, txtkindOptBreak, fTxtVisiBreaks,
pilsobj->wchVisiOptBreak, pfmtr);
case clabNonBreak:
return FormatStartEmptyDobj(plnobj, pfmtin, txtkindOptNonBreak, fTxtVisiBreaks,
pilsobj->wchVisiNoBreak, pfmtr);
case clabFESpace:
if (pilsobj->grpf & fTxtVisiSpaces)
return FormatSpecial(plnobj, wchFirst, pilsobj->wchVisiFESpace, fTrue, txtkindSpecSpace, pfmtin, pfmtr);
else
return FormatSpecial(plnobj, wchFirst, wchFirst, fFalse, txtkindSpecSpace, pfmtin, pfmtr);
case clabJoiner:
case clabNonJoiner:
return FormatStartOneRegularChar(plnobj, pfmtin, txtkindRegular, pfmtr);
case clabToReplace: /* backslash in FE Word */
return FormatStartToReplace(plnobj, pfmtin, pfmtr);
}
}
return lserrNone;
}
/* L S D E S T R O Y T X T D O B J*/
/*----------------------------------------------------------------------------
%%Function: LsDestroyTxtDObj
%%Contact: sergeyge
DestroyDObj method of the text handler.
----------------------------------------------------------------------------*/
LSERR WINAPI DestroyDObjText(PDOBJ pdobj)
{
Unreferenced(pdobj);
return lserrNone;
}
/* L S S U B L I N E F I N I S H E D T E X T */
/*----------------------------------------------------------------------------
%%Function: LsSublineFinishedText
%%Contact: sergeyge
Notification from Manager about finishing the subline
----------------------------------------------------------------------------*/
LSERR LsSublineFinishedText(PLNOBJ plnobj)
{
Assert(plnobj->pilsobj->wchMac + 2 <= plnobj->pilsobj->wchMax);
return IncreaseWchMacBy2(plnobj);
}
/* Internal Functions Implementation */
/* F O R M A T R E G U L A R C H A R A C T E R S */
/*----------------------------------------------------------------------------
%%Function: FormatRegularCharacters
%%Contact: sergeyge
Formats run starting with the regular character.
Ends as soon as any special character is encountered or
right margin is achieved or
all characters are processed.
----------------------------------------------------------------------------*/
static LSERR FormatRegularCharacters(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr)
{
LSERR lserr;
PILSOBJ pilsobj;
long cwchGlobal;
long iwchGlobal;
long iwchLocal;
long cwchLocal;
long iwSpaces;
long cwchMax;
LSCP cpFirst;
long durWidthExceed;
WCHAR* rgwchGlobal;
WCHAR* rgwchLocal;
long rgwSpaces[cwchLocalMax];
TXTOBJ* pdobjText;
long durWidth;
long ddur;
BOOL fTerminateLoops;
long dur;
CLABEL clab;
CLABEL* rgbSwitch;
WCHAR wchSpace;
long iwchGlobalNew;
BOOL fInSpaces = fFalse;
int i;
int idur;
pilsobj = plnobj->pilsobj;
lserr = CreateFillTextDobj(plnobj, txtkindRegular, pfmtin, fFalse, &pdobjText);
if (lserr != lserrNone) return lserr;
rgbSwitch = pilsobj->rgbSwitch;
wchSpace = pilsobj->wchSpace;
rgwchGlobal = (WCHAR*)pfmtin->lsfrun.lpwchRun;
cwchGlobal = (long)pfmtin->lsfrun.cwchRun;
iwchGlobal = 0;
fTerminateLoops = fFalse;
durWidthExceed = pfmtin->lsfgi.urColumnMax - pfmtin->lsfgi.urPen;
cpFirst = pfmtin->lsfgi.cpFirst;
dur = 0;
while (iwchGlobal < cwchGlobal && !fTerminateLoops)
{
rgwchLocal = &rgwchGlobal[iwchGlobal];
cwchMax = cwchGlobal - iwchGlobal;
if (cwchMax > cwchLocalMax)
cwchMax = cwchLocalMax;
lserr = GetWidths(plnobj, pfmtin->lsfrun.plsrun, pdobjText->iwchLim, rgwchLocal,
cpFirst, cwchMax, durWidthExceed, pfmtin->lsfgi.lstflow, &cwchLocal, &durWidth);
if (lserr != lserrNone) return lserr;
iwchLocal = 0;
iwSpaces = 0;
while (iwchLocal < cwchLocal /*&& !fTerminateLoops*/)
{
if (rgbSwitch[rgwchLocal[iwchLocal] & 0x00FF] == clabRegular)
iwchLocal++;
else if (rgwchLocal[iwchLocal] == wchSpace)
{
if (!pfmtin->lsfrun.plschp->fBorder)
{
rgwSpaces[iwSpaces] = iwchLocal;
iwchLocal++;
iwSpaces++;
}
else
{
fTerminateLoops = fTrue;
durWidth = 0;
for (i = 0, idur = pdobjText->iwchLim; i < iwchLocal; i++, idur++)
durWidth += pilsobj->pdur[idur];
break; /* This break is equivalent to the check commented out in the loop condition */
}
}
else
{
clab = ClabFromChar(pilsobj, rgwchLocal[iwchLocal]);
if (clab == clabRegular)
{
iwchLocal++;
}
else
{
/* Terminate loops (and processing of run) for any special character */
fTerminateLoops = fTrue;
durWidth = 0;
for (i = 0, idur = pdobjText->iwchLim; i < iwchLocal; i++, idur++)
durWidth += pilsobj->pdur[idur];
break; /* This break is equivalent to the check commented out in the loop condition */
}
}
}
if (iwchLocal != 0)
{
fInSpaces = fFalse;
lserr = FormatString(plnobj, pdobjText, rgwchLocal, iwchLocal, rgwSpaces, iwSpaces, durWidth);
if (lserr != lserrNone) return lserr;
iwchGlobal += iwchLocal;
durWidthExceed -= durWidth;
Assert(dur < uLsInfiniteRM); /* We can be sure of it because dur is 0 during first iteration,
and we check for uLsInfiniteRM in the TrailingSpaces logic */
Assert(durWidth < uLsInfiniteRM);
dur += durWidth;
cpFirst += iwchLocal;
if (cwchLocal == iwchLocal && durWidthExceed < 0)
{
if (rgwchLocal[cwchLocal-1] == wchSpace)
{
fInSpaces = fTrue;
if (iwchGlobal < cwchGlobal && pilsobj->wchSpace == rgwchGlobal[iwchGlobal])
{
lserr = AppendTrailingSpaces(plnobj, pdobjText, rgwchGlobal,
(DWORD)iwchGlobal, cwchGlobal, &iwchGlobalNew, &ddur);
if (lserr != lserrNone) return lserr;
if (iwchGlobalNew != iwchGlobal)
{
cpFirst += (iwchGlobalNew - iwchGlobal);
iwchGlobal = iwchGlobalNew;
Assert (ddur <= uLsInfiniteRM - dur);
if (ddur > uLsInfiniteRM - dur)
return lserrTooLongParagraph;
dur += ddur;
}
}
}
else
fTerminateLoops = fTrue;
}
} /* if iwchLocal != 0 */
} /* while iwchGlobal < cwchGlobal && !fTerminateLoops */
Assert(iwchGlobal == pdobjText->iwchLim - pdobjText->iwchFirst);
Assert(iwchGlobal > 0);
lserr = FillRegularPresWidths(plnobj, pfmtin->lsfrun.plsrun, pfmtin->lsfgi.lstflow, pdobjText);
if (lserr != lserrNone) return lserr;
if ((pilsobj->grpf & fTxtVisiSpaces) && pfmtin->lsfgi.cpFirst >= 0)
{
FixSpaces(plnobj, pdobjText, pilsobj->wchVisiSpace);
}
*pfmtr = fmtrCompletedRun;
if (durWidthExceed < 0 && !fInSpaces)
{
*pfmtr = fmtrExceededMargin;
}
lserr = FillRealFmtOut(pilsobj, iwchGlobal, dur, pdobjText, pfmtin,
iwchGlobal == pdobjText->u.reg.iwSpacesLim - pdobjText->u.reg.iwSpacesFirst);
return lserr;
}
/* C R E A T E F I L L T E X T D O B J */
/*----------------------------------------------------------------------------
%%Function: CreateFillTextDobj
%%Contact: sergeyge
Requests pointer to the new text DObj and then fills common memebers
----------------------------------------------------------------------------*/
static LSERR CreateFillTextDobj(PLNOBJ plnobj, long txtkind, PCFMTIN pfmtin, BOOL fIgnoreGlyphs,
TXTOBJ** ppdobjText)
{
LSERR lserr;
PILSOBJ pilsobj;
pilsobj = plnobj->pilsobj;
lserr = GetTextDobj(plnobj, ppdobjText);
if (lserr != lserrNone) return lserr;
(*ppdobjText)->txtkind = (BYTE)txtkind;
(*ppdobjText)->plnobj = plnobj;
(*ppdobjText)->plsdnUpNode = pfmtin->plsdnTop;
if (pfmtin->lstxmPres.fMonospaced)
(*ppdobjText)->txtf |= txtfMonospaced;
(*ppdobjText)->iwchFirst = pilsobj->wchMac;
(*ppdobjText)->iwchLim = pilsobj->wchMac;
if (txtkind == txtkindRegular)
{
(*ppdobjText)->u.reg.iwSpacesFirst = pilsobj->wSpacesMac;
(*ppdobjText)->u.reg.iwSpacesLim = pilsobj->wSpacesMac;
}
if (!fIgnoreGlyphs && pfmtin->lsfrun.plschp->fGlyphBased)
(*ppdobjText)->txtf |= txtfGlyphBased;
return lserrNone;
}
/* G E T T E X T D O B J */
/*----------------------------------------------------------------------------
%%Function: GetTextDobj
%%Contact: sergeyge
Produces pointer of the first unoccupied DObj from the preallocated chunk.
If nothing is left, allocates next piece and includes it in the linked list.
----------------------------------------------------------------------------*/
static LSERR GetTextDobj(PLNOBJ plnobj, TXTOBJ** ppdobjText)
{
PILSOBJ pilsobj;
TXTOBJ* ptxtobj;
pilsobj = plnobj->pilsobj;
if (pilsobj->txtobjMac < txtobjMaxM)
{
*ppdobjText = &plnobj->ptxtobj[pilsobj->txtobjMac];
pilsobj->txtobjMac++;
}
else
{
/* if nothing is left in the active piece, there are still two possibilities:
either there is next preallocated (during the formatting of the previous lines piece
or next piece should be allocated
*/
if ( *(TXTOBJ**)(plnobj->ptxtobj + txtobjMaxM) == NULL)
{
ptxtobj = (*pilsobj->plscbk->pfnNewPtr)(pilsobj->pols, sizeof(TXTOBJ) * txtobjMaxM + sizeof(TXTOBJ**));
if (ptxtobj == NULL)
{
return lserrOutOfMemory;
}
*(TXTOBJ**)(ptxtobj + txtobjMaxM) = NULL;
*(TXTOBJ**)(plnobj->ptxtobj + txtobjMaxM) = ptxtobj;
plnobj->ptxtobj = ptxtobj;
}
else
{
plnobj->ptxtobj = *(TXTOBJ**)(plnobj->ptxtobj + txtobjMaxM);
}
*ppdobjText = plnobj->ptxtobj;
pilsobj->txtobjMac = 1;
}
memset(*ppdobjText, 0, sizeof(**ppdobjText));
return lserrNone;
}
/* F I L L R E A L F M T O U T */
/*----------------------------------------------------------------------------
%%Function: FillRealFmtOut
%%Contact: sergeyge
Sets dup in dobj and
calls to LsdnFinishSimpleRegular for the regular case (real upper node)
----------------------------------------------------------------------------*/
static LSERR FillRealFmtOut(PILSOBJ pilsobj, LSDCP lsdcp, long dur, TXTOBJ* pdobjText, PCFMTIN pfmtin,
BOOL fSpacesOnly)
{
LSERR lserr;
OBJDIM objdim;
objdim.dur = dur;
objdim.heightsPres.dvAscent = pfmtin->lstxmPres.dvAscent;
objdim.heightsRef.dvAscent = pfmtin->lstxmRef.dvAscent;
objdim.heightsPres.dvDescent = pfmtin->lstxmPres.dvDescent;
objdim.heightsRef.dvDescent = pfmtin->lstxmRef.dvDescent;
objdim.heightsPres.dvMultiLineHeight = pfmtin->lstxmPres.dvMultiLineHeight;
objdim.heightsRef.dvMultiLineHeight = pfmtin->lstxmRef.dvMultiLineHeight;
if (fSpacesOnly)
{
if (!(pilsobj->grpf & fTxtSpacesInfluenceHeight))
{
objdim.heightsRef.dvMultiLineHeight = dvHeightIgnore;
objdim.heightsPres.dvMultiLineHeight = dvHeightIgnore;
}
}
/* It is ugly to set part of FetchedWidth state here, but it is absolutely needed
to fix bug 546. iwchFetchedWidthFirst was introduced to fix this bug
*/
if (lsdcp < pfmtin->lsfrun.cwchRun)
pilsobj->wchFetchedWidthFirst = pfmtin->lsfrun.lpwchRun[lsdcp];
else
FlushStringState(pilsobj); /* Next char is not available---it is risky to use optimization */
lserr = LsdnFinishRegular(pilsobj->plsc, lsdcp,
pfmtin->lsfrun.plsrun, pfmtin->lsfrun.plschp, (PDOBJ)pdobjText, &objdim);
return lserr;
}
/* A P P E N D T R A I L I N G S P A C E S */
/*----------------------------------------------------------------------------
%%Function: AppendTrailingSpaces
%%Contact: sergeyge
Trailing spaces logic.
----------------------------------------------------------------------------*/
static LSERR AppendTrailingSpaces(PLNOBJ plnobj, TXTOBJ* pdobjText, WCHAR* rgwchGlobal,
long iwchGlobal, long cwchGlobal,
long* iwchGlobalNew, long* pddur)
{
LSERR lserr;
PILSOBJ pilsobj;
long iNumOfSpaces;
long durSpace;
pilsobj = plnobj->pilsobj;
Assert(iwchGlobal < cwchGlobal && pilsobj->wchSpace == rgwchGlobal[iwchGlobal]);
iNumOfSpaces = 1;
iwchGlobal++;
while (iwchGlobal < cwchGlobal && pilsobj->wchSpace == rgwchGlobal[iwchGlobal])
{
iNumOfSpaces++;
iwchGlobal++;
}
*iwchGlobalNew = iwchGlobal;
Assert(pilsobj->pwchOrig[pdobjText->iwchLim - 1] == pilsobj->wchSpace);
durSpace = pilsobj->pdur[pdobjText->iwchLim - 1];
Assert (iNumOfSpaces > 0);
Assert(durSpace <= uLsInfiniteRM / iNumOfSpaces);
if (durSpace > uLsInfiniteRM / iNumOfSpaces)
return lserrTooLongParagraph;
*pddur = durSpace * iNumOfSpaces;
/* Calls function of the string module level */
lserr = AddSpaces(plnobj, pdobjText, durSpace, iNumOfSpaces);
return lserr;
}
/* F O R M A T S T A R T E M P T Y D O B J */
/*----------------------------------------------------------------------------
%%Function: FormatStartEmptyDobj
%%Contact: sergeyge
NonReqHyphen/OptionalBreak/OptionalNonBreak logic
----------------------------------------------------------------------------*/
static LSERR FormatStartEmptyDobj(PLNOBJ plnobj, PCFMTIN pfmtin, long txtkind, DWORD fTxtVisi,
WCHAR wchVisi, FMTRES* pfmtr)
{
LSERR lserr;
PILSOBJ pilsobj;
TXTOBJ* pdobjText;
PLSRUN plsrun;
long dup;
/* long durOut = 0; */
pilsobj = plnobj->pilsobj;
plsrun = pfmtin->lsfrun.plsrun;
lserr = CreateFillTextDobj(plnobj, txtkind, pfmtin, fTrue, &pdobjText);
if (lserr != lserrNone) return lserr;
pdobjText->txtf |= txtfSkipAtNti;
pilsobj->fDifficultForAdjust = fTrue;
if (pilsobj->grpf & fTxtVisi)
{
Assert(pilsobj->fDisplay);
/* Imitate formatting for 1-char string without writing in the string level structures */
/* lserr = GetOneCharDur(pilsobj, plsrun, pilsobj->wchHyphen, pfmtin->lsfgi.lstflow, &durOut);
if (lserr != lserrNone) return lserr;
*/
pdobjText->txtf |= txtfSkipAtWysi;
pdobjText->txtf |= txtfVisi;
lserr = GetVisiCharDup(pilsobj, plsrun, wchVisi, pfmtin->lsfgi.lstflow, &dup);
if (lserr != lserrNone) return lserr;
/* Restore this code instead of current one if Word wants to keep differences in breaking
lserr = AddCharacterWithWidth(plnobj, pdobjText, pilsobj->wchHyphen, durOut, wchVisi, dup);
if (lserr != lserrNone) return lserr;
lserr = FillRealFmtOut(pilsobj, 1, durOut, pdobjText, pfmtin, fFalse);
if (lserr != lserrNone) return lserr;
*/
lserr = AddCharacterWithWidth(plnobj, pdobjText, pilsobj->wchHyphen, 0, wchVisi, dup);
if (lserr != lserrNone) return lserr;
lserr = FillRealFmtOut(pilsobj, 1, 0, pdobjText, pfmtin, fTrue);
if (lserr != lserrNone) return lserr;
}
else
{
lserr = FillRealFmtOut(pilsobj, 1, 0, pdobjText, pfmtin, fTrue);
if (lserr != lserrNone) return lserr;
FlushStringState(pilsobj); /* Position of fetched widths is not correct any longer */
}
*pfmtr = fmtrCompletedRun;
return lserrNone;
}
/* F O R M A T S T A R T T A B */
/*----------------------------------------------------------------------------
%%Function: FormatStartTab
%%Contact: sergeyge
Tab logic
----------------------------------------------------------------------------*/
static LSERR FormatStartTab(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr)
{
LSERR lserr;
PILSOBJ pilsobj;
PTXTOBJ pdobjText;
int durJunk;
long cJunk;
pilsobj = plnobj->pilsobj;
lserr = CreateFillTextDobj(plnobj, txtkindTab, pfmtin, fTrue, &pdobjText);
if (lserr != lserrNone) return lserr;
pdobjText->u.tab.wchTabLeader = pilsobj->wchSpace;
if (pilsobj->grpf & fTxtVisiTabs)
{
Assert(pilsobj->fDisplay);
pdobjText->txtf |= txtfVisi;
/* REVIEW sergeyge: Next call is made to show Visi Tab correctly in WORD
it should be moved to the WAL */
(*pilsobj->plscbk->pfnGetRunCharWidths)(pilsobj->pols, pfmtin->lsfrun.plsrun,
lsdevPres, &pilsobj->wchVisiTab, 1, LONG_MAX, pfmtin->lsfgi.lstflow,
&durJunk, (long*)&durJunk, &cJunk);
pdobjText->u.tab.wch = pilsobj->wchVisiTab;
}
else
{
pdobjText->u.tab.wch = pfmtin->lsfrun.lpwchRun[0];
}
lserr = AddCharacterWithWidth(plnobj, pdobjText, pfmtin->lsfrun.lpwchRun[0], 0,
pfmtin->lsfrun.lpwchRun[0], 0);
if (lserr != lserrNone) return lserr;
lserr = FillRealFmtOut(pilsobj, 1, 0, pdobjText, pfmtin, fTrue);
if (lserr != lserrNone) return lserr;
*pfmtr = fmtrTab;
return lserrNone;
}
/* F O R M A T S T A R T B O R D E R E D S P A C E S */
/*----------------------------------------------------------------------------
%%Function: FormatStartBorderedSpaces
%%Contact: sergeyge
Formatting od the spaces within bordered run
----------------------------------------------------------------------------*/
static LSERR FormatStartBorderedSpaces(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr)
{
LSERR lserr;
PILSOBJ pilsobj;
TXTOBJ* pdobjText;
long durSpace;
DWORD iNumOfSpaces;
pilsobj = plnobj->pilsobj;
lserr = CreateFillTextDobj(plnobj, txtkindRegular, pfmtin, fFalse, &pdobjText);
if (lserr != lserrNone) return lserr;
Assert(pfmtin->lsfrun.lpwchRun[0] == pilsobj->wchSpace);
/* fill additional information for txtkindYsrChar text DObj */
lserr = GetOneCharDur(pilsobj, pfmtin->lsfrun.plsrun, pilsobj->wchSpace, pfmtin->lsfgi.lstflow, &durSpace);
if (lserr != lserrNone) return lserr;
iNumOfSpaces = 0;
while (pilsobj->wchSpace == pfmtin->lsfrun.lpwchRun[iNumOfSpaces] && iNumOfSpaces < pfmtin->lsfrun.cwchRun)
{
iNumOfSpaces++;
}
/* Calls functions of the string module level */
lserr = AddSpaces(plnobj, pdobjText, durSpace, iNumOfSpaces);
if (lserr != lserrNone) return lserr;
lserr = FillRegularPresWidths(plnobj, pfmtin->lsfrun.plsrun, pfmtin->lsfgi.lstflow, pdobjText);
if (lserr != lserrNone) return lserr;
if ((pilsobj->grpf & fTxtVisiSpaces) && pfmtin->lsfgi.cpFirst >= 0)
{
FixSpaces(plnobj, pdobjText, pilsobj->wchVisiSpace);
}
*pfmtr = fmtrCompletedRun;
lserr = FillRealFmtOut(pilsobj, iNumOfSpaces, durSpace * iNumOfSpaces, pdobjText, pfmtin, fTrue);
if (lserr != lserrNone) return lserr;
return lserrNone;
}
/* F O R M A T S T A R T O N E R E G U L A R C H A R */
/*----------------------------------------------------------------------------
%%Function: FormatStartOneRegularChar
%%Contact: sergeyge
YSR/(NonSignificant for this paragraph EOP) character logic.
----------------------------------------------------------------------------*/
static LSERR FormatStartOneRegularChar(PLNOBJ plnobj, PCFMTIN pfmtin, long txtkind, FMTRES* pfmtr)
{
LSERR lserr;
PILSOBJ pilsobj;
TXTOBJ* pdobjText;
long durOut;
long dupOut;
WCHAR wch;
pilsobj = plnobj->pilsobj;
lserr = CreateFillTextDobj(plnobj, txtkind, pfmtin, fFalse, &pdobjText);
if (lserr != lserrNone) return lserr;
wch = pfmtin->lsfrun.lpwchRun[0];
/* fill additional information for txtkindYsrChar text DObj */
lserr = GetOneCharDur(pilsobj, pfmtin->lsfrun.plsrun, wch, pfmtin->lsfgi.lstflow, &durOut);
if (lserr != lserrNone) return lserr;
lserr = GetOneCharDup(pilsobj, pfmtin->lsfrun.plsrun, wch, pfmtin->lsfgi.lstflow, durOut, &dupOut);
if (lserr != lserrNone) return lserr;
Assert(durOut < uLsInfiniteRM);
lserr = AddCharacterWithWidth(plnobj, pdobjText, wch, durOut, wch, dupOut);
*pfmtr = fmtrCompletedRun;
if (durOut > pfmtin->lsfgi.urColumnMax - pfmtin->lsfgi.urPen)
{
*pfmtr = fmtrExceededMargin;
}
lserr = FillRealFmtOut(pilsobj, 1, durOut, pdobjText, pfmtin, fFalse);
if (lserr != lserrNone) return lserr;
return lserrNone;
}
/* F O R M A T S T A R T T O R E P L A C E */
/*----------------------------------------------------------------------------
%%Function: FormatStartToReplace
%%Contact: sergeyge
Implements replacement of one char code ("\") by another (Yen)
----------------------------------------------------------------------------*/
static LSERR FormatStartToReplace(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr)
{
LSERR lserr;
PILSOBJ pilsobj;
TXTOBJ* pdobjText;
WCHAR wch;
long durOut;
long dupOut;
pilsobj = plnobj->pilsobj;
lserr = CreateFillTextDobj(plnobj, txtkindRegular, pfmtin, fFalse, &pdobjText);
if (lserr != lserrNone) return lserr;
/* fill additional information for txtkindYsrChar text DObj */
if (pfmtin->lsfrun.plschp->fCheckForReplaceChar)
wch = pilsobj->wchReplace;
else
wch = pfmtin->lsfrun.lpwchRun[0];
lserr = GetOneCharDur(pilsobj, pfmtin->lsfrun.plsrun, wch, pfmtin->lsfgi.lstflow, &durOut);
if (lserr != lserrNone) return lserr;
lserr = GetOneCharDup(pilsobj, pfmtin->lsfrun.plsrun, wch, pfmtin->lsfgi.lstflow, durOut, &dupOut);
if (lserr != lserrNone) return lserr;
Assert(durOut < uLsInfiniteRM);
lserr = AddCharacterWithWidth(plnobj, pdobjText, wch, durOut, wch, dupOut);
*pfmtr = fmtrCompletedRun;
if (durOut > pfmtin->lsfgi.urColumnMax - pfmtin->lsfgi.urPen)
{
*pfmtr = fmtrExceededMargin;
}
lserr = FillRealFmtOut(pilsobj, 1, durOut, pdobjText, pfmtin, fFalse);
if (lserr != lserrNone) return lserr;
return lserrNone;
}
/* F O R M A T S T A R T E O L */
/*----------------------------------------------------------------------------
%%Function: FormatStartEop
%%Contact: sergeyge
EOP/SoftCR logic.
----------------------------------------------------------------------------*/
static LSERR FormatStartEol(PLNOBJ plnobj, PCFMTIN pfmtin, WCHAR wchVisiEnd, STOPRES stopr, FMTRES* pfmtr)
{
LSERR lserr;
PILSOBJ pilsobj;
PLSRUN plsrun;
TXTOBJ* pdobjText;
WCHAR wchAdd;
long dupWch;
long durWch;
BOOL fInChildList;
OBJDIM objdim;
pilsobj = plnobj->pilsobj;
plsrun = pfmtin->lsfrun.plsrun;
lserr = LsdnFInChildList(pilsobj->plsc, pfmtin->plsdnTop, &fInChildList);
Assert(lserr == lserrNone);
if (fInChildList)
return FormatStartOneRegularChar(plnobj, pfmtin, txtkindRegular, pfmtr);
*pfmtr = fmtrStopped;
/* CreateFillTextDobj section starts */
lserr = GetTextDobj(plnobj, &pdobjText);
if (lserr != lserrNone) return lserr;
pdobjText->txtkind = txtkindEOL;
pdobjText->plnobj = plnobj;
pdobjText->plsdnUpNode = pfmtin->plsdnTop;
pdobjText->iwchFirst = pilsobj->wchMac;
/* CreateFillTextDobj section ends */
pdobjText->txtf |= txtfSkipAtNti;
if (pilsobj->grpf & fTxtVisiParaMarks)
wchAdd = wchVisiEnd;
else
wchAdd = pilsobj->wchSpace;
if (pilsobj->fDisplay)
{
lserr = GetVisiCharDup(pilsobj, plsrun, wchVisiEnd, pfmtin->lsfgi.lstflow, &dupWch);
if (lserr != lserrNone) return lserr;
durWch = UrFromUp(pfmtin->lsfgi.lstflow, &pilsobj->lsdevres, dupWch);
plnobj->pwch[pilsobj->wchMac] = wchAdd;
plnobj->pdup[pilsobj->wchMac] = dupWch;
}
else
{
durWch = 1;
}
Assert(durWch < uLsInfiniteRM);
pilsobj->pwchOrig[pilsobj->wchMac] = wchAdd;
pilsobj->pdur[pilsobj->wchMac] = durWch;
/* AddCharacterWithWidth section starts---parts of it were moved up */
/* We do not check for sufficient space in allocated arrays becayse anyway we allocate for 2 additional
characters due to possible changes at hyphenation time
*/
pilsobj->dcpFetchedWidth = 0;
pilsobj->wchMac++;
pdobjText->iwchLim = pilsobj->wchMac;
Assert(pdobjText->iwchLim == pdobjText->iwchFirst + 1);
/* AddCharacterWithWidth section ends */
/* FillRealFmtOut section starts */
objdim.dur = durWch;
objdim.heightsPres.dvAscent = pfmtin->lstxmPres.dvAscent;
objdim.heightsRef.dvAscent = pfmtin->lstxmRef.dvAscent;
objdim.heightsPres.dvDescent = pfmtin->lstxmPres.dvDescent;
objdim.heightsRef.dvDescent = pfmtin->lstxmRef.dvDescent;
objdim.heightsPres.dvMultiLineHeight = pfmtin->lstxmPres.dvMultiLineHeight;
objdim.heightsRef.dvMultiLineHeight = pfmtin->lstxmRef.dvMultiLineHeight;
if (!(pilsobj->grpf & fTxtSpacesInfluenceHeight))
{
objdim.heightsRef.dvMultiLineHeight = dvHeightIgnore;
objdim.heightsPres.dvMultiLineHeight = dvHeightIgnore;
}
lserr = LsdnSetStopr(pilsobj->plsc, pfmtin->plsdnTop, stopr);
Assert(lserr == lserrNone);
lserr = LsdnFinishRegular(pilsobj->plsc, 1,
pfmtin->lsfrun.plsrun, pfmtin->lsfrun.plschp, (PDOBJ)pdobjText, &objdim);
return lserr;
}
/* F O R M A T S T A R T D E L E T E */
/*----------------------------------------------------------------------------
%%Function: FormatStartDelete
%%Contact: sergeyge
Formatting by Delete upper dnode
----------------------------------------------------------------------------*/
static LSERR FormatStartDelete(PLNOBJ plnobj, LSDCP dcp, FMTRES* pfmtr)
{
PILSOBJ pilsobj;
pilsobj = plnobj->pilsobj;
FlushStringState(pilsobj); /* Position of fetched widths is not correct any longer */
*pfmtr = fmtrCompletedRun;
return LsdnFinishDelete(pilsobj->plsc, dcp);
}
/* F O R M A T S T A R T S P L A T */
/*----------------------------------------------------------------------------
%%Function: FormatStartSplat
%%Contact: sergeyge
Splat formatting logic
----------------------------------------------------------------------------*/
static LSERR FormatStartSplat(PLNOBJ plnobj, PCFMTIN pfmtin, STOPRES stopr, FMTRES* pfmtr)
{
*pfmtr = fmtrStopped;
LsdnSetStopr(plnobj->pilsobj->plsc, pfmtin->plsdnTop, stopr);
return FillRealFmtOut(plnobj->pilsobj, 1, 0, NULL, pfmtin, fTrue);
}
/* F O R M A T S P E C I A L */
/*----------------------------------------------------------------------------
%%Function: FormatSpecial
%%Contact: sergeyge
Formatting of the special characters (not NonReqHyphen, not Tab)
Uses wchRef for formatting on reference device, wchPres--on preview device
----------------------------------------------------------------------------*/
static LSERR FormatSpecial(PLNOBJ plnobj, WCHAR wchRef, WCHAR wchPres, BOOL fVisible, long txtkind,
PCFMTIN pfmtin, FMTRES* pfmtr)
{
LSERR lserr;
PILSOBJ pilsobj;
PTXTOBJ pdobjText;
PLSRUN plsrun;
long dur;
long dup;
long durGlobal;
long cwchRun;
const WCHAR* pwchRun;
long iNumOfChars;
long durWidth;
long i;
pilsobj = plnobj->pilsobj;
plsrun = pfmtin->lsfrun.plsrun;
lserr = CreateFillTextDobj(plnobj, txtkind, pfmtin, fTrue, &pdobjText);
if (lserr != lserrNone) return lserr;
durWidth = pfmtin->lsfgi.urColumnMax - pfmtin->lsfgi.urPen;
/* Imitate formatting for 1-char string without writing in the string level structures */
lserr = GetOneCharDur(pilsobj, plsrun, wchRef, pfmtin->lsfgi.lstflow, &dur);
if (lserr != lserrNone) return lserr;
/* Calculate presentation width */
Assert(wchPres == wchRef || fVisible);
if (fVisible)
{
long dupOrig;
pilsobj->fDifficultForAdjust = fTrue;
lserr = GetVisiCharDup(pilsobj, plsrun, wchPres, pfmtin->lsfgi.lstflow, &dup);
if (lserr != lserrNone) return lserr;
lserr = GetOneCharDup(pilsobj, plsrun, wchPres, pfmtin->lsfgi.lstflow, dur, &dupOrig);
if (lserr != lserrNone) return lserr;
if (dup != dupOrig)
pdobjText->txtf |= txtfSkipAtWysi;
}
else
{
lserr = GetOneCharDup(pilsobj, plsrun, wchPres, pfmtin->lsfgi.lstflow, dur, &dup);
if (lserr != lserrNone) return lserr;
}
cwchRun = (long)pfmtin->lsfrun.cwchRun;
pwchRun = pfmtin->lsfrun.lpwchRun;
/* check if there are a few identical characters and calculate their number -- we can format them all at once */
for (iNumOfChars = 1; iNumOfChars < cwchRun && pwchRun[0] == pwchRun[iNumOfChars]; iNumOfChars++);
durGlobal = 0;
Assert(iNumOfChars > 0);
Assert (dur <= uLsInfiniteRM / iNumOfChars);
if (dur > uLsInfiniteRM / iNumOfChars)
return lserrTooLongParagraph;
/* Don't forget to write at least one char even if pen was positioned behind right margin */
lserr = AddCharacterWithWidth(plnobj, pdobjText, wchRef, dur, wchPres, dup);
if (lserr != lserrNone) return lserr;
durWidth -= dur;
durGlobal += dur;
for (i = 1; i < iNumOfChars && (durWidth >= 0 || txtkind == txtkindSpecSpace); i++)
{
lserr = AddCharacterWithWidth(plnobj, pdobjText, wchRef, dur, wchPres, dup);
if (lserr != lserrNone) return lserr;
durWidth -= dur;
durGlobal += dur;
}
iNumOfChars = i;
*pfmtr = fmtrCompletedRun;
if (durWidth < 0 && txtkind != txtkindSpecSpace) /* Don't stop formatting while in spaces */
*pfmtr = fmtrExceededMargin;
if (fVisible)
pdobjText->txtf |= txtfVisi;
lserr = FillRealFmtOut(pilsobj, iNumOfChars, durGlobal, pdobjText, pfmtin,
txtkind == txtkindSpecSpace);
if (lserr != lserrNone) return lserr;
return lserrNone;
}
/* F M T R H A R D B R E A K */
/*----------------------------------------------------------------------------
%%Function: FmtrHardBreak
%%Contact: sergeyge
Calculates fmtr based on clab for the hard breaks.
----------------------------------------------------------------------------*/
static STOPRES StoprHardBreak(CLABEL clab)
{
switch (clab)
{
case clabSectionBreak:
return stoprEndSection;
case clabPageBreak:
return stoprEndPage;
case clabColumnBreak:
return stoprEndColumn;
default:
NotReached();
return 0;
}
}
/* C L A B F R O M C H A R */
/*----------------------------------------------------------------------------
%%Function: ClabFromChar
%%Contact: sergeyge
Calculates clab for wch
----------------------------------------------------------------------------*/
static CLABEL ClabFromChar(PILSOBJ pilsobj, WCHAR wch) /* REVIEW sergeyge - the whole procedure can be fixed */
{
DWORD i;
if (wch < 0x00FF)
{
return (CLABEL)(pilsobj->rgbSwitch[wch] & fSpecMask);
}
else
{
if (pilsobj->rgbSwitch[wch & 0x00FF] & clabSuspicious)
{
/*
REVIEW sergeyge (elik) It does not make sense to make bin search while
there are two wide special characters only. It would make sense to switch
to binary search as soon as this number is more than 4.
*/
for (i=0; i < pilsobj->cwchSpec && wch != pilsobj->rgwchSpec[i]; i++);
if (i == pilsobj->cwchSpec)
{
return clabRegular;
}
else
{
return pilsobj->rgbKind[i];
}
}
else
{
return clabRegular;
}
}
}