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