|
|
#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; }
|