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

1567 lines
42 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
#include "lsmem.h"
#include "limits.h"
#include "lscbk.h"
#include "lsdevres.h"
#include "pdobj.h"
#include "objdim.h"
#include "plssubl.h"
#include "plsdnode.h"
#include "pilsobj.h"
#include "lscrsubl.h"
#include "lssubset.h"
#include "lsdnset.h"
#include "lsdocinf.h"
#include "lsidefs.h"
#include "fmti.h"
#include "posichnk.h"
#include "locchnk.h"
#include "lsdnfin.h"
#include "brko.h"
#include "lspap.h"
#include "plspap.h"
#include "lsqsubl.h"
#include "dispi.h"
#include "lsdssubl.h"
#include "lsems.h"
#include "lstfset.h"
#include "plnobj.h"
#include "plocchnk.h"
#include "lsimeth.h"
#include "robj.h"
#include "lsidefs.h"
#include "brkpos.h"
#include "objhelp.h"
#include "lssubset.h"
typedef enum breaksublinetype
{
breakSublineAfter,
breakSublineInside
} BREAKSUBLINETYPE;
struct ilsobj
{
POLS pols;
LSCBK lscbk;
PLSC plsc;
DWORD idobj;
LSESC lsesc;
PFNREVERSEGETINFO pfnReverseGetInfo;
PFNREVERSEENUM pfnReverseEnum;
};
typedef struct rbreakrec
{
BOOL fValid; /* Is this break record contains valid info? */
BREAKSUBLINETYPE breakSublineType; /* After / Inside */
LSCP cpBreak; /* CpLim of the break */
} RBREAKREC;
struct dobj
{
PILSOBJ pilsobj; /* ILS object */
LSTFLOW lstflowL; /* flow of line input */
LSTFLOW lstflowO; /* flow of this object */
BOOL fDoNotBreakAround; /* Break around robj as "can" */
BOOL fSuppressTrailingSpaces;
/* Kill trailing space when robj is
alone on the line & broken */
BOOL fFirstOnLine; /* If first on line -- required for
fSuppressTrailingSpaces */
PLSDNODE plsdnTop; /* Parent dnode */
LSCP cpStart; /* Starting LS cp for object */
LSCP cpStartObj; /* cp for start of object can be different
than cpStart if object is broken. */
LSCP cpFirstSubline; /* cpFirst of the subline; will be
equal to cpStart when object is broken and
equal to cpStart+1 when it isnot broken */
LSDCP dcpSubline; /* Number of characters in the subline */
LSDCP dcp; /* Number of characters in object */
PLSSUBL plssubl; /* Subline formatted RTL */
OBJDIM objdimAll; /* Objdim for entire object */
long dup; /* dup of object */
RBREAKREC breakRecord [NBreaksToSave];
/* Last 3 break records for each break */
};
static LSTFLOW rlstflowReverse[8] =
{
lstflowWS, /* Reverse lstflowES */
lstflowWN, /* Reverse lstflowEN */
lstflowNE, /* Reverse lstflowSE */
lstflowNW, /* Reverse lstflowSW */
lstflowES, /* Reverse lstflowWS */
lstflowEN, /* Reverse lstflowWN */
lstflowSE, /* Reverse lstflowNE */
lstflowSW /* Reverse lstflowNW */
};
/* R E V E R S E S A V E B R E A K R E C O R D */
/*----------------------------------------------------------------------------
%%Function: RobjSaveBreakRecord
%%Contact: antons
Save break record in DOBJ.
----------------------------------------------------------------------------*/
static void ReverseSaveBreakRecord (
PDOBJ pdobj,
BRKKIND brkkindWhatBreak,
BREAKSUBLINETYPE breakSublineType,
LSCP cpBreak)
{
DWORD ind = GetBreakRecordIndex (brkkindWhatBreak);
pdobj->breakRecord [ind].fValid = TRUE;
pdobj->breakRecord [ind].breakSublineType = breakSublineType;
pdobj->breakRecord [ind].cpBreak = cpBreak;
}
/* R E V E R S E G E T B R E A K R E C O R D */
/*----------------------------------------------------------------------------
%%Function: ReverseGetBreakRecord
%%Contact: antons
Read break record from DOBJ.
----------------------------------------------------------------------------*/
static void ReverseGetBreakRecord (
PDOBJ pdobj,
BRKKIND brkkindWhatBreak,
BREAKSUBLINETYPE *breakSublineType,
LSCP * pcpBreak )
{
DWORD ind = GetBreakRecordIndex (brkkindWhatBreak);
Assert (pdobj->breakRecord [ind].fValid);
*breakSublineType = pdobj->breakRecord [ind].breakSublineType;
*pcpBreak = pdobj->breakRecord [ind].cpBreak;
}
/* F R E E D O B J */
/*----------------------------------------------------------------------------
%%Function: ReverseFreeDobj
%%Contact: antons
Free all resources associated with this Reverse dobj.
----------------------------------------------------------------------------*/
static LSERR ReverseFreeDobj(PDOBJ pdobj)
{
LSERR lserr = lserrNone;
PILSOBJ pilsobj = pdobj->pilsobj;
if (pdobj->plssubl != NULL)
{
lserr = LsDestroySubline(pdobj->plssubl);
}
pilsobj->lscbk.pfnDisposePtr(pilsobj->pols, pdobj);
return lserr;
}
/* R E V E R S E F M T F A I L E D */
/*----------------------------------------------------------------------------
%%Function: ReverseFmtFailed
%%Contact: antons
Could not create Reverse DOBJ due to error.
----------------------------------------------------------------------------*/
static LSERR ReverseFmtFailed (PDOBJ pdobj, LSERR lserr)
{
if (pdobj != NULL) ReverseFreeDobj (pdobj); /* Works with parially-filled DOBJ */
return lserr;
}
/* T R A N S L A T E C P L I M S U B L I N E T O D C P E X T E R N A L
/*----------------------------------------------------------------------------
%%Function: TranslateCpLimSublineToDcpExternal
%%Contact: antons
Translates position (CpLim) in the subline to dcp of
the reverse object.
----------------------------------------------------------------------------*/
/* REVIEW (antons): Is old name OK for new behavior? */
LSDCP TranslateCpLimSublineToDcpExternal (PDOBJ pdobj, LSCP cpLim)
{
Unreferenced (pdobj);
Assert (cpLim <= pdobj->cpStart + (long) pdobj->dcp);
Assert (cpLim >= pdobj->cpStart);
Assert (pdobj->cpStart <= pdobj->cpFirstSubline);
Assert (pdobj->cpStart + pdobj->dcp >= pdobj->cpFirstSubline + pdobj->dcpSubline);
return cpLim - pdobj->cpStart;
}
/* T R A N S L A T E D C P E X T E R N A L T O C P L I M S U B L I N E
/*----------------------------------------------------------------------------
%%Function: TranslateCpLimInternalToExternal
%%Contact: antons
Translates position (dcp) in reverse object to cpLim of
the subline.
----------------------------------------------------------------------------*/
LSCP TranslateDcpExternalToCpLimSubline (PDOBJ pdobj, LSDCP dcp)
{
Unreferenced (pdobj);
Assert (dcp <= pdobj->dcp);
Assert (pdobj->cpStart <= pdobj->cpFirstSubline);
Assert (pdobj->cpStart + pdobj->dcp >= pdobj->cpFirstSubline + pdobj->dcpSubline);
return pdobj->cpStart + dcp;
}
/* F I N I S H B R E A K R E G U L A R */
/*----------------------------------------------------------------------------
%%Function: FinishBreakRegular
%%Contact: antons
Set up breaking information for proposed break point.
Caller must save break record by hiself!
----------------------------------------------------------------------------*/
static LSERR FinishBreakRegular (
DWORD ichnk, /* (IN): chunk id */
PDOBJ pdobj, /* (IN): object for break */
LSCP cpBreak, /* (IN): cp - break to report outside */
POBJDIM pobjdimSubline, /* (IN): objdim for subline at proposed break */
PBRKOUT pbrkout) /* (OUT): break info for Line Services */
{
Assert (ichnk != ichnkOutside);
pbrkout->fSuccessful = fTrue;
pbrkout->posichnk.dcp = TranslateCpLimSublineToDcpExternal (pdobj, cpBreak);
pbrkout->posichnk.ichnk = ichnk;
pbrkout->objdim = *pobjdimSubline;
return lserrNone;
}
/* P U T B R E A K A T E N D O F O B J E C T */
/*----------------------------------------------------------------------------
%%Function: PutBreakAtEndOfObject
%%Contact: antons
Fill in break output record for the end of the object.
----------------------------------------------------------------------------*/
static void PutBreakAtEndOfObject (
DWORD ichnk, /* (IN): index in chunk */
PCLOCCHNK pclocchnk, /* (IN): locchnk to find break */
PBRKOUT pbrkout) /* (OUT): results of breaking */
{
PDOBJ pdobj = pclocchnk->plschnk[ichnk].pdobj;
Assert (ichnk != ichnkOutside);
pbrkout->fSuccessful = fTrue;
pbrkout->posichnk.dcp = pdobj->dcp;
pbrkout->posichnk.ichnk = ichnk;
pbrkout->objdim = pdobj->objdimAll;
}
/* P U T B R E A K B E F O R E O B J E C T */
/*----------------------------------------------------------------------------
%%Function: PutBreakBeforeObject
%%Contact: antons
Fill in break output record for break before object.
----------------------------------------------------------------------------*/
static void PutBreakBeforeObject (
DWORD ichnk, /* (IN): index in chunk */
PCLOCCHNK pclocchnk, /* (IN): locchnk to find break */
PBRKOUT pbrkout) /* (OUT): results of breaking */
{
Unreferenced (pclocchnk);
Assert (ichnk != ichnkOutside);
pbrkout->fSuccessful = fTrue;
pbrkout->posichnk.dcp = 0;
pbrkout->posichnk.ichnk = ichnk;
ZeroMemory (&pbrkout->objdim, sizeof(pbrkout->objdim));
}
/* P U T B R E A K U N S U C C E S S F U L */
/*----------------------------------------------------------------------------
%%Function: PutBreakUnsuccessful
%%Contact: antons
Fill in break output record for unsuccessful break of ROBJ
----------------------------------------------------------------------------*/
static void PutBreakUnsuccessful (PDOBJ pdobj, PBRKOUT pbrkout)
{
pbrkout->fSuccessful = FALSE;
if (pdobj->fDoNotBreakAround) pbrkout->brkcond = brkcondCan;
else
pbrkout->brkcond = brkcondPlease;
}
/* I N I T D O B J */
/*----------------------------------------------------------------------------
%%Function: InitDobj
%%Contact: ricksa
Allocate and initialize DOBJ with basic information.
----------------------------------------------------------------------------*/
static LSERR InitDobj(
PILSOBJ pilsobj, /* (IN): ilsobj */
PCFMTIN pcfmtin, /* (IN): formatting input */
PDOBJ *ppdobj) /* (OUT): initialized dobj */
{
/* Assume failure */
LSERR lserr;
PDOBJ pdobj = (PDOBJ)
pilsobj->lscbk.pfnNewPtr(pilsobj->pols, sizeof(*pdobj));
if (pdobj != NULL)
{
int iBreakRec;
ZeroMemory(pdobj, sizeof(*pdobj));
pdobj->pilsobj = pilsobj;
pdobj->cpStart = pcfmtin->lsfgi.cpFirst;
pdobj->lstflowL = pcfmtin->lsfgi.lstflow;
pdobj->lstflowO = rlstflowReverse[(int) pcfmtin->lsfgi.lstflow];
pdobj->cpStartObj = pcfmtin->lsfgi.cpFirst;
for (iBreakRec = 0; iBreakRec < NBreaksToSave; iBreakRec++)
{
pdobj->breakRecord [iBreakRec].fValid = FALSE;
};
*ppdobj = pdobj;
lserr = lserrNone;
}
else
{
lserr = lserrOutOfMemory;
}
return lserr;
}
/* F I N I S H F M T */
/*----------------------------------------------------------------------------
%%Function: FinishFmt
%%Contact: ricksa
Helper for ReverseFmt & ReverseFmtResume that completes work
for formatting.
----------------------------------------------------------------------------*/
static LSERR FinishFmt(
PDOBJ pdobj, /* (IN): dobj for reverse */
PILSOBJ pilsobj, /* (IN): ILS object for Reverse */
PCFMTIN pcfmtin, /* (IN): formatting input */
LSCP cpFirstMain, /* (IN): cp first of reverse subline */
LSCP cpLast, /* (IN): cp output from formatting subline */
FMTRES fmtres) /* (IN): final format state */
{
LSERR lserr;
/* Set cpFirst and cpLim for reverse subline */
pdobj->cpFirstSubline = cpFirstMain;
pdobj->dcpSubline = cpLast - pdobj->cpFirstSubline;
/* Set dcp for whole object */
pdobj->dcp = cpLast - pdobj->cpStart;
if (fmtres != fmtrExceededMargin)
{
/* Note: +1 for the escape character at the end of the object. */
pdobj->dcp++;
}
lserr = LsdnSubmitSublines(pilsobj->plsc, pcfmtin->plsdnTop, 1,
&pdobj->plssubl, TRUE, FALSE, TRUE, TRUE, FALSE);
if (lserr != lserrNone) return ReverseFmtFailed (pdobj, lserr);
return LsdnFinishRegular(pilsobj->plsc, pdobj->dcp,
pcfmtin->lsfrun.plsrun, pcfmtin->lsfrun.plschp, pdobj,
&pdobj->objdimAll);
}
/* R E V E R S E C R E A T E I L S O B J */
/*----------------------------------------------------------------------------
%%Function: ReverseCreateILSObj
%%Contact: ricksa
CreateILSObj
Create the ILS object for all Reverse objects.
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseCreateILSObj(
POLS pols, /* (IN): client application context */
PLSC plsc, /* (IN): LS context */
PCLSCBK pclscbk, /* (IN): callbacks to client application */
DWORD idObj, /* (IN): id of the object */
PILSOBJ *ppilsobj) /* (OUT): object ilsobj */
{
PILSOBJ pilsobj;
REVERSEINIT reverseinit;
LSERR lserr;
*ppilsobj = NULL; /* in case of error */
/* Get initialization data */
reverseinit.dwVersion = REVERSE_VERSION;
lserr = pclscbk->pfnGetObjectHandlerInfo(pols, idObj, &reverseinit);
if (lserr != lserrNone) return lserr;
pilsobj = (PILSOBJ) pclscbk->pfnNewPtr(pols, sizeof(*pilsobj));
if (NULL == pilsobj) return lserrOutOfMemory;
pilsobj->pols = pols;
pilsobj->lscbk = *pclscbk;
pilsobj->plsc = plsc;
pilsobj->idobj = idObj;
pilsobj->lsesc.wchFirst = reverseinit.wchEndReverse;
pilsobj->lsesc.wchLast = reverseinit.wchEndReverse;
pilsobj->pfnReverseEnum = reverseinit.pfnEnum;
pilsobj->pfnReverseGetInfo = reverseinit.pfnGetRobjInfo;
*ppilsobj = pilsobj;
return lserrNone;
}
/* R E V E R S E D E S T R O Y I L S O B J */
/*----------------------------------------------------------------------------
%%Function: ReverseDestroyILSObj
%%Contact: ricksa
DestroyILSObj
Free all resources assocaiated with Reverse ILS object.
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseDestroyILSObj(
PILSOBJ pilsobj) /* (IN): object ilsobj */
{
pilsobj->lscbk.pfnDisposePtr(pilsobj->pols, pilsobj);
return lserrNone;
}
/* R E V E R S E S E T D O C */
/*----------------------------------------------------------------------------
%%Function: ReverseSetDoc
%%Contact: ricksa
SetDoc
Keep track of device information for scaling purposes.
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseSetDoc(
PILSOBJ pilsobj, /* (IN): object ilsobj */
PCLSDOCINF pclsdocinf) /* (IN): initialization data of the document level */
{
Unreferenced(pilsobj);
Unreferenced(pclsdocinf);
return lserrNone;
}
/* R E V E R S E C R E A T E L N O B J */
/*----------------------------------------------------------------------------
%%Function: ReverseCreateLNObj
%%Contact: ricksa
CreateLNObj
Create the Line Object for the Reverse. No real need for a line
object so don't allocated it.
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseCreateLNObj(
PCILSOBJ pcilsobj, /* (IN): object ilsobj */
PLNOBJ *pplnobj) /* (OUT): object lnobj */
{
*pplnobj = (PLNOBJ) pcilsobj;
return lserrNone;
}
/* R E V E R S E D E S T R O Y L N O B J */
/*----------------------------------------------------------------------------
%%Function: ReverseDestroyLNObj
%%Contact: ricksa
DestroyLNObj
Frees resources associated with the Reverse line object. Since
there isn't any this is a no-op.
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseDestroyLNObj(
PLNOBJ plnobj) /* (OUT): object lnobj */
{
Unreferenced(plnobj);
return lserrNone;
}
/* R E V E R S E F M T */
/*----------------------------------------------------------------------------
%%Function: ReverseFmt
%%Contact: ricksa
Fmt
Format the Reverse object.
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseFmt(
PLNOBJ plnobj, /* (IN): object lnobj */
PCFMTIN pcfmtin, /* (IN): formatting input */
FMTRES *pfmtres) /* (OUT): formatting result */
{
PDOBJ pdobj;
LSERR lserr;
PILSOBJ pilsobj = (PILSOBJ) plnobj;
LSCP cpStartMain = pcfmtin->lsfgi.cpFirst + 1;
LSCP cpOut;
lserr = InitDobj(pilsobj, pcfmtin, &pdobj);
// Assert (pilsobj->pfnReverseGetInfo != NULL);
if (pilsobj->pfnReverseGetInfo != NULL)
{
lserr = pilsobj->pfnReverseGetInfo (pilsobj->pols,
pcfmtin->lsfgi.cpFirst,
pcfmtin->lsfrun.plsrun,
&pdobj->fDoNotBreakAround,
&pdobj->fSuppressTrailingSpaces);
if (lserr != lserrNone) return ReverseFmtFailed (pdobj, lserr);
};
if (lserr != lserrNone) return lserrNone;
pdobj->fFirstOnLine = pcfmtin->lsfgi.fFirstOnLine;
pdobj->plsdnTop = pcfmtin->plsdnTop;
// Format the text to the maximum remaining in the column
lserr = FormatLine(pilsobj->plsc, cpStartMain,
pcfmtin->lsfgi.urColumnMax - pcfmtin->lsfgi.urPen,
pdobj->lstflowO, &pdobj->plssubl, 1, &pilsobj->lsesc,
&pdobj->objdimAll, &cpOut, NULL, NULL, pfmtres);
if (lserr != lserrNone) return ReverseFmtFailed (pdobj, lserr);
return FinishFmt(pdobj, pilsobj, pcfmtin, cpStartMain, cpOut, *pfmtres);
}
/* R E V E R S E F M T R E S U M E */
/*----------------------------------------------------------------------------
%%Function: ReverseFmtResume
%%Contact: ricksa
Fmt
Format a broken Reverse object.
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseFmtResume(
PLNOBJ plnobj, /* (IN): object lnobj */
const BREAKREC *rgBreakRecord, /* (IN): array of break records */
DWORD nBreakRecord, /* (IN): size of the break records array */
PCFMTIN pcfmtin, /* (IN): formatting input */
FMTRES *pfmtres) /* (OUT): formatting result */
{
PDOBJ pdobj;
LSERR lserr;
PILSOBJ pilsobj = (PILSOBJ) plnobj;
LSCP cpStartMain = pcfmtin->lsfgi.cpFirst;
LSCP cpOut;
lserr = InitDobj(pilsobj, pcfmtin, &pdobj);
if (lserr != lserrNone) return lserr;
/* InitDobj sets cpStartObj to start of text. Because we are resuming,
we need to set this to the real start of the object. */
pdobj->cpStartObj = rgBreakRecord->cpFirst;
// Assert (pilsobj->pfnReverseGetInfo != NULL);
if (pilsobj->pfnReverseGetInfo != NULL)
{
lserr = pilsobj->pfnReverseGetInfo (pilsobj->pols, pcfmtin->lsfgi.cpFirst,
pcfmtin->lsfrun.plsrun,
&pdobj->fDoNotBreakAround,
&pdobj->fSuppressTrailingSpaces);
if (lserr != lserrNone) return ReverseFmtFailed (pdobj, lserr);
};
pdobj->fFirstOnLine = pcfmtin->lsfgi.fFirstOnLine;
pdobj->plsdnTop = pcfmtin->plsdnTop;
/* Format the text to the maximum remaining in the column */
lserr = FormatResumedLine(pilsobj->plsc, cpStartMain,
pcfmtin->lsfgi.urColumnMax - pcfmtin->lsfgi.urPen,
pdobj->lstflowO, &pdobj->plssubl, 1, &pilsobj->lsesc,
&pdobj->objdimAll, &cpOut, NULL, NULL, pfmtres,
&rgBreakRecord[1], nBreakRecord - 1);
if (lserr != lserrNone) return ReverseFmtFailed (pdobj, lserr);
return FinishFmt(pdobj, pilsobj, pcfmtin, cpStartMain, cpOut, *pfmtres);
}
/* R E V E R S E T R U N C A T E C H U N K */
/*----------------------------------------------------------------------------
%%Function: ReverseTruncateChunk
%%Contact: ricksa
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseTruncateChunk(
PCLOCCHNK plocchnk, /* (IN): locchnk to truncate */
PPOSICHNK posichnk) /* (OUT): truncation point */
{
long urColumnMax = plocchnk->lsfgi.urColumnMax;
long ur = plocchnk->ppointUvLoc[0].u;
PDOBJ pdobj = NULL;
DWORD i;
LSCP cp;
LSERR lserr;
AssertSz(plocchnk->ppointUvLoc[0].u <= urColumnMax,
"ReverseTruncateChunk - pen greater than column max");
/* Look for chunk to truncate */
for (i = 0; ur <= urColumnMax; i++)
{
AssertSz((i < plocchnk->clschnk), "ReverseTruncateChunk exceeded group of chunks");
ur = plocchnk->ppointUvLoc[i].u;
AssertSz(ur <= urColumnMax,
"ReverseTruncateChunk - pen pos past column max");
pdobj = plocchnk->plschnk[i].pdobj;
ur += pdobj->objdimAll.dur;
}
/* Found the object where truncation is to occur */
AssertSz(pdobj != NULL, "ReverseTruncateChunk - pdobj is NULL");
/* Get the truncation point from the subline */
lserr = LsTruncateSubline(pdobj->plssubl,
urColumnMax - (ur - pdobj->objdimAll.dur), &cp);
if (lserr != lserrNone) return lserr;
/* Format return result */
posichnk->ichnk = i - 1;
posichnk->dcp = TranslateCpLimSublineToDcpExternal (pdobj, cp + 1);
return lserrNone;
}
/* R E V E R S E F I N D P R E V B R E A K C O R E*/
/*----------------------------------------------------------------------------
%%Function: ReverseFindPrevBreakCore
%%Contact: antons
----------------------------------------------------------------------------*/
LSERR ReverseFindPrevBreakCore (
PCLOCCHNK pclocchnk, /* (IN): locchnk to break */
DWORD ichnk, /* (IN): object to start looking for break */
BOOL fDcpOutside, /* (IN): when true, start looking from outside */
LSDCP dcp, /* (IN): starting dcp; valid only when fDcpOutside=False */
BRKCOND brkcond, /* (IN): recommmendation about the break before ichnk */
PBRKOUT pbrkout) /* (OUT): result of breaking */
{
LSERR lserr;
PDOBJ pdobj = pclocchnk->plschnk[ichnk].pdobj;
if (fDcpOutside)
{
if ( brkcond != brkcondNever &&
! (pdobj->fDoNotBreakAround && brkcond == brkcondCan) )
{
/* Can break after ichnk */
PutBreakAtEndOfObject(ichnk, pclocchnk, pbrkout);
ReverseSaveBreakRecord (pdobj, brkkindPrev, breakSublineAfter, pdobj->cpStart + pdobj->dcp);
return lserrNone;
}
else
{
/* Try to break ichnk */
return ReverseFindPrevBreakCore ( pclocchnk,
ichnk,
fFalse,
pclocchnk->plschnk[ichnk].dcp - 1,
brkcond,
pbrkout );
}
}
else
{
LSCP cpTruncateSubline = TranslateDcpExternalToCpLimSubline (pdobj, dcp - 1);
BOOL fSuccessful;
LSCP cpBreak;
OBJDIM objdimSubline;
BRKPOS brkpos;
Assert (dcp >= 1 && dcp <= pdobj->dcp);
/* REVIEW (antons): I do not think that passing pclocchnk->lsfgi.urColumnMax is correct... */
/* need to be confirmed with IgorZv */
lserr = LsFindPrevBreakSubline (
pdobj->plssubl,
pclocchnk->lsfgi.fFirstOnLine,
cpTruncateSubline,
pclocchnk->lsfgi.urColumnMax,
&fSuccessful,
&cpBreak,
&objdimSubline,
&brkpos);
if (lserr != lserrNone) return lserr;
/* 1. Unsuccessful or break before first DNode */
if (!fSuccessful || (fSuccessful && brkpos == brkposBeforeFirstDnode))
{
if (ichnk == 0)
{
/* First in the chunk => return UnSuccessful */
PutBreakUnsuccessful (pdobj, pbrkout);
return lserrNone;
}
else
{
/* Break between objects */
if (pdobj->fDoNotBreakAround)
{
return ReverseFindPrevBreakCore ( pclocchnk,
ichnk - 1,
fTrue,
0,
brkcondCan,
pbrkout );
}
else
{
pdobj = pclocchnk->plschnk[ichnk-1].pdobj;
PutBreakAtEndOfObject(ichnk - 1, pclocchnk, pbrkout);
ReverseSaveBreakRecord (
pclocchnk->plschnk[ichnk-1].pdobj,
brkkindPrev,
breakSublineAfter, pdobj->cpStart + pdobj->dcp);
return lserrNone;
};
};
}
/* 2. Successful break after last DNode */
else if (brkpos == brkposAfterLastDnode)
{
if (brkcond == brkcondNever) /* Can not reset dcp */
{
/* We are not allowed to break "after", */
/* so we are trying another previous break if possible */
return ReverseFindPrevBreakCore ( pclocchnk,
ichnk,
fFalse,
dcp-1,
brkcondCan,
pbrkout );
}
else /* Can reset dcp */
{
/* We reset dcp of the break so it happends after object but in break
record we remember that we should call SetBreakSubline with brkkindPrev */
ReverseSaveBreakRecord ( pdobj, brkkindPrev, breakSublineInside,
pdobj->cpStart + pdobj->dcp );
return FinishBreakRegular ( ichnk,
pdobj,
pdobj->cpStart + pdobj->dcp,
& objdimSubline,
pbrkout );
} ;
}
else
{
/* 3. Successful break inside subline */
ReverseSaveBreakRecord (pdobj, brkkindPrev, breakSublineInside,
cpBreak );
return FinishBreakRegular ( ichnk,
pdobj,
cpBreak,
&objdimSubline,
pbrkout );
};
};
}
/* R E V E R S E F I N D P R E V B R E A K C H U N K */
/*----------------------------------------------------------------------------
%%Function: ReverseFindPrevBreakChunk
%%Contact: antons
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseFindPrevBreakChunk (
PCLOCCHNK pclocchnk, /* (IN): locchnk to break */
PCPOSICHNK pcpoischnk, /* (IN): place to start looking for break */
BRKCOND brkcond, /* (IN): recommmendation about the break after chunk */
PBRKOUT pbrkout) /* (OUT): results of breaking */
{
if (pcpoischnk->ichnk == ichnkOutside)
{
return ReverseFindPrevBreakCore ( pclocchnk,
pclocchnk->clschnk - 1,
fTrue,
0,
brkcond,
pbrkout );
}
else
{
return ReverseFindPrevBreakCore ( pclocchnk,
pcpoischnk->ichnk,
fFalse,
pcpoischnk->dcp,
brkcondPlease,
pbrkout );
};
}
/* R E V E R S E F I N D N E X T B R E A K C O R E*/
/*----------------------------------------------------------------------------
%%Function: ReverseFindNextBreakCore
%%Contact: antons
----------------------------------------------------------------------------*/
LSERR ReverseFindNextBreakCore (
PCLOCCHNK pclocchnk, /* (IN): locchnk to break */
DWORD ichnk, /* (IN): object to start looking for break */
BOOL fDcpOutside, /* (IN): when true, start looking from outside */
LSDCP dcp, /* (IN): starting dcp; valid only when fDcpOutside=False */
BRKCOND brkcond, /* (IN): recommmendation about the break before ichnk */
PBRKOUT pbrkout ) /* (OUT): result of breaking */
{
LSERR lserr;
PDOBJ pdobj = pclocchnk->plschnk[ichnk].pdobj;
if (fDcpOutside)
{
if ( brkcond != brkcondNever &&
! (pdobj->fDoNotBreakAround && brkcond == brkcondCan) )
{
/* Can break before ichnk */
PutBreakBeforeObject (ichnk, pclocchnk, pbrkout);
return lserrNone;
}
else
{
/* Try to break ichnk */
return ReverseFindNextBreakCore (pclocchnk, ichnk, fFalse, 1, brkcond, pbrkout );
}
}
else
{
/* Dcp is inside ichnk */
LSCP cpTruncateSubline = TranslateDcpExternalToCpLimSubline (pdobj, dcp - 1);
BOOL fSuccessful;
LSCP cpBreak;
OBJDIM objdimSubline;
BRKPOS brkpos;
Assert (dcp >= 1 && dcp <= pdobj->dcp);
/* REVIEW (antons): I do not think that passing pclocchnk->lsfgi.urColumnMax is correct... */
/* need to be confirmed with IgorZv */
lserr = LsFindNextBreakSubline (
pdobj->plssubl,
pclocchnk->lsfgi.fFirstOnLine,
cpTruncateSubline,
pclocchnk->lsfgi.urColumnMax,
&fSuccessful,
&cpBreak,
&objdimSubline,
&brkpos);
if (lserr != lserrNone) return lserr;
if (!fSuccessful)
{
/* Unsuccessful break */
if (ichnk == pclocchnk->clschnk-1) /* Last object in chunk */
{
/* Review (AntonS): Better would be take objdimSubline */
pbrkout->objdim = pclocchnk->plschnk[ichnk].pdobj->objdimAll;
PutBreakUnsuccessful (pdobj, pbrkout);
/* Break condition is not next => have to store break record */
ReverseSaveBreakRecord ( pdobj,
brkkindNext,
breakSublineAfter, pdobj->cpStart + pdobj->dcp );
return lserrNone;
}
else if (pdobj->fDoNotBreakAround)
{
/* Try to break next object */
return ReverseFindNextBreakCore (
pclocchnk,
ichnk+1,
fTrue,
0,
brkcondCan,
pbrkout );
}
else
{
/* Break after ichnk */
PutBreakAtEndOfObject(ichnk, pclocchnk, pbrkout);
ReverseSaveBreakRecord ( pclocchnk->plschnk[ichnk].pdobj,
brkkindNext,
breakSublineAfter,
pclocchnk->plschnk[ichnk].pdobj->cpStart +
pclocchnk->plschnk[ichnk].pdobj->dcp );
return lserrNone;
};
}
else if (brkpos == brkposAfterLastDnode)
{
/* Break after last dnode => reset dcp and break afetr ichnk */
ReverseSaveBreakRecord (pdobj, brkkindNext, breakSublineInside, pdobj->cpStart + pdobj->dcp);
return FinishBreakRegular ( ichnk,
pdobj,
pdobj->cpStart + pdobj->dcp,
& objdimSubline,
pbrkout );
}
else
{
/* 3. Successful break inside subline */
ReverseSaveBreakRecord (pdobj, brkkindNext, breakSublineInside, cpBreak);
return FinishBreakRegular ( ichnk,
pdobj,
cpBreak,
& objdimSubline,
pbrkout);
};
}
} /* End of ReverseFindNextBreakCore */
/* R E V E R S E F I N D N E X T B R E A K C H U N K */
/*----------------------------------------------------------------------------
%%Function: ReverseFindNextBreakChunk
%%Contact: antons
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseFindNextBreakChunk (
PCLOCCHNK pclocchnk, /* (IN): locchnk to break */
PCPOSICHNK pcpoischnk, /* (IN): place to start looking for break */
BRKCOND brkcond, /* (IN): recommmendation about the break after chunk */
PBRKOUT pbrkout) /* (OUT): results of breaking */
{
LSERR lserr;
if (pcpoischnk->ichnk == ichnkOutside)
{
lserr = ReverseFindNextBreakCore ( pclocchnk,
0,
fTrue,
0,
brkcond,
pbrkout );
}
else
{
lserr = ReverseFindNextBreakCore ( pclocchnk,
pcpoischnk->ichnk,
fFalse,
pcpoischnk->dcp,
brkcondPlease,
pbrkout );
};
return lserr;
}
/* R E V E R S E F O R C E B R E A K C H U N K */
/*----------------------------------------------------------------------------
%%Function: ReverseForceBreak
%%Contact: antons
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseForceBreakChunk (
PCLOCCHNK pclocchnk, /* (IN): locchnk to break */
PCPOSICHNK pcposichnkIn, /* (IN): place to start looking for break */
PBRKOUT pbrkout) /* (OUT): results of breaking */
{
POSICHNK posichnk = * pcposichnkIn;
LSERR lserr;
LSCP cpTruncateSubline;
LSCP cpBreak;
OBJDIM objdimSubline;
PDOBJ pdobj;
BRKPOS brkpos;
if (posichnk.ichnk == ichnkOutside)
{
/* When left indent is bigger then Right Margin */
posichnk.ichnk = 0;
posichnk.dcp = 1;
};
Assert (posichnk.ichnk != ichnkOutside);
pdobj = pclocchnk->plschnk[posichnk.ichnk].pdobj;
if (pclocchnk->lsfgi.fFirstOnLine && (posichnk.ichnk == 0))
{
/* Object is the first on line (can not break before) */
LSDCP dcp = posichnk.dcp;
BOOL fEmpty;
Assert (dcp >= 1 && dcp <= pdobj->dcp);
lserr = LssbFIsSublineEmpty (pdobj->plssubl, &fEmpty);
if (lserr != lserrNone) return lserr;
if (fEmpty)
{
/* Can not ForceBreak empty subline */
Assert (posichnk.ichnk == 0);
PutBreakAtEndOfObject(0, pclocchnk, pbrkout);
ReverseSaveBreakRecord ( pclocchnk->plschnk[0].pdobj,
brkkindForce,
breakSublineAfter,
pclocchnk->plschnk[0].pdobj->cpStart +
pclocchnk->plschnk[0].pdobj->dcp );
return lserrNone;
};
/* Subline is not empty => do force break */
/* REVIEW (antons): The same as in Prev & Next Break */
cpTruncateSubline = TranslateDcpExternalToCpLimSubline (pdobj, dcp - 1);
lserr = LsForceBreakSubline (
pdobj->plssubl,
pclocchnk->lsfgi.fFirstOnLine,
cpTruncateSubline,
pclocchnk->lsfgi.urColumnMax,
&cpBreak,
&objdimSubline,
&brkpos );
if (lserr != lserrNone) return lserr;
/* REVIEW (antons): Check with IgorZv that Assert is correct ;-) */
Assert (brkpos != brkposBeforeFirstDnode);
if (brkpos == brkposAfterLastDnode)
{
/* We reset dcp so that closing brace stays on the same line */
ReverseSaveBreakRecord (pdobj, brkkindForce, breakSublineInside, pdobj->cpStart + pdobj->dcp);
return FinishBreakRegular ( posichnk.ichnk,
pdobj,
pdobj->cpStart + pdobj->dcp,
&objdimSubline,
pbrkout );
}
else
{
/* "Regular" ;-) ForceBreak inside subline */
ReverseSaveBreakRecord (pdobj, brkkindForce, breakSublineInside, cpBreak);
return FinishBreakRegular ( posichnk.ichnk,
pdobj,
cpBreak,
&objdimSubline,
pbrkout );
}
}
else
{
/* Can break before ichnk */
PutBreakBeforeObject (posichnk.ichnk, pclocchnk, pbrkout);
/* Do not need to save break record when break "before", because it will be
translated by manager to SetBreak (previous_dnode, ImposeAfter) */
/* REVIEW (antons): It is strange that I have difference between break "before"
not-first ichnk element and break "after" not-last. And only
in the second case I remember break record */
return lserrNone;
};
} /* ReverseForceBreakChunk */
/* R E V E R S E S E T B R E A K */
/*----------------------------------------------------------------------------
%%Function: ReverseSetBreak
%%Contact: antons
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseSetBreak(
PDOBJ pdobj, /* (IN): dobj which is broken */
BRKKIND brkkind, /* (IN): Prev / Next / Force / Impose After */
DWORD cBreakRecord, /* (IN): size of array */
BREAKREC *rgBreakRecord, /* (IN): array of break records */
DWORD *pcActualBreakRecord) /* (IN): actual number of used elements in array */
{
LSERR lserr = lserrNone;
if (cBreakRecord < 1) return lserrInsufficientBreakRecBuffer;
if (pdobj->fSuppressTrailingSpaces && pdobj->fFirstOnLine)
{
/* Robj is alone on the line => submit for trailing spaces */
if (brkkind != brkkindImposedAfter)
{
BREAKSUBLINETYPE breakSublineType;
LSCP cpBreak;
ReverseGetBreakRecord (pdobj, brkkind, &breakSublineType, &cpBreak);
if (cpBreak < (LSCP) (pdobj->cpStart + pdobj->dcp))
{
lserr = LsdnSubmitSublines(pdobj->pilsobj->plsc, pdobj->plsdnTop, 1,
&pdobj->plssubl, TRUE, TRUE, TRUE, TRUE, TRUE);
if (lserr != lserrNone) return lserr;
};
};
};
if (brkkind == brkkindImposedAfter)
{
/* Break is imposed ater DNODE */
lserr = LsSetBreakSubline ( pdobj->plssubl,
brkkindImposedAfter,
cBreakRecord-1,
& rgBreakRecord [1],
pcActualBreakRecord );
if (lserr != lserrNone) return lserr;
Assert (*pcActualBreakRecord == 0);
return lserrNone;
}
else
{
BREAKSUBLINETYPE breakSublineType;
LSCP cpBreak;
/* Result of previous Prev / Next or Force - used stored break record */
ReverseGetBreakRecord (pdobj, brkkind, &breakSublineType, &cpBreak);
Assert (breakSublineType == breakSublineAfter || breakSublineType == breakSublineInside);
if (breakSublineType == breakSublineAfter)
{
/* type = breakSublineAfter */
lserr = LsSetBreakSubline ( pdobj->plssubl,
brkkindImposedAfter,
cBreakRecord-1,
& rgBreakRecord [1],
pcActualBreakRecord );
if (lserr != lserrNone) return lserr;
Assert (*pcActualBreakRecord == 0);
return lserrNone;
}
else
{
/* type = breakSublineInside */
lserr = LsSetBreakSubline ( pdobj->plssubl,
brkkind,
cBreakRecord-1,
& rgBreakRecord [1],
pcActualBreakRecord );
if (lserr != lserrNone) return lserr;
/* Still possible to have break after object */
if (cpBreak == (LSCP) (pdobj->cpStart + pdobj->dcp))
{
Assert (*pcActualBreakRecord == 0);
return lserrNone;
}
else
{
(*pcActualBreakRecord) += 1;
rgBreakRecord[0].idobj = pdobj->pilsobj->idobj;
rgBreakRecord[0].cpFirst = pdobj->cpStartObj;
return lserrNone;
}
};
};
}
/* R E V E R S E G E T S P E C I A L E F F E C T S I N S I D E */
/*----------------------------------------------------------------------------
%%Function: ReverseGetSpecialEffectsInside
%%Contact: ricksa
GetSpecialEffectsInside
.
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseGetSpecialEffectsInside(
PDOBJ pdobj, /* (IN): dobj */
UINT *pEffectsFlags) /* (OUT): Special effects for this object */
{
return LsGetSpecialEffectsSubline(pdobj->plssubl, pEffectsFlags);
}
/* R E V E R S E C A L C P R E S E N T A T I O N */
/*----------------------------------------------------------------------------
%%Function: ReverseCalcPresentation
%%Contact: ricksa
CalcPresentation
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseCalcPresentation(
PDOBJ pdobj, /* (IN): dobj */
long dup, /* (IN): dup of dobj */
LSKJUST lskjust, /* (IN): Justification type */
BOOL fLastVisibleOnLine ) /* (IN): Is this object last visible on line? */
{
LSERR lserr;
BOOL fDone;
Unreferenced (lskjust);
Unreferenced (fLastVisibleOnLine);
pdobj->dup = dup;
/* Make sure that justification line has been made ready for presentation */
lserr = LssbFDonePresSubline(pdobj->plssubl, &fDone);
if ((lserrNone == lserr) && !fDone)
{
lserr = LsMatchPresSubline(pdobj->plssubl);
}
return lserr;
}
/* R E V E R S E Q U E R Y P O I N T P C P */
/*----------------------------------------------------------------------------
%%Function: ReverseQueryPointPcp
%%Contact: ricksa
Map dup to dcp
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseQueryPointPcp(
PDOBJ pdobj, /*(IN): dobj to query */
PCPOINTUV ppointuvQuery, /*(IN): query point (uQuery,vQuery) */
PCLSQIN plsqin, /*(IN): query input */
PLSQOUT plsqout) /*(OUT): query output */
{
Unreferenced(ppointuvQuery);
return CreateQueryResult(pdobj->plssubl, pdobj->dup - 1, 0, plsqin, plsqout);
}
/* R E V E R S E Q U E R Y C P P P O I N T */
/*----------------------------------------------------------------------------
%%Function: ReverseQueryCpPpoint
%%Contact: ricksa
Map dcp to dup
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseQueryCpPpoint(
PDOBJ pdobj, /*(IN): dobj to query, */
LSDCP dcp, /*(IN): dcp for the query */
PCLSQIN plsqin, /*(IN): query input */
PLSQOUT plsqout) /*(OUT): query output */
{
Unreferenced(dcp);
return CreateQueryResult(pdobj->plssubl, pdobj->dup - 1, 0, plsqin, plsqout);
}
/* R E V E R S E D I S P L A Y */
/*----------------------------------------------------------------------------
%%Function: ReverseDisplay
%%Contact: ricksa
Display
This calculates the positions of the various lines for the
display and then displays them.
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseDisplay(
PDOBJ pdobj,
PCDISPIN pcdispin)
{
POINTUV pointuv;
POINT pt;
BOOL fDisplayed;
LSERR lserr = LssbFDoneDisplay(pdobj->plssubl, &fDisplayed);
if (lserr != lserrNone)
{
return lserr;
}
if (fDisplayed)
{
return lserrNone;
}
/* Calculate point to start displaying the subline. */
pointuv.u = pdobj->dup - 1;
pointuv.v = 0;
LsPointXYFromPointUV(&pcdispin->ptPen, pdobj->lstflowL, &pointuv, &pt);
/* display the Reverse line */
return LsDisplaySubline(pdobj->plssubl, &pt, pcdispin->kDispMode, pcdispin->prcClip);
}
/* R E V E R S E D E S T R O Y D O B J */
/*----------------------------------------------------------------------------
%%Function: ReverseDestroyDobj
%%Contact: ricksa
DestroyDobj
Free all resources connected with the input dobj.
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseDestroyDobj(
PDOBJ pdobj)
{
return ReverseFreeDobj(pdobj);
}
/* R E V E R S E E N U M */
/*----------------------------------------------------------------------------
%%Function: ReverseEnum
%%Contact: ricksa
Enum
Enumeration callback - passed to client.
----------------------------------------------------------------------------*/
LSERR WINAPI ReverseEnum(
PDOBJ pdobj, /*(IN): dobj to enumerate */
PLSRUN plsrun, /*(IN): from DNODE */
PCLSCHP plschp, /*(IN): from DNODE */
LSCP cp, /*(IN): from DNODE */
LSDCP dcp, /*(IN): from DNODE */
LSTFLOW lstflow, /*(IN): text flow*/
BOOL fReverse, /*(IN): enumerate in reverse order */
BOOL fGeometryNeeded, /*(IN): */
const POINT *pt, /*(IN): starting position (top left), iff fGeometryNeeded */
PCHEIGHTS pcheights, /*(IN): from DNODE, relevant iff fGeometryNeeded */
long dupRun) /*(IN): from DNODE, relevant iff fGeometryNeeded */
{
return pdobj->pilsobj->pfnReverseEnum(pdobj->pilsobj->pols, plsrun, plschp,
cp, dcp, lstflow, fReverse, fGeometryNeeded, pt, pcheights, dupRun,
pdobj->lstflowO, pdobj->plssubl);
}
/* L S G E T R E V E R S E L S I M E T H O D S */
/*----------------------------------------------------------------------------
%%Function: LsGetReverseLsimethods
%%Contact: ricksa
Initialize object handler for client.
----------------------------------------------------------------------------*/
LSERR WINAPI LsGetReverseLsimethods(
LSIMETHODS *plsim)
{
plsim->pfnCreateILSObj = ReverseCreateILSObj;
plsim->pfnDestroyILSObj = ReverseDestroyILSObj;
plsim->pfnSetDoc = ReverseSetDoc;
plsim->pfnCreateLNObj = ReverseCreateLNObj;
plsim->pfnDestroyLNObj = ReverseDestroyLNObj;
plsim->pfnFmt = ReverseFmt;
plsim->pfnFmtResume = ReverseFmtResume;
plsim->pfnGetModWidthPrecedingChar = ObjHelpGetModWidthChar;
plsim->pfnGetModWidthFollowingChar = ObjHelpGetModWidthChar;
plsim->pfnTruncateChunk = ReverseTruncateChunk;
plsim->pfnFindPrevBreakChunk = ReverseFindPrevBreakChunk;
plsim->pfnFindNextBreakChunk = ReverseFindNextBreakChunk;
plsim->pfnForceBreakChunk = ReverseForceBreakChunk;
plsim->pfnSetBreak = ReverseSetBreak;
plsim->pfnGetSpecialEffectsInside = ReverseGetSpecialEffectsInside;
plsim->pfnFExpandWithPrecedingChar = ObjHelpFExpandWithPrecedingChar;
plsim->pfnFExpandWithFollowingChar = ObjHelpFExpandWithFollowingChar;
plsim->pfnCalcPresentation = ReverseCalcPresentation;
plsim->pfnQueryPointPcp = ReverseQueryPointPcp;
plsim->pfnQueryCpPpoint = ReverseQueryCpPpoint;
plsim->pfnDisplay = ReverseDisplay;
plsim->pfnDestroyDObj = ReverseDestroyDobj;
plsim->pfnEnum = ReverseEnum;
return lserrNone;
}