Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

328 lines
8.2 KiB

  1. #include "lsqline.h"
  2. #include "lsc.h"
  3. #include "lsline.h"
  4. #include "lslinfo.h"
  5. #include "lsqsinfo.h"
  6. #include "lsqcore.h"
  7. #include "lstxtqry.h"
  8. #include "lsqrycon.h"
  9. #include "lsdnode.h"
  10. #include "prepdisp.h"
  11. #include "dispmisc.h"
  12. #include "heights.h"
  13. #include "lschp.h"
  14. #include "dnutils.h"
  15. #include "dninfo.h"
  16. #include "iobj.h"
  17. #include "zqfromza.h"
  18. #include "lsdevice.h"
  19. void AdjustForLeftIndent(PLSQSUBINFO, DWORD, PLSTEXTCELL, long);
  20. #define FIsSplat(endr) (endr == endrEndColumn || \
  21. endr == endrEndSection || \
  22. endr == endrEndPage)
  23. // %%Function: LsQueryLineCpPpoint
  24. // %%Contact: victork
  25. //
  26. /*
  27. * Returns dim-info of the cp in the line.
  28. *
  29. * If that cp isn't displayed in the line, take closest to the left that is displayed.
  30. * If that's impossible, go to the right.
  31. */
  32. LSERR WINAPI LsQueryLineCpPpoint(
  33. PLSLINE plsline,
  34. LSCP cpQuery,
  35. DWORD cDepthQueryMax, /* IN: allocated size of results array */
  36. PLSQSUBINFO plsqsubinfoResults, /* OUT: array[nDepthFormatMax] of query results */
  37. DWORD* pcActualDepth, /* OUT: size of results array (filled) */
  38. PLSTEXTCELL plstextcell) /* OUT: Text cell info */
  39. {
  40. LSERR lserr;
  41. PLSSUBL plssubl;
  42. PLSC plsc;
  43. if (!FIsLSLINE(plsline)) return lserrInvalidLine;
  44. plssubl = &(plsline->lssubl);
  45. plsc = plssubl->plsc;
  46. Assert(FIsLSC(plsc));
  47. lserr = PrepareLineForDisplayProc(plsline);
  48. if (lserr != lserrNone)
  49. return lserr;
  50. /* cp of splat - we can return nothing sensible */
  51. if (cpQuery >= (plsline->lslinfo.cpLim)-1 && FIsSplat(plsline->lslinfo.endr))
  52. {
  53. *pcActualDepth = 0;
  54. return lserrNone;
  55. }
  56. if (plsc->lsstate == LsStateFree)
  57. {
  58. plsc->lsstate = LsStateQuerying;
  59. }
  60. lserr = QuerySublineCpPpointCore(plssubl, cpQuery, cDepthQueryMax,
  61. plsqsubinfoResults, pcActualDepth, plstextcell);
  62. if (lserr == lserrNone)
  63. {
  64. if (plsline->upStartAutonumberingText != 0)
  65. {
  66. AdjustForLeftIndent(plsqsubinfoResults, *pcActualDepth, plstextcell, plsline->upStartAutonumberingText);
  67. }
  68. if (plsqsubinfoResults->idobj == idObjNone)
  69. {
  70. /* empty line - we can return nothing */
  71. *pcActualDepth = 0;
  72. }
  73. }
  74. if (plsc->lsstate == LsStateQuerying)
  75. {
  76. plsc->lsstate = LsStateFree;
  77. }
  78. return lserr;
  79. }
  80. // %%Function: LsQueryLinePointPcp
  81. // %%Contact: victork
  82. //
  83. /*
  84. * Returns dim-info of the cp in the line that contains given point.
  85. *
  86. * If that dup isn't in the line, take closest that is instead.
  87. */
  88. LSERR WINAPI LsQueryLinePointPcp(
  89. PLSLINE plsline,
  90. PCPOINTUV ppointuvIn, /* IN: query point */
  91. DWORD cDepthQueryMax,
  92. PLSQSUBINFO plsqsubinfoResults, /* IN: pointer to array[nDepthQueryMax] */
  93. DWORD* pcActualDepth, /* OUT */
  94. PLSTEXTCELL plstextcell) /* OUT: Text cell info */
  95. {
  96. LSERR lserr;
  97. PLSSUBL plssubl;
  98. PLSC plsc;
  99. POINTUV pointuvStart;
  100. if (!FIsLSLINE(plsline)) return lserrInvalidLine;
  101. plssubl = &(plsline->lssubl);
  102. plsc = plssubl->plsc;
  103. Assert(FIsLSC(plsc));
  104. lserr = PrepareLineForDisplayProc(plsline);
  105. if (lserr != lserrNone)
  106. return lserr;
  107. /* splat - we can return nothing */
  108. if (ppointuvIn->u >= plsline->upLimLine && FIsSplat(plsline->lslinfo.endr))
  109. {
  110. *pcActualDepth = 0;
  111. return lserrNone;
  112. }
  113. pointuvStart = *ppointuvIn;
  114. // left indent isn't represented in the dnode list
  115. if (plsline->upStartAutonumberingText != 0)
  116. {
  117. pointuvStart.u -= plsline->upStartAutonumberingText;
  118. }
  119. lserr = QuerySublinePointPcpCore(plssubl, &pointuvStart, cDepthQueryMax,
  120. plsqsubinfoResults, pcActualDepth, plstextcell);
  121. if (lserr == lserrNone)
  122. {
  123. if (plsline->upStartAutonumberingText != 0)
  124. {
  125. AdjustForLeftIndent(plsqsubinfoResults, *pcActualDepth, plstextcell, plsline->upStartAutonumberingText);
  126. }
  127. if (plsqsubinfoResults->idobj == idObjNone)
  128. {
  129. /* empty line - we can return nothing */
  130. *pcActualDepth = 0;
  131. }
  132. }
  133. return lserr;
  134. }
  135. // %%Function: LsQueryTextCellDetails
  136. // %%Contact: victork
  137. //
  138. LSERR WINAPI LsQueryTextCellDetails(
  139. PLSLINE plsline,
  140. PCELLDETAILS pcelldetails,
  141. LSCP cpStartCell, /* IN: cpStartCell */
  142. DWORD cCharsInCell, /* IN: nCharsInCell */
  143. DWORD cGlyphsInCell, /* IN: nGlyphsInCell */
  144. WCHAR* pwch, /* OUT: pointer array[nCharsInCell] of char codes */
  145. PGINDEX pgindex, /* OUT: pointer array[nGlyphsInCell] of glyph indices */
  146. long* pdup, /* OUT: pointer array[nGlyphsCell] of glyph widths */
  147. PGOFFSET pgoffset, /* OUT: pointer array[nGlyphsInCell] of glyph offsets */
  148. PGPROP pgprop) /* OUT: pointer array[nGlyphsInCell] of glyph handles */
  149. {
  150. PLSDNODE pdnText;
  151. Unreferenced(plsline); // is used in an assert only
  152. pdnText = (PLSDNODE)pcelldetails; // I know it's really PLSDNODE
  153. Assert(FIsLSDNODE(pdnText));
  154. Assert(FIsDnodeReal(pdnText));
  155. Assert(IdObjFromDnode(pdnText) == IobjTextFromLsc(&(plsline->lssubl.plsc->lsiobjcontext)));
  156. // Try to defend again wrong input. Can't do a better job (use cCharsInCell) because of hyphenation.
  157. if (cpStartCell < pdnText->cpFirst || cpStartCell > pdnText->cpFirst + (long)pdnText->dcp)
  158. {
  159. NotReached(); // can only be client's mistake
  160. return lserrContradictoryQueryInput; // in case it isn't noticed
  161. }
  162. return QueryTextCellDetails(
  163. pdnText->u.real.pdobj,
  164. cpStartCell - pdnText->cpFirst,
  165. cCharsInCell,
  166. cGlyphsInCell,
  167. pwch,
  168. pgindex,
  169. pdup,
  170. pgoffset,
  171. pgprop);
  172. }
  173. // %%Function: LsQueryLineDup
  174. // %%Contact: victork
  175. //
  176. LSERR WINAPI LsQueryLineDup(PLSLINE plsline, /* IN: pointer to line -- opaque to client */
  177. long* pupStartAutonumberingText,
  178. long* pupLimAutonumberingText,
  179. long* pupStartMainText,
  180. long* pupStartTrailing,
  181. long* pupLimLine)
  182. {
  183. LSERR lserr;
  184. if (!FIsLSLINE(plsline))
  185. return lserrInvalidLine;
  186. if (plsline->lssubl.plsc->lsstate != LsStateFree)
  187. return lserrContextInUse;
  188. lserr = PrepareLineForDisplayProc(plsline);
  189. if (lserr != lserrNone)
  190. return lserr;
  191. *pupStartAutonumberingText = plsline->upStartAutonumberingText;
  192. *pupLimAutonumberingText = plsline->upLimAutonumberingText;
  193. *pupStartMainText = plsline->upStartMainText;
  194. *pupStartTrailing = plsline->upStartTrailing;
  195. *pupLimLine = plsline->upLimLine;
  196. return lserrNone;
  197. }
  198. // %%Function: LsQueryFLineEmpty
  199. // %%Contact: victork
  200. //
  201. LSERR WINAPI LsQueryFLineEmpty(PLSLINE plsline, /* IN: pointer to line -- opaque to client */
  202. BOOL* pfEmpty) /* OUT: Is line empty? */
  203. {
  204. enum endres endr;
  205. PLSDNODE plsdnFirst;
  206. if (!FIsLSLINE(plsline))
  207. return lserrInvalidLine;
  208. if (plsline->lssubl.plsc->lsstate != LsStateFree)
  209. return lserrContextInUse;
  210. endr = plsline->lslinfo.endr;
  211. if (endr == endrNormal || endr == endrHyphenated)
  212. {
  213. // line that ends like that cannot be empty
  214. *pfEmpty = fFalse;
  215. return lserrNone;
  216. }
  217. // skip autonumbering - it cannot make line non-empty
  218. for(plsdnFirst = plsline->lssubl.plsdnFirst;
  219. plsdnFirst != NULL && FIsNotInContent(plsdnFirst);
  220. plsdnFirst = plsdnFirst->plsdnNext);
  221. // plsdnFirst points to the first dnode in content now or it is NULL
  222. switch (endr)
  223. {
  224. case endrEndPara:
  225. case endrAltEndPara:
  226. case endrSoftCR:
  227. // last dnode contains EOP and doesn't count as content
  228. Assert(plsdnFirst != NULL);
  229. Assert(plsdnFirst->plsdnNext == NULL ||
  230. plsdnFirst->plsdnNext->cpFirst < plsline->lslinfo.cpLim);
  231. // EOP doesn't count as content - it cannot make line non-empty
  232. *pfEmpty = (plsdnFirst->plsdnNext == NULL);
  233. break;
  234. case endrEndColumn:
  235. case endrEndSection:
  236. case endrEndParaSection:
  237. case endrEndPage:
  238. case endrStopped:
  239. *pfEmpty = (plsdnFirst == NULL);
  240. break;
  241. default:
  242. NotReached();
  243. }
  244. return lserrNone;
  245. }
  246. // %%Function: AdjustForLeftIndent
  247. // %%Contact: victork
  248. //
  249. void AdjustForLeftIndent(PLSQSUBINFO plsqsubinfoResults, DWORD cQueryLim, PLSTEXTCELL plstextcell, long upStartLine)
  250. {
  251. plstextcell->pointUvStartCell.u += upStartLine;
  252. while (cQueryLim > 0)
  253. {
  254. plsqsubinfoResults->pointUvStartSubline.u += upStartLine;
  255. plsqsubinfoResults->pointUvStartRun.u += upStartLine;
  256. plsqsubinfoResults->pointUvStartObj.u += upStartLine;
  257. plsqsubinfoResults++;
  258. cQueryLim--;
  259. }
  260. }