windows-nt/Source/XPSP1/NT/windows/richedit/lssrc/lsdnset.c
2020-09-26 16:20:57 +08:00

673 lines
19 KiB
C

#include "lsdnset.h"
#include "lsc.h"
#include "lsdnode.h"
#include "dnutils.h"
#include "iobj.h"
#include "ntiman.h"
#include "tabutils.h"
#include "getfmtst.h"
#include "setfmtst.h"
#include "lstext.h"
#include "dninfo.h"
#include "chnutils.h"
#include "lssubl.h"
#include "sublutil.h"
#include "lscfmtfl.h"
#include "iobjln.h"
#include "lsmem.h" /* memset() */
#define FColinearTflows(t1, t2) \
(((t1) & fUVertical) == ((t2) & fUVertical))
/* L S D N Q U E R Y O B J D I M R A N G E */
/*----------------------------------------------------------------------------
%%Function: LsdnQueryObjDimRange
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
plsdnFirst - (IN) first dnode in the range
plsdnLast - (IN) last dnode in the range
pobjdim - (OUT) geometry of the range
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnQueryObjDimRange(PLSC plsc,
PLSDNODE plsdnFirst, PLSDNODE plsdnLast,
POBJDIM pobjdim)
{
PLSDNODE plsdn;
LSERR lserr;
if (pobjdim == NULL)
return lserrNullOutputParameter;
if (!FIsLSC(plsc))
return lserrInvalidContext;
/* if client call us with empty range return right away */
if (plsdnFirst == NULL)
{
if (plsdnLast != NULL)
return lserrInvalidDnode;
memset(pobjdim, 0, sizeof(OBJDIM));
return lserrNone;
}
if (!FIsLSDNODE(plsdnFirst))
return lserrInvalidDnode;
if (!FIsLSDNODE(plsdnLast))
return lserrInvalidDnode;
if (plsdnFirst->plssubl != plsdnLast->plssubl)
return lserrInvalidDnode;
/* we should call NominalToIdeal if we are in formating stage and range intersects last chunk
and this chunk is chunk of text*/
plsdn = plsdnLast;
/* to find chunk where we are we should skip back borders */
while (plsdn != NULL && FIsDnodeBorder(plsdn))
{
plsdn = plsdn->plsdnPrev;
}
if ((plsc->lsstate == LsStateFormatting) &&
FNominalToIdealEncounted(plsc) &&
(plsdn != NULL) &&
FIsDnodeReal(plsdn) &&
(IdObjFromDnode(plsdn) == IobjTextFromLsc(&plsc->lsiobjcontext))
)
{
for(; !FIsChunkBoundary(plsdn->plsdnNext, IobjTextFromLsc(&plsc->lsiobjcontext),
plsdnLast->cpFirst);
plsdn=plsdn->plsdnNext);
if (plsdn->plsdnNext == NULL)
{
lserr = ApplyNominalToIdeal(PlschunkcontextFromSubline(plsdnFirst->plssubl),
&plsc->lsiobjcontext, plsc->grpfManager, plsc->lsadjustcontext.lskj,
FIsSubLineMain(SublineFromDnode(plsdn)), FLineContainsAutoNumber(plsc),
plsdn);
if (lserr != lserrNone)
return lserr;
}
}
return FindListDims(plsdnFirst, plsdnLast, pobjdim);
}
/* L S D N G E T C U R T A B I N F O */
/*----------------------------------------------------------------------------
%%Function: LsdnGetCurTabInfo
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
plsktab - (OUT) type of current tab
Finds tab stop nearest to the current pen position and returns type of such tab stop.
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnGetCurTabInfo(PLSC plsc, LSKTAB* plsktab)
{
PLSDNODE plsdnTab;
LSTABSCONTEXT* plstabscontext;
BOOL fBreakThroughTab;
LSERR lserr;
long urNewMargin;
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FFormattingAllowed(plsc)) return lserrFormattingFunctionDisabled;
if (plsktab == NULL) return lserrInvalidParameter;
plsdnTab = GetCurrentDnode(plsc);
plstabscontext = &(plsc->lstabscontext);
Assert(FIsLSDNODE(plsdnTab));
if (!plsdnTab->fTab) return lserrCurrentDnodeIsNotTab;
Assert(FIsDnodeReal(plsdnTab));
if (plstabscontext->plsdnPendingTab != NULL) return lserrPendingTabIsNotResolved;
lserr = GetCurTabInfoCore(&plsc->lstabscontext, plsdnTab, GetCurrentUr(plsc), fFalse,
plsktab, &fBreakThroughTab);
if (lserr != lserrNone)
return lserr;
TurnOnTabEncounted(plsc);
if (*plsktab != lsktLeft)
TurnOnNonLeftTabEncounted(plsc);
/* move current pen position */
AdvanceCurrentUr(plsc, DurFromDnode(plsdnTab));
if (fBreakThroughTab)
{
lserr = GetMarginAfterBreakThroughTab(&plsc->lstabscontext, plsdnTab, &urNewMargin);
if (lserr != lserrNone)
return lserr;
SetBreakthroughLine(plsc, urNewMargin);
}
return lserrNone;
}
/* L S D N R E S O L V E P R E V T A B */
/*----------------------------------------------------------------------------
%%Function: LsdnResolvePrevTab
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnResolvePrevTab(PLSC plsc)
{
long dur;
LSERR lserr;
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FFormattingAllowed(plsc)) return lserrFormattingFunctionDisabled;
lserr = ResolvePrevTabCore(&plsc->lstabscontext, GetCurrentDnode(plsc), GetCurrentUr(plsc),
&dur);
if (lserr != lserrNone)
return lserr;
AdvanceCurrentUr(plsc, dur);
return lserrNone;
}
/* L S D N S K I P C U R T A B */
/*----------------------------------------------------------------------------
%%Function: LsdnSkipCurTab
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnSkipCurTab(PLSC plsc) /* IN: Pointer to LS Context */
{
PLSDNODE plsdnTab;
LSTABSCONTEXT* plstabscontext;
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FFormattingAllowed(plsc)) return lserrFormattingFunctionDisabled;
plsdnTab = GetCurrentDnode(plsc);
plstabscontext = &(plsc->lstabscontext);
Assert(FIsLSDNODE(plsdnTab));
if (!plsdnTab->fTab) return lserrCurrentDnodeIsNotTab;
Assert(FIsDnodeReal(plsdnTab));
if (plstabscontext->plsdnPendingTab != NULL)
{
CancelPendingTab(&plsc->lstabscontext);
}
else
{
AdvanceCurrentUr(plsc, - plsdnTab->u.real.objdim.dur);
SetDnodeDurFmt(plsdnTab, 0);
}
return lserrNone;
}
/* L S D N S E T R I G I D D U P */
/*----------------------------------------------------------------------------
%%Function: LsdnSetRigidDup
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
plsdn - (IN) dnode to be modified
dup - (IN) dup to put in the dnode
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnSetRigidDup(PLSC plsc, PLSDNODE plsdn, long dup)
{
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FIsLSDNODE(plsdn)) return lserrInvalidParameter;
if (!FFormattingAllowed(plsc)) return lserrFormattingFunctionDisabled;
plsdn->fRigidDup = fTrue;
if (plsdn->klsdn == klsdnReal)
{
plsdn->u.real.dup = dup;
}
else
{
plsdn->u.pen.dup = dup;
}
return lserrNone;
}
/* L S D N G E T D U P */
/*----------------------------------------------------------------------------
%%Function: LsdnGetDup
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
plsdn - (IN) dnode queried
dup - (OUT) dup of this dnode
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnGetDup(PLSC plsc, PLSDNODE plsdn, long* pdup)
{
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FIsLSDNODE(plsdn)) return lserrInvalidParameter;
/* check that dup in dnode is valid */
if (plsdn->plssubl->fDupInvalid && !plsdn->fRigidDup)
return lserrDupInvalid;
*pdup = DupFromDnode(plsdn);
return lserrNone;
}
/* L S D N R E S E T O B J D I M */
/*----------------------------------------------------------------------------
%%Function: LsdnResetObjDim
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
plsdn - (IN) dnode to be modified
pobjdimNew - (IN) new dimensions of the dnode
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnResetObjDim(PLSC plsc, PLSDNODE plsdn, PCOBJDIM pobjdimNew)
{
long durOld;
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FIsLSDNODE(plsdn)) return lserrInvalidParameter;
if (!FIsDnodeReal(plsdn)) return lserrInvalidParameter;
/* we should be in the stage of formatting or breaking */
if (!FFormattingAllowed(plsc) && !FBreakingAllowed(plsc))
return lserrFormattingFunctionDisabled;
durOld = plsdn->u.real.objdim.dur;
SetDnodeObjdimFmt(plsdn, *pobjdimNew);
/* update current pen position */
AdvanceCurrentUrSubl(plsdn->plssubl, (plsdn->u.real.objdim.dur - durOld));
return lserrNone;
}
/* L S D N R E S E T P E N N O D E */
/*----------------------------------------------------------------------------
%%Function: LsdnResetPenNode
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
plsdnPen - (IN) dnode to be modified
dvpPen - (IN) new dvp of the dnode
durPen - (IN) new dur of the dnode
dvrPen - (IN) new dvr of the dnode
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnResetPenNode(PLSC plsc, PLSDNODE plsdnPen,
long dvpPen, long durPen, long dvrPen)
{
long durOld;
long dvrOld;
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FIsLSDNODE(plsdnPen)) return lserrInvalidParameter;
if (!FIsDnodePen(plsdnPen)) return lserrInvalidParameter;
/* we should be in the stage of formatting */
if (!FFormattingAllowed(plsc)) return lserrFormattingFunctionDisabled;
if (GetDnodeToFinish(plsc) == NULL) return lserrFormattingFunctionDisabled;
if (!FIsDnodeReal(GetDnodeToFinish(plsc)) )
return lserrFormattingFunctionDisabled;
if (plsdnPen->plssubl != GetCurrentSubline(plsc)) return lserrInvalidParameter;
durOld = plsdnPen->u.pen.dur;
dvrOld = plsdnPen->u.pen.dvr;
plsdnPen->u.pen.dvp = dvpPen;
SetPenBorderDurFmt(plsdnPen, durPen);
plsdnPen->u.pen.dvr = dvrPen;
/* update current pen position */
AdvanceCurrentUr(plsc, plsdnPen->u.pen.dur - durOld);
AdvanceCurrentVr(plsc, plsdnPen->u.pen.dvr - dvrOld);
return lserrNone;
}
/* L S D N Q U E R Y N O D E */
/*----------------------------------------------------------------------------
%%Function: LsdnQueryPenNode
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
plsdnPen - (IN) dnode quried
pdvpPen - (OUT) dvp of the dnode
pdurPen - (OUT) dur of the dnode
pdvrPen - (OUT) dvr of the dnode
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnQueryPenNode(PLSC plsc, PLSDNODE plsdnPen,
long* pdvpPen, long* pdurPen, long* pdvrPen)
{
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FIsLSDNODE(plsdnPen)) return lserrInvalidParameter;
if (!FIsDnodePen(plsdnPen)) return lserrInvalidParameter;
*pdvpPen = plsdnPen->u.pen.dvp;
*pdurPen = plsdnPen->u.pen.dur;
*pdvrPen = plsdnPen->u.pen.dvr;
return lserrNone;
}
/* L S D N S E T A B S B A S E L I N E */
/*----------------------------------------------------------------------------
%%Function: LsdnSetAbsBaseLine
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
vaAdvanceNew - (IN) new vaBase
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnSetAbsBaseLine(PLSC plsc, long vaAdvanceNew)
{
if (!FIsLSC(plsc)) return lserrInvalidParameter;
/* we should be in the stage of formatting*/
if (!FFormattingAllowed(plsc)) return lserrFormattingFunctionDisabled;
plsc->plslineCur->lslinfo.fAdvanced = fTrue;
plsc->plslineCur->lslinfo.vaAdvance = vaAdvanceNew;
return lserrNone;
}
#define PlnobjFromLsc(plsc,iobj) ((Assert(FIsLSC(plsc)), PlnobjFromLsline((plsc)->plslineCur,iobj)))
/* L S D N M O D I F Y P A R A E N D I N G*/
/*----------------------------------------------------------------------------
%%Function: LsdnModifyParaEnding
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
lskeop - (IN) Kind of line ending
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnModifyParaEnding(PLSC plsc, LSKEOP lskeop)
{
LSERR lserr;
DWORD iobjText;
PLNOBJ plnobjText;
if (!FIsLSC(plsc)) return lserrInvalidParameter;
/* we should be in the stage of formatting*/
if (!FFormattingAllowed(plsc)) return lserrFormattingFunctionDisabled;
iobjText = IobjTextFromLsc(&plsc->lsiobjcontext);
plnobjText = PlnobjFromLsc(plsc, iobjText);
lserr = ModifyTextLineEnding(plnobjText, lskeop);
return lserr;
}
/* L S D N D I S T R I B U T E */
/*----------------------------------------------------------------------------
%%Function: LsdnDistribute
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
plsdnFirst - (IN) first dnode in the range
plsdnFirst - (IN) last dnode in the range
durToDistribute - (IN) amount to distribute between dnodes
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnDistribute(PLSC plsc, PLSDNODE plsdnFirst,
PLSDNODE plsdnLast, long durToDistribute)
{
GRCHUNKEXT grchunkext;
LSERR lserr;
long durToNonText;
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FIsLSDNODE(plsdnFirst)) return lserrInvalidParameter;
if (!FIsLSDNODE(plsdnLast)) return lserrInvalidParameter;
/* we should be in the stage of formatting or breaking*/
if (!FFormattingAllowed(plsc) && !FBreakingAllowed(plsc))
return lserrFormattingFunctionDisabled;
InitGroupChunkExt(PlschunkcontextFromSubline(plsdnFirst->plssubl),
IobjTextFromLsc(&plsc->lsiobjcontext), &grchunkext);
/* skip first pen dnodes */
while (FIsDnodePen(plsdnFirst) && (plsdnFirst != plsdnLast))
{
plsdnFirst = plsdnFirst->plsdnNext;
if (plsdnFirst == NULL) /* plsdnFirst and plksdnLast are not in the same level */
return lserrInvalidParameter;
}
if (FIsDnodePen(plsdnFirst)) /* only pens are in the list so there is no business for us */
return lserrNone;
while (FIsDnodePen(plsdnLast) && (plsdnLast != plsdnFirst))
{
plsdnLast = plsdnLast->plsdnPrev;
if (plsdnLast == NULL) /* plsdnFirst and plksdnLast are not in the same level */
return lserrInvalidParameter;
}
Assert(!FIsDnodePen(plsdnLast));
lserr = CollectTextGroupChunk(plsdnFirst, plsdnLast->cpFirst + plsdnLast->dcp,
CollectSublinesNone, &grchunkext);
if (lserr != lserrNone)
return lserr;
/* Because of rigid dup it doesn't make sense to change dur of non text objects
We inforce text to distrubute everything among text by setting amount of
non text to 0 */
return DistributeInText(&(grchunkext.lsgrchnk),
LstflowFromSubline(SublineFromDnode(plsdnFirst)),
0, durToDistribute, &durToNonText);
}
/* L S D N S U B M I T S U B L I N E S */
/*----------------------------------------------------------------------------
%%Function: LsdnSubmitSublines
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
plsdnode - (IN) dnode
cSubline - (IN) amount of submitted sublines
rgpsubl - (IN) array of submitted sublines
fUseForJustification - (IN) to use for justification
fUseForCompression - (IN) to use for compression
fUseForDisplay - (IN) to use for display
fUseForDecimalTab - (IN) to use for decimal tab
fUseForTrailingArea - (IN) to use for calculating trailing area
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnSubmitSublines(PLSC plsc, PLSDNODE plsdnode,
DWORD cSubline, PLSSUBL* rgpsubl,
BOOL fUseForJustification, BOOL fUseForCompression,
BOOL fUseForDisplay, BOOL fUseForDecimalTab,
BOOL fUseForTrailingArea)
{
DWORD i;
BOOL fEmpty = fFalse;
BOOL fEmptyWork;
BOOL fTabOrPen = fFalse;
BOOL fNotColinearTflow = fFalse;
BOOL fNotSameTflow = fFalse;
LSERR lserr;
if (!FIsLSC(plsc)) return lserrInvalidParameter;
if (!FIsLSDNODE(plsdnode)) return lserrInvalidParameter;
if (!FIsDnodeReal(plsdnode)) return lserrInvalidParameter;
/* we should be in the stage of formatting or breaking*/
if (!FFormattingAllowed(plsc) && !FBreakingAllowed(plsc)) return lserrFormattingFunctionDisabled;
/* this procedure can be called many times for the same dnode, so
we should dispose memory allocated in previous call */
if (plsdnode->u.real.pinfosubl != NULL)
{
if (plsdnode->u.real.pinfosubl->rgpsubl != NULL)
{
plsc->lscbk.pfnDisposePtr(plsc->pols, plsdnode->u.real.pinfosubl->rgpsubl);
}
plsc->lscbk.pfnDisposePtr(plsc->pols, plsdnode->u.real.pinfosubl);
plsdnode->u.real.pinfosubl = NULL;
}
/* if nothing submitted return right away */
if (cSubline == 0)
return lserrNone;
TurnOnSubmittedSublineEncounted(plsc);
/* calculate some properties of sublines to decide accept or not */
for (i = 0; i < cSubline; i++)
{
if (rgpsubl[i] == NULL) return lserrInvalidParameter;
if (!FIsLSSUBL(rgpsubl[i])) return lserrInvalidParameter;
lserr = FIsSublineEmpty(rgpsubl[i], &fEmptyWork);
if (lserr != lserrNone)
return lserr;
if (fEmptyWork) fEmpty = fTrue;
if (FAreTabsPensInSubline(rgpsubl[i]))
fTabOrPen = fTrue;
if (LstflowFromSubline(SublineFromDnode(plsdnode)) !=
LstflowFromSubline(rgpsubl[i]))
fNotSameTflow = fTrue;
if (!FColinearTflows(LstflowFromSubline(SublineFromDnode(plsdnode)),
LstflowFromSubline(rgpsubl[i])))
fNotColinearTflow = fTrue;
}
plsdnode->u.real.pinfosubl = plsc->lscbk.pfnNewPtr(plsc->pols,
sizeof(*(plsdnode->u.real.pinfosubl)));
if (plsdnode->u.real.pinfosubl == NULL)
return lserrOutOfMemory;
plsdnode->u.real.pinfosubl->cSubline = cSubline;
plsdnode->u.real.pinfosubl->rgpsubl = plsc->lscbk.pfnNewPtr(plsc->pols,
sizeof(PLSSUBL) * cSubline);
if (plsdnode->u.real.pinfosubl->rgpsubl == NULL)
return lserrOutOfMemory;
/* copy array of sublines */
for (i = 0; i < cSubline; i++)
{
plsdnode->u.real.pinfosubl->rgpsubl[i] = rgpsubl[i];
}
/* set flags */
plsdnode->u.real.pinfosubl->fUseForJustification =
fUseForJustification && !fEmpty && !fTabOrPen && !fNotColinearTflow ;
plsdnode->u.real.pinfosubl->fUseForCompression =
fUseForCompression && plsdnode->u.real.pinfosubl->fUseForJustification;
/* if subline is submitted for compression it should also submitted for justification */
plsdnode->u.real.pinfosubl->fUseForTrailingArea =
fUseForTrailingArea && plsdnode->u.real.pinfosubl->fUseForCompression;
/* if subline is submitted for trailing area it should also be submitted for compression
which implies submitting for justification */
plsdnode->u.real.pinfosubl->fUseForDisplay =
fUseForDisplay && !fEmpty && !(plsc->grpfManager & fFmiDrawInCharCodes);
plsdnode->u.real.pinfosubl->fUseForDecimalTab =
fUseForDecimalTab && !fEmpty && !fTabOrPen;
return lserrNone;
}
/* L S D N G E T F O R M A T D E P T H */
/*----------------------------------------------------------------------------
%%Function: LsdnGetFormatDepth
%%Contact: igorzv
Parameters:
plsc - (IN) ptr to line services context
pnDepthFormatLineMax - (OUT) maximum depth of sublines
----------------------------------------------------------------------------*/
LSERR WINAPI LsdnGetFormatDepth(
PLSC plsc, /* IN: Pointer to LS Context */
DWORD* pnDepthFormatLineMax) /* OUT: nDepthFormatLineMax */
{
if (!FIsLSC(plsc)) return lserrInvalidParameter;
/* we should be in the stage of formatting or breaking*/
if (!FFormattingAllowed(plsc) && !FBreakingAllowed(plsc))
return lserrFormattingFunctionDisabled;
Assert(FWorkWithCurrentLine(plsc));
*pnDepthFormatLineMax = plsc->plslineCur->lslinfo.nDepthFormatLineMax;
return lserrNone;
}