windows-nt/Source/XPSP1/NT/windows/richedit/lssrc/lsdnfin.c

606 lines
18 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/* LSDNFIN.C */
#include "lsdnfin.h"
#include "lsidefs.h"
#include "lsc.h"
#include "getfmtst.h"
#include "setfmtst.h"
#include "dninfo.h"
#include "lschp.h"
#include "lsffi.h"
#include "iobj.h"
#include "dnutils.h"
#include "lsfrun.h"
#include "lsfetch.h"
#include "qheap.h"
#include "sublutil.h"
#include "lsmem.h"
#include "lscfmtfl.h"
#include "ntiman.h"
#ifdef DEBUG
#define DebugMemset(a,b,c) if ((a) != NULL) memset(a,b,c); else
#else
#define DebugMemset(a,b,c) (void)(0)
#endif
#define IsLschpFlagsValid(plsc, plschp) fTrue
/* Word violates condition bellow and it is not very important to us, so I deleted body of this macro,
but not deleted macro itself to have a place where to put such checks later */
// ((((plsc)->lsadjustcontext.lsbrj == lsbrjBreakWithCompJustify) || ((plsc)->lsadjustcontext.lskj == lskjSnapGrid)) ? \
// fTrue :\
// (!((plschp)->fCompressOnRun || (plschp)->fCompressSpace || (plschp)->fCompressTable)))
/* L S D N F I N I S H R E G U L A R */
/*----------------------------------------------------------------------------
%%Function: LsdnFinishRegular
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
lsdcp - (IN) dcp adopted
plsrun - (IN) plsrun of dnode
plschp - (IN) plschp of dnode
pdobj - (IN) pdobj of dnode
pobjdim - (IN) pobjdim of dnode
Finish creating dnode
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnFinishRegular(
PLSC plsc,
LSDCP lsdcp,
PLSRUN plsrun,
PCLSCHP plschp,
PDOBJ pdobj,
PCOBJDIM pobjdim)
{
PLSDNODE plsdn;
LSERR lserr;
PLSSUBL plssubl;
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FFormattingAllowed(plsc)) return lserrFormattingFunctionDisabled;
/* all sublines should be closed */
if (GetCurrentSubline(plsc) != NULL) return lserrFormattingFunctionDisabled;
plsdn = GetDnodeToFinish(plsc);
if (plsdn == NULL) return lserrFiniFunctionDisabled;
plssubl = SublineFromDnode(plsdn);
plsdn->u.real.pdobj = pdobj;
/* if handler changed plsrun that we passed to him than we should release previous one */
/* Attention: we have assumption here that new one has another plsrun */
if (plsdn->u.real.plsrun != plsrun && !plsc->fDontReleaseRuns)
{
lserr = plsc->lscbk.pfnReleaseRun(plsc->pols, plsdn->u.real.plsrun);
plsdn->u.real.plsrun = plsrun; /* to release it later */
if (lserr != lserrNone)
return lserr;
}
plsdn->dcp = lsdcp;
plsdn->cpLimOriginal = plsdn->cpFirst + lsdcp;
Assert(FIsDnodeReal(plsdn)); /* this is default value */
Assert(pobjdim->dur >= 0);
SetDnodeObjdimFmt(plsdn, *pobjdim);
Assert(IsLschpFlagsValid(plsc, plschp));
plsdn->u.real.lschp = *plschp;
/* Special effects */
plsc->plslineCur->lslinfo.EffectsFlags |= plschp->EffectsFlags;
/* set flags for display */
if (plschp->dvpPos != 0)
TurnOnNonZeroDvpPosEncounted(plsc);
AddToAggregatedDisplayFlags(plsc, plschp);
if (FApplyNominalToIdeal(plschp))
TurnOnNominalToIdealEncounted(plsc);
if (plsdn->u.real.lschp.idObj == idObjTextChp)
plsdn->u.real.lschp.idObj = (WORD) IobjTextFromLsc(&plsc->lsiobjcontext);
AssertImplies(plsc->lsdocinf.fPresEqualRef,
plsdn->u.real.objdim.heightsPres.dvAscent == plsdn->u.real.objdim.heightsRef.dvAscent);
AssertImplies(plsc->lsdocinf.fPresEqualRef,
plsdn->u.real.objdim.heightsPres.dvDescent == plsdn->u.real.objdim.heightsRef.dvDescent);
AssertImplies(plsc->lsdocinf.fPresEqualRef,
plsdn->u.real.objdim.heightsPres.dvMultiLineHeight
== plsdn->u.real.objdim.heightsRef.dvMultiLineHeight);
/* nobody can change current dnode after plsdn was constructed */
Assert(GetCurrentDnodeSubl(plssubl) == plsdn->plsdnPrev);
*(GetWhereToPutLinkSubl(plssubl, plsdn->plsdnPrev)) = plsdn;
SetCurrentDnodeSubl(plssubl, plsdn);
SetDnodeToFinish(plsc, NULL);
AdvanceCurrentCpLimSubl(plssubl, lsdcp);
AdvanceCurrentUrSubl(plssubl, pobjdim->dur);
return lserrNone;
}
/* L S D N F I N I S H R E G U L A R A D D A D V A N C E D P E N */
/*----------------------------------------------------------------------------
%%Function: LsdnFinishRegularAddAdvancePen
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
lsdcp - (IN) dcp adopted
plsrun - (IN) plsrun of dnode
plschp - (IN) plschp of dnode
pdobj - (IN) pdobj of dnode
pobjdim - (IN) pobjdim of dnode
durPen - (IN) dur of advanced pen
dvrPen - (IN) dvr of advanced pen
dvpPen - (IN) dvp of advanced pen
Finish creating dnode and add advanced pen after such dnode
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnFinishRegularAddAdvancePen(
PLSC plsc, /* IN: Pointer to LS Context */
LSDCP lsdcp, /* IN: dcp adopted */
PLSRUN plsrun, /* IN: PLSRUN */
PCLSCHP plschp, /* IN: CHP */
PDOBJ pdobj, /* IN: PDOBJ */
PCOBJDIM pobjdim, /* IN: OBJDIM */
long durPen, /* IN: durPen */
long dvrPen, /* IN: dvrPen */
long dvpPen) /* IN: dvpPen */
{
LSERR lserr;
PLSDNODE plsdnPrev;
PLSDNODE plsdnPen;
PLSSUBL plssubl;
/* we don't have checks of parameters here because they are in LsdnFinishRegular */
plsdnPrev = GetDnodeToFinish(plsc); /* we should store it before calling LsdnFinishRegular */
plssubl = SublineFromDnode(plsdnPrev);
lserr = LsdnFinishRegular(plsc, lsdcp, plsrun, plschp, pdobj, pobjdim);
if (lserr != lserrNone)
return lserr;
/* create and fill in pen dnode */
plsdnPen = PvNewQuick(GetPqhAllDNodes(plsc), sizeof *plsdnPen);
if (plsdnPen == NULL)
return lserrOutOfMemory;
plsdnPen->tag = tagLSDNODE;
plsdnPen->cpFirst = GetCurrentCpLimSubl(plssubl);
plsdnPen->cpLimOriginal = plsdnPen->cpFirst;
plsdnPen->plsdnPrev = plsdnPrev;
plsdnPen->plsdnNext = NULL;
plsdnPen->plssubl = plssubl;
plsdnPen->dcp = 0;
/* flush all flags, bellow check that result is what we expect */ \
*((DWORD *) ((&(plsdnPen)->dcp)+1)) = 0;\
Assert((plsdnPen)->fRigidDup == fFalse);\
Assert((plsdnPen)->fTab == fFalse);\
Assert((plsdnPen)->icaltbd == 0);\
Assert((plsdnPen)->fBorderNode == fFalse);\
Assert((plsdnPen)->fOpenBorder == fFalse);\
Assert((plsdnPen)->fEndOfSection == fFalse); \
Assert((plsdnPen)->fEndOfColumn == fFalse); \
Assert((plsdnPen)->fEndOfPage == fFalse); \
Assert((plsdnPen)->fEndOfPara == fFalse); \
Assert((plsdnPen)->fAltEndOfPara == fFalse); \
Assert((plsdnPen)->fSoftCR == fFalse); \
Assert((plsdnPen)->fInsideBorder == fFalse); \
Assert((plsdnPen)->fAutoDecTab == fFalse); \
Assert((plsdnPen)->fTabForAutonumber == fFalse);
plsdnPen->klsdn = klsdnPenBorder;
plsdnPen->fAdvancedPen = fTrue;
SetPenBorderDurFmt(plsdnPen, durPen);
plsdnPen->u.pen.dvr = dvrPen;
plsdnPen->u.pen.dvp = dvpPen;
/* maintain list */
plsdnPrev->plsdnNext = plsdnPen;
SetCurrentDnodeSubl(plssubl, plsdnPen);
AdvanceCurrentUrSubl(plssubl, durPen);
AdvanceCurrentVrSubl(plssubl, dvrPen);
if (durPen < 0)
plsc->fAdvanceBack = fTrue;
TurnOnNonRealDnodeEncounted(plsc);
return lserrNone;
}
/* L S D N F I N I S H D E L E T E */
/*----------------------------------------------------------------------------
%%Function: LsdnFinishDelete
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
lsdcp - (IN) dcp adopted
Delete dnode due to the will of formater
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnFinishDelete(
PLSC plsc, /* IN: Pointer to LS Context */
LSDCP lsdcp) /* IN: dcp to add */
{
PLSDNODE plsdn;
PLSSUBL plssubl;
LSERR lserr;
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FFormattingAllowed(plsc)) return lserrFormattingFunctionDisabled;
/* all sublines should be closed */
if (GetCurrentSubline(plsc) != NULL) return lserrFormattingFunctionDisabled;
plsdn = GetDnodeToFinish(plsc);
if (plsdn == NULL) return lserrFiniFunctionDisabled;
plssubl = SublineFromDnode(plsdn);
/* nobody can change current dnode after plsdn was constructed */
Assert(GetCurrentDnodeSubl(plssubl) == plsdn->plsdnPrev);
Assert(plsdn->plsdnNext == NULL);
lserr = DestroyDnodeList (&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
plsdn, plsc->fDontReleaseRuns);
if (lserr != lserrNone)
return lserr;
SetDnodeToFinish(plsc, NULL);
AdvanceCurrentCpLimSubl(plssubl, lsdcp);
return lserrNone;
}
/* L S D N F I N I S H P E N */
/*----------------------------------------------------------------------------
%%Function: LsdnFinishSimpleRegular
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
lsdcp - (IN) dcp adopted
plsrun - (IN) plsrun of dnode
plschp - (IN) plschp of dnode
dur, dvr, dvp - (IN) variables to put in pen dnode
Finish dnode as a pen
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnFinishByPen(PLSC plsc, /* IN: Pointer to LS Context */
LSDCP lsdcp, /* IN: dcp adopted */
PLSRUN plsrun, /* IN: PLSRUN */
PDOBJ pdobj, /* IN: PDOBJ */
long durPen, /* IN: dur */
long dvrPen, /* IN: dvr */
long dvpPen) /* IN: dvp */
{
PLSDNODE plsdn;
LSERR lserr;
PLSSUBL plssubl;
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FFormattingAllowed(plsc)) return lserrFormattingFunctionDisabled;
/* all sublines should be closed */
if (GetCurrentSubline(plsc) != NULL) return lserrFormattingFunctionDisabled;
plsdn = GetDnodeToFinish(plsc);
if (plsdn == NULL) return lserrFiniFunctionDisabled;
plssubl = SublineFromDnode(plsdn);
if (plsrun != NULL && !plsc->fDontReleaseRuns)
{
lserr = plsc->lscbk.pfnReleaseRun(plsc->pols, plsrun);
if (lserr != lserrNone) return lserr;
}
/* caller pass pdobj to us only to destroy it*/
if (pdobj != NULL)
{
Assert(plsdn->u.real.lschp.idObj != idObjTextChp);
lserr = (PLsimFromLsc(&plsc->lsiobjcontext,
plsdn->u.real.lschp.idObj))->pfnDestroyDObj (pdobj);
if (lserr != lserrNone) return lserr;
}
plsdn->dcp = lsdcp;
plsdn->cpLimOriginal = plsdn->cpFirst + lsdcp;
plsdn->klsdn = klsdnPenBorder;
plsdn->fBorderNode = fFalse;
SetPenBorderDurFmt(plsdn, durPen);
plsdn->u.pen.dvr = dvrPen;
plsdn->u.pen.dvp = dvpPen;
/* nobody can change current dnode after plsdn was constructed */
Assert(GetCurrentDnodeSubl(plssubl) == plsdn->plsdnPrev);
*(GetWhereToPutLinkSubl(plssubl, plsdn->plsdnPrev)) = plsdn;
SetCurrentDnodeSubl(plssubl, plsdn);
SetDnodeToFinish(plsc, NULL);
AdvanceCurrentCpLimSubl(plssubl, lsdcp);
AdvanceCurrentUrSubl(plssubl, durPen);
AdvanceCurrentVrSubl(plssubl, dvrPen);
TurnOnNonRealDnodeEncounted(plsc);
return lserrNone;
}
/* L S D N F I N I S H B Y S U B L I N E*/
/*----------------------------------------------------------------------------
%%Function: LsdnFinishBySubline
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
lsdcp - (IN) increase cp by this number before hanldler ends
plssubl - (IN) subline to substitute dnode to finish
Delete dnode and include child list in the upper level
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnFinishBySubline(PLSC plsc, /* IN: Pointer to LS Context */
LSDCP lsdcp, /* IN: dcp adopted */
PLSSUBL plssubl) /* IN: Subline context */
{
PLSDNODE plsdnParent;
PLSDNODE plsdnChildFirst;
PLSDNODE plsdnChildCurrent, plsdnChildPrevious;
PLSSUBL plssublParent;
LSERR lserr;
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FFormattingAllowed(plsc)) return lserrFormattingFunctionDisabled;
/* all sublines should be closed */
if (GetCurrentSubline(plsc) != NULL) return lserrFormattingFunctionDisabled;
plsdnParent = GetDnodeToFinish(plsc);
if (plsdnParent == NULL) return lserrFiniFunctionDisabled;
plssublParent = SublineFromDnode(plsdnParent);
AdvanceCurrentCpLimSubl(plssublParent, lsdcp);
plsdnChildFirst = plssubl->plsdnFirst;
/* go through child list change subline and calculate resulting pen movement */
plsdnChildCurrent = plsdnChildFirst;
plsdnChildPrevious = NULL;
while (plsdnChildPrevious != plssubl->plsdnLast)
{
plsdnChildCurrent->plssubl = plssublParent;
AdvanceCurrentUrSubl(plssublParent, DurFromDnode(plsdnChildCurrent));
AdvanceCurrentVrSubl(plssublParent, DvrFromDnode(plsdnChildCurrent));
plsdnChildPrevious = plsdnChildCurrent;
plsdnChildCurrent = plsdnChildCurrent->plsdnNext;
}
/* include subline's list to upper level */
*(GetWhereToPutLinkSubl(plssublParent, plsdnParent->plsdnPrev)) = plsdnChildFirst;
if (plsdnChildFirst != NULL && plsdnParent->plsdnPrev != NULL)
plsdnChildFirst->plsdnPrev = plsdnParent->plsdnPrev;
/* if subline's list is empty than dnode before parent should be made current */
if (plsdnChildFirst == NULL)
{
/* if subline's list is empty than dnode before parent should be made current */
SetCurrentDnodeSubl(plssublParent, plsdnParent->plsdnPrev);
}
else
{
/* else last dnode in subline is now current dnode */
SetCurrentDnodeSubl(plssublParent, plssubl->plsdnLast);
}
/* delete parent dnode */
lserr = DestroyDnodeList (&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
plsdnParent, plsc->fDontReleaseRuns);
if (lserr != lserrNone)
return lserr;
/* set first dnode of subline to NULL and destroy subline will not erase dnodes that has
been promoted to the upper level */
plssubl->plsdnFirst = NULL;
lserr = DestroySublineCore(plssubl,&plsc->lscbk, plsc->pols,
&plsc->lsiobjcontext, plsc->fDontReleaseRuns);
if (lserr != lserrNone)
return lserr;
SetDnodeToFinish(plsc, NULL);
return lserrNone;
}
/* L S D N F I N I S H D E L E T E A L L*/
/*----------------------------------------------------------------------------
%%Function: LsdnFinishDeleteAll
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
dcpToAdvance - (IN) increase cp by this number before hanldler ends
Delete parent dnode and include child list in the upper level
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnFinishDeleteAll(PLSC plsc, /* IN: Pointer to LS Context */
LSDCP lsdcp) /* IN: dcp adopted */
{
PLSDNODE plsdnParent;
PLSDNODE plsdnFirstOnLine;
PLSDNODE plsdnFirstInContents;
PLSDNODE plsdnLastBeforeContents;
LSERR lserr;
long dvpPen;
long durPen;
long dvrPen;
PLSSUBL plssublMain;
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FFormattingAllowed(plsc)) return lserrFormattingFunctionDisabled;
/* all sublines should be closed */
if (GetCurrentSubline(plsc) != NULL) return lserrFormattingFunctionDisabled;
plsdnParent = GetDnodeToFinish(plsc);
if (plsdnParent == NULL) return lserrFiniFunctionDisabled;
plssublMain = &plsc->plslineCur->lssubl;
AdvanceCurrentCpLimSubl(plssublMain, lsdcp);
plsdnFirstOnLine = plssublMain->plsdnFirst;
plsdnFirstInContents = plsdnFirstOnLine;
plsdnLastBeforeContents = NULL;
while (plsdnFirstInContents != NULL && FIsNotInContent(plsdnFirstInContents))
{
plsdnLastBeforeContents = plsdnFirstInContents;
plsdnFirstInContents = plsdnFirstInContents->plsdnNext;
}
/* restore state as it was before starting formatting content*/
plsc->lstabscontext.plsdnPendingTab = NULL;
plsc->plslineCur->lslinfo.fAdvanced = 0;
plsc->plslineCur->lslinfo.EffectsFlags = 0;
/* break link with contest*/
if (plsdnFirstInContents != NULL)
*(GetWhereToPutLinkSubl(plssublMain, plsdnFirstInContents->plsdnPrev)) = NULL;
/* set dnode to append */
SetCurrentDnodeSubl(plssublMain, plsdnLastBeforeContents);
/* set current subline */
SetCurrentSubline(plsc, plssublMain);
/* recalculate current position */
if (plsdnFirstInContents != NULL)
{
FindListFinalPenMovement(plsdnFirstInContents, plssublMain->plsdnLast,
&durPen, &dvrPen, &dvpPen);
AdvanceCurrentUrSubl(plssublMain, -durPen);
AdvanceCurrentVrSubl(plssublMain, -dvrPen);
}
/* delete content before this parent dnode */
if (plsdnFirstInContents != NULL)
{
lserr = DestroyDnodeList (&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
plsdnFirstInContents, plsc->fDontReleaseRuns);
if (lserr != lserrNone)
return lserr;
}
/* delete parent dnode and child list*/
lserr = DestroyDnodeList (&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
plsdnParent, plsc->fDontReleaseRuns);
if (lserr != lserrNone)
return lserr;
SetDnodeToFinish(plsc, NULL);
return lserrNone;
}
LSERR WINAPI LsdnFinishByOneChar( /* allows replacement by simple DNODE only */
PLSC plsc, /* IN: Pointer to LS Context */
long urColumnMax, /* IN: urColumnMax */
WCHAR ch, /* IN: character to replace */
PCLSCHP plschp, /* IN: lschp for character */
PLSRUN plsrun, /* IN: plsrun for character */
FMTRES* pfmtres) /* OUT:Result of the Repl formatter*/
{
LSERR lserr;
LSFRUN lsfrun;
PLSDNODE plsdn;
PLSSUBL plssubl;
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FFormattingAllowed(plsc)) return lserrFormattingFunctionDisabled;
/* all sublines should be closed */
if (GetCurrentSubline(plsc) != NULL) return lserrFormattingFunctionDisabled;
plsdn = GetDnodeToFinish(plsc);
if (plsdn == NULL) return lserrFiniFunctionDisabled;
plssubl = SublineFromDnode(plsdn);
/* nobody can change current dnode after plsdn was constructed */
Assert(GetCurrentDnodeSubl(plssubl) == plsdn->plsdnPrev);
if (plsdn->dcp != 1) return lserrWrongFiniFunction;
lserr = LsdnFinishDelete(plsc, 0);
if (lserr != lserrNone)
return lserr;
Assert(IsLschpFlagsValid(plsc, plschp));
lsfrun.plschp = plschp;
/* Special effects */
plsc->plslineCur->lslinfo.EffectsFlags |= plschp->EffectsFlags;
lsfrun.plsrun = plsrun;
lsfrun.lpwchRun = &ch;
lsfrun.cwchRun = 1;
/* to ProcessOneRun work properly we need to temporarely restore current subline */
SetCurrentSubline(plsc, plssubl);
lserr = ProcessOneRun(plsc, urColumnMax, &lsfrun, NULL, 0, pfmtres);
if (lserr != lserrNone)
return lserr;
SetCurrentSubline(plsc, NULL);
return lserrNone;
}