329 lines
8.2 KiB
C
329 lines
8.2 KiB
C
#include "lsqline.h"
|
|
#include "lsc.h"
|
|
#include "lsline.h"
|
|
#include "lslinfo.h"
|
|
#include "lsqsinfo.h"
|
|
#include "lsqcore.h"
|
|
#include "lstxtqry.h"
|
|
#include "lsqrycon.h"
|
|
#include "lsdnode.h"
|
|
#include "prepdisp.h"
|
|
#include "dispmisc.h"
|
|
#include "heights.h"
|
|
#include "lschp.h"
|
|
#include "dnutils.h"
|
|
#include "dninfo.h"
|
|
#include "iobj.h"
|
|
#include "zqfromza.h"
|
|
#include "lsdevice.h"
|
|
|
|
void AdjustForLeftIndent(PLSQSUBINFO, DWORD, PLSTEXTCELL, long);
|
|
|
|
|
|
#define FIsSplat(endr) (endr == endrEndColumn || \
|
|
endr == endrEndSection || \
|
|
endr == endrEndPage)
|
|
|
|
|
|
// %%Function: LsQueryLineCpPpoint
|
|
// %%Contact: victork
|
|
//
|
|
/*
|
|
* Returns dim-info of the cp in the line.
|
|
*
|
|
* If that cp isn't displayed in the line, take closest to the left that is displayed.
|
|
* If that's impossible, go to the right.
|
|
*/
|
|
LSERR WINAPI LsQueryLineCpPpoint(
|
|
PLSLINE plsline,
|
|
LSCP cpQuery,
|
|
DWORD cDepthQueryMax, /* IN: allocated size of results array */
|
|
PLSQSUBINFO plsqsubinfoResults, /* OUT: array[nDepthFormatMax] of query results */
|
|
DWORD* pcActualDepth, /* OUT: size of results array (filled) */
|
|
PLSTEXTCELL plstextcell) /* OUT: Text cell info */
|
|
{
|
|
LSERR lserr;
|
|
PLSSUBL plssubl;
|
|
PLSC plsc;
|
|
|
|
if (!FIsLSLINE(plsline)) return lserrInvalidLine;
|
|
|
|
plssubl = &(plsline->lssubl);
|
|
plsc = plssubl->plsc;
|
|
Assert(FIsLSC(plsc));
|
|
|
|
lserr = PrepareLineForDisplayProc(plsline);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
/* cp of splat - we can return nothing sensible */
|
|
|
|
if (cpQuery >= (plsline->lslinfo.cpLim)-1 && FIsSplat(plsline->lslinfo.endr))
|
|
{
|
|
*pcActualDepth = 0;
|
|
return lserrNone;
|
|
}
|
|
|
|
if (plsc->lsstate == LsStateFree)
|
|
{
|
|
plsc->lsstate = LsStateQuerying;
|
|
}
|
|
|
|
lserr = QuerySublineCpPpointCore(plssubl, cpQuery, cDepthQueryMax,
|
|
plsqsubinfoResults, pcActualDepth, plstextcell);
|
|
|
|
if (lserr == lserrNone)
|
|
{
|
|
if (plsline->upStartAutonumberingText != 0)
|
|
{
|
|
AdjustForLeftIndent(plsqsubinfoResults, *pcActualDepth, plstextcell, plsline->upStartAutonumberingText);
|
|
}
|
|
|
|
if (plsqsubinfoResults->idobj == idObjNone)
|
|
{
|
|
/* empty line - we can return nothing */
|
|
*pcActualDepth = 0;
|
|
}
|
|
}
|
|
|
|
if (plsc->lsstate == LsStateQuerying)
|
|
{
|
|
plsc->lsstate = LsStateFree;
|
|
}
|
|
|
|
return lserr;
|
|
}
|
|
|
|
|
|
|
|
// %%Function: LsQueryLinePointPcp
|
|
// %%Contact: victork
|
|
//
|
|
/*
|
|
* Returns dim-info of the cp in the line that contains given point.
|
|
*
|
|
* If that dup isn't in the line, take closest that is instead.
|
|
*/
|
|
LSERR WINAPI LsQueryLinePointPcp(
|
|
PLSLINE plsline,
|
|
PCPOINTUV ppointuvIn, /* IN: query point */
|
|
DWORD cDepthQueryMax,
|
|
PLSQSUBINFO plsqsubinfoResults, /* IN: pointer to array[nDepthQueryMax] */
|
|
DWORD* pcActualDepth, /* OUT */
|
|
PLSTEXTCELL plstextcell) /* OUT: Text cell info */
|
|
{
|
|
LSERR lserr;
|
|
PLSSUBL plssubl;
|
|
PLSC plsc;
|
|
POINTUV pointuvStart;
|
|
|
|
if (!FIsLSLINE(plsline)) return lserrInvalidLine;
|
|
|
|
|
|
plssubl = &(plsline->lssubl);
|
|
plsc = plssubl->plsc;
|
|
Assert(FIsLSC(plsc));
|
|
|
|
lserr = PrepareLineForDisplayProc(plsline);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
/* splat - we can return nothing */
|
|
if (ppointuvIn->u >= plsline->upLimLine && FIsSplat(plsline->lslinfo.endr))
|
|
{
|
|
*pcActualDepth = 0;
|
|
return lserrNone;
|
|
}
|
|
|
|
pointuvStart = *ppointuvIn;
|
|
|
|
// left indent isn't represented in the dnode list
|
|
if (plsline->upStartAutonumberingText != 0)
|
|
{
|
|
pointuvStart.u -= plsline->upStartAutonumberingText;
|
|
}
|
|
|
|
lserr = QuerySublinePointPcpCore(plssubl, &pointuvStart, cDepthQueryMax,
|
|
plsqsubinfoResults, pcActualDepth, plstextcell);
|
|
|
|
if (lserr == lserrNone)
|
|
{
|
|
if (plsline->upStartAutonumberingText != 0)
|
|
{
|
|
AdjustForLeftIndent(plsqsubinfoResults, *pcActualDepth, plstextcell, plsline->upStartAutonumberingText);
|
|
}
|
|
|
|
if (plsqsubinfoResults->idobj == idObjNone)
|
|
{
|
|
/* empty line - we can return nothing */
|
|
*pcActualDepth = 0;
|
|
}
|
|
}
|
|
|
|
return lserr;
|
|
}
|
|
|
|
|
|
// %%Function: LsQueryTextCellDetails
|
|
// %%Contact: victork
|
|
//
|
|
LSERR WINAPI LsQueryTextCellDetails(
|
|
PLSLINE plsline,
|
|
PCELLDETAILS pcelldetails,
|
|
LSCP cpStartCell, /* IN: cpStartCell */
|
|
DWORD cCharsInCell, /* IN: nCharsInCell */
|
|
DWORD cGlyphsInCell, /* IN: nGlyphsInCell */
|
|
WCHAR* pwch, /* OUT: pointer array[nCharsInCell] of char codes */
|
|
PGINDEX pgindex, /* OUT: pointer array[nGlyphsInCell] of glyph indices */
|
|
long* pdup, /* OUT: pointer array[nGlyphsCell] of glyph widths */
|
|
PGOFFSET pgoffset, /* OUT: pointer array[nGlyphsInCell] of glyph offsets */
|
|
PGPROP pgprop) /* OUT: pointer array[nGlyphsInCell] of glyph handles */
|
|
{
|
|
|
|
PLSDNODE pdnText;
|
|
|
|
Unreferenced(plsline); // is used in an assert only
|
|
|
|
pdnText = (PLSDNODE)pcelldetails; // I know it's really PLSDNODE
|
|
|
|
Assert(FIsLSDNODE(pdnText));
|
|
Assert(FIsDnodeReal(pdnText));
|
|
Assert(IdObjFromDnode(pdnText) == IobjTextFromLsc(&(plsline->lssubl.plsc->lsiobjcontext)));
|
|
|
|
// Try to defend again wrong input. Can't do a better job (use cCharsInCell) because of hyphenation.
|
|
|
|
if (cpStartCell < pdnText->cpFirst || cpStartCell > pdnText->cpFirst + (long)pdnText->dcp)
|
|
{
|
|
NotReached(); // can only be client's mistake
|
|
return lserrContradictoryQueryInput; // in case it isn't noticed
|
|
}
|
|
|
|
return QueryTextCellDetails(
|
|
pdnText->u.real.pdobj,
|
|
cpStartCell - pdnText->cpFirst,
|
|
cCharsInCell,
|
|
cGlyphsInCell,
|
|
pwch,
|
|
pgindex,
|
|
pdup,
|
|
pgoffset,
|
|
pgprop);
|
|
}
|
|
|
|
// %%Function: LsQueryLineDup
|
|
// %%Contact: victork
|
|
//
|
|
LSERR WINAPI LsQueryLineDup(PLSLINE plsline, /* IN: pointer to line -- opaque to client */
|
|
long* pupStartAutonumberingText,
|
|
long* pupLimAutonumberingText,
|
|
long* pupStartMainText,
|
|
long* pupStartTrailing,
|
|
long* pupLimLine)
|
|
|
|
{
|
|
LSERR lserr;
|
|
|
|
if (!FIsLSLINE(plsline))
|
|
return lserrInvalidLine;
|
|
|
|
if (plsline->lssubl.plsc->lsstate != LsStateFree)
|
|
return lserrContextInUse;
|
|
|
|
lserr = PrepareLineForDisplayProc(plsline);
|
|
if (lserr != lserrNone)
|
|
return lserr;
|
|
|
|
*pupStartAutonumberingText = plsline->upStartAutonumberingText;
|
|
*pupLimAutonumberingText = plsline->upLimAutonumberingText;
|
|
*pupStartMainText = plsline->upStartMainText;
|
|
*pupStartTrailing = plsline->upStartTrailing;
|
|
*pupLimLine = plsline->upLimLine;
|
|
|
|
return lserrNone;
|
|
|
|
}
|
|
|
|
|
|
// %%Function: LsQueryFLineEmpty
|
|
// %%Contact: victork
|
|
//
|
|
LSERR WINAPI LsQueryFLineEmpty(PLSLINE plsline, /* IN: pointer to line -- opaque to client */
|
|
BOOL* pfEmpty) /* OUT: Is line empty? */
|
|
{
|
|
|
|
enum endres endr;
|
|
PLSDNODE plsdnFirst;
|
|
|
|
|
|
if (!FIsLSLINE(plsline))
|
|
return lserrInvalidLine;
|
|
|
|
if (plsline->lssubl.plsc->lsstate != LsStateFree)
|
|
return lserrContextInUse;
|
|
|
|
endr = plsline->lslinfo.endr;
|
|
|
|
if (endr == endrNormal || endr == endrHyphenated)
|
|
{
|
|
// line that ends like that cannot be empty
|
|
*pfEmpty = fFalse;
|
|
return lserrNone;
|
|
}
|
|
|
|
// skip autonumbering - it cannot make line non-empty
|
|
for(plsdnFirst = plsline->lssubl.plsdnFirst;
|
|
plsdnFirst != NULL && FIsNotInContent(plsdnFirst);
|
|
plsdnFirst = plsdnFirst->plsdnNext);
|
|
|
|
// plsdnFirst points to the first dnode in content now or it is NULL
|
|
|
|
switch (endr)
|
|
{
|
|
case endrEndPara:
|
|
case endrAltEndPara:
|
|
case endrSoftCR:
|
|
// last dnode contains EOP and doesn't count as content
|
|
Assert(plsdnFirst != NULL);
|
|
Assert(plsdnFirst->plsdnNext == NULL ||
|
|
plsdnFirst->plsdnNext->cpFirst < plsline->lslinfo.cpLim);
|
|
// EOP doesn't count as content - it cannot make line non-empty
|
|
*pfEmpty = (plsdnFirst->plsdnNext == NULL);
|
|
break;
|
|
|
|
case endrEndColumn:
|
|
case endrEndSection:
|
|
case endrEndParaSection:
|
|
case endrEndPage:
|
|
case endrStopped:
|
|
*pfEmpty = (plsdnFirst == NULL);
|
|
break;
|
|
|
|
default:
|
|
NotReached();
|
|
}
|
|
|
|
return lserrNone;
|
|
|
|
}
|
|
|
|
|
|
// %%Function: AdjustForLeftIndent
|
|
// %%Contact: victork
|
|
//
|
|
void AdjustForLeftIndent(PLSQSUBINFO plsqsubinfoResults, DWORD cQueryLim, PLSTEXTCELL plstextcell, long upStartLine)
|
|
|
|
{
|
|
plstextcell->pointUvStartCell.u += upStartLine;
|
|
|
|
while (cQueryLim > 0)
|
|
{
|
|
plsqsubinfoResults->pointUvStartSubline.u += upStartLine;
|
|
plsqsubinfoResults->pointUvStartRun.u += upStartLine;
|
|
plsqsubinfoResults->pointUvStartObj.u += upStartLine;
|
|
plsqsubinfoResults++;
|
|
cQueryLim--;
|
|
}
|
|
}
|
|
|
|
|