Leaked source code of windows server 2003
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.

409 lines
11 KiB

  1. /*
  2. * Contains Display and CalcPres methods of display object
  3. */
  4. #include "disptext.h"
  5. #include "dispmisc.h"
  6. #include "lsdevice.h"
  7. #include "lstfset.h"
  8. #include "lstxtmap.h"
  9. #include "dispi.h"
  10. #include "txtobj.h"
  11. #include "txtln.h"
  12. #include "txtils.h"
  13. #include "lschp.h"
  14. #define TABBUFSIZE 32
  15. static LSERR DisplayGlyphs(PTXTOBJ ptxtobj, PCDISPIN pdispin);
  16. static LSERR DisplayTabLeader(PCDISPIN pdispin, PILSOBJ pilsobj, WCHAR wchtl);
  17. // %%Function: DisplayText
  18. // %%Contact: victork
  19. //
  20. LSERR WINAPI DisplayText(PDOBJ pdo, PCDISPIN pdispin)
  21. {
  22. LSERR lserr;
  23. PTXTOBJ ptxtobj;
  24. WCHAR wchSave;
  25. WCHAR* pwch;
  26. int iwch;
  27. int cwch;
  28. PILSOBJ pilsobj;
  29. POINT ptOrg, ptExtTextOut;
  30. POINTUV ptLeftCut;
  31. long dupStart;
  32. long dupPenStart;
  33. long* pdup;
  34. long* pdupPen;
  35. long* rgdupLeftCut;
  36. int i;
  37. void* (WINAPI* pfnNewPtr)(POLS, DWORD);
  38. void (WINAPI* pfnDisposePtr)(POLS, void*);
  39. ptxtobj = (PTXTOBJ) pdo;
  40. pilsobj = ptxtobj->plnobj->pilsobj;
  41. Assert(ptxtobj->txtkind == txtkindRegular ||
  42. ptxtobj->txtkind == txtkindHardHyphen ||
  43. ptxtobj->txtkind == txtkindTab ||
  44. ptxtobj->txtkind == txtkindNonReqHyphen ||
  45. ptxtobj->txtkind == txtkindYsrChar ||
  46. ptxtobj->txtkind == txtkindNonBreakSpace ||
  47. ptxtobj->txtkind == txtkindNonBreakHyphen ||
  48. ptxtobj->txtkind == txtkindOptNonBreak ||
  49. ptxtobj->txtkind == txtkindSpecSpace ||
  50. ptxtobj->txtkind == txtkindOptBreak ||
  51. ptxtobj->txtkind == txtkindEOL );
  52. if (ptxtobj->txtkind == txtkindTab)
  53. {
  54. Assert(ptxtobj->dupBefore == 0);
  55. if (pdispin->dup <= 0) /* do nothing for zero-length tab */
  56. {
  57. return lserrNone;
  58. }
  59. // Draw tab only if it is visi case
  60. if (ptxtobj->txtf&txtfVisi)
  61. {
  62. lserr = (*pilsobj->plscbk->pfnDrawTextRun)(pilsobj->pols, pdispin->plsrun,
  63. FALSE, FALSE, /* Tab leader will take care of UL */
  64. &(pdispin->ptPen), &(pilsobj->wchVisiTab),
  65. (const int*) &(pdispin->dup), 1,
  66. pdispin->lstflow, (const) pdispin->kDispMode,
  67. &(pdispin->ptPen), &(pdispin->heightsPres), pdispin->dup,
  68. pdispin->dupLimUnderline, pdispin->prcClip);
  69. if (lserr != lserrNone) return lserr;
  70. }
  71. if (ptxtobj->u.tab.wchTabLeader == pilsobj->wchSpace)
  72. {
  73. // it is OK to draw the space in one take
  74. lserr = (*pilsobj->plscbk->pfnDrawTextRun)(pilsobj->pols, pdispin->plsrun,
  75. pdispin->fDrawStrikethrough, pdispin->fDrawUnderline,
  76. &(pdispin->ptPen), &(pilsobj->wchSpace),
  77. (const int*) &(pdispin->dup), 1,
  78. pdispin->lstflow, (const) pdispin->kDispMode,
  79. &(pdispin->ptPen), &(pdispin->heightsPres), pdispin->dup,
  80. pdispin->dupLimUnderline, pdispin->prcClip);
  81. }
  82. else
  83. {
  84. // we should apply tab leader alingment logic
  85. lserr = DisplayTabLeader(pdispin, pilsobj, ptxtobj->u.tab.wchTabLeader);
  86. }
  87. return lserr;
  88. }
  89. if (ptxtobj->txtf & txtfGlyphBased)
  90. {
  91. return DisplayGlyphs(ptxtobj, pdispin);
  92. }
  93. iwch = ptxtobj->iwchFirst;
  94. pwch = ptxtobj->plnobj->pwch + iwch;
  95. cwch = ptxtobj->iwchLim - iwch;
  96. if (cwch == 0) // nothing to display
  97. {
  98. return lserrNone;
  99. }
  100. Assert(ptxtobj->plnobj->pdupPen == ptxtobj->plnobj->pdup || ptxtobj->plnobj->pdupPen == ptxtobj->plnobj->pdupPenAlloc);
  101. pdupPen = ptxtobj->plnobj->pdupPen + iwch;
  102. ptOrg = pdispin->ptPen;
  103. if (ptxtobj->dupBefore == 0)
  104. {
  105. ptExtTextOut = ptOrg;
  106. }
  107. else
  108. {
  109. ptLeftCut.u = -ptxtobj->dupBefore;
  110. ptLeftCut.v = 0;
  111. LsPointXYFromPointUV(&(ptOrg), pdispin->lstflow, &ptLeftCut, &ptExtTextOut);
  112. }
  113. // Have to deal with special spaces before DrawTextRun
  114. if (ptxtobj->txtkind == txtkindSpecSpace && !(ptxtobj->txtf&txtfVisi))
  115. {
  116. wchSave = *pwch; // remember actual code
  117. for (i = 0; i < cwch; i++)
  118. {
  119. pwch[i] = pilsobj->wchSpace; // replace special spaces with the normal space
  120. }
  121. lserr = (*pilsobj->plscbk->pfnDrawTextRun)(pilsobj->pols, pdispin->plsrun,
  122. pdispin->fDrawStrikethrough, pdispin->fDrawUnderline,
  123. &ptExtTextOut, pwch, (const int*) pdupPen, cwch,
  124. pdispin->lstflow, pdispin->kDispMode,
  125. &ptOrg, &(pdispin->heightsPres),
  126. pdispin->dup, pdispin->dupLimUnderline, pdispin->prcClip);
  127. if (lserr != lserrNone) return lserr;
  128. for (i = 0; i < cwch; i++)
  129. {
  130. pwch[i] = wchSave; // restore special spaces
  131. }
  132. }
  133. else
  134. {
  135. lserr = (*pilsobj->plscbk->pfnDrawTextRun)(pilsobj->pols, pdispin->plsrun,
  136. pdispin->fDrawStrikethrough, pdispin->fDrawUnderline,
  137. &ptExtTextOut, pwch, (const int*) pdupPen, cwch,
  138. pdispin->lstflow, pdispin->kDispMode,
  139. &ptOrg, &(pdispin->heightsPres),
  140. pdispin->dup, pdispin->dupLimUnderline, pdispin->prcClip);
  141. if (lserr != lserrNone) return lserr;
  142. }
  143. if (pdispin->plschp->EffectsFlags)
  144. {
  145. pfnNewPtr = pilsobj->plscbk->pfnNewPtr;
  146. pfnDisposePtr = pilsobj->plscbk->pfnDisposePtr;
  147. /* create array for LeftCut info */
  148. rgdupLeftCut = pfnNewPtr(pilsobj->pols, cwch * sizeof(*rgdupLeftCut));
  149. if (rgdupLeftCut == NULL)
  150. return lserrOutOfMemory;
  151. /* fill LeftCut info array */
  152. pdup = ptxtobj->plnobj->pdup + iwch;
  153. dupStart = pdup[0]; /* the beginning of char */
  154. dupPenStart = pdupPen[0]; /* starting position for drawing char */
  155. for (i = 1; i < cwch; i++)
  156. {
  157. rgdupLeftCut[i] = dupStart - dupPenStart;
  158. dupStart += pdup[i];
  159. dupPenStart += pdupPen[i];
  160. }
  161. rgdupLeftCut[0] = ptxtobj->dupBefore;
  162. lserr = (*pilsobj->plscbk->pfnDrawEffects)(pilsobj->pols, pdispin->plsrun, pdispin->plschp->EffectsFlags,
  163. &(ptOrg), pwch, (const int*) pdup, (const int*) rgdupLeftCut,
  164. ptxtobj->iwchLim - iwch,
  165. pdispin->lstflow, pdispin->kDispMode, &(pdispin->heightsPres),
  166. pdispin->dup, pdispin->dupLimUnderline, pdispin->prcClip);
  167. /* dispose of the array for LeftCut info */
  168. pfnDisposePtr(pilsobj->pols, rgdupLeftCut);
  169. }
  170. return lserr;
  171. }
  172. // %%Function: DisplayTabLeader
  173. // %%Contact: victork
  174. //
  175. static LSERR DisplayTabLeader(PCDISPIN pdispin, PILSOBJ pilsobj, WCHAR wchtl)
  176. {
  177. LSTFLOW lstflow = pdispin->lstflow;
  178. LONG dupSum, dupCh, dupAdj, z, zOnGrid;
  179. BOOL fGrow;
  180. WCHAR rgwch[TABBUFSIZE];
  181. LONG rgdup[TABBUFSIZE];
  182. LONG dupbuf;
  183. int i = 0, cwch, cwchout;
  184. LSERR lserr;
  185. POINT pt;
  186. POINTUV ptAdj = {0,0};
  187. lserr = (*pilsobj->plscbk->pfnGetRunCharWidths)(pilsobj->pols, pdispin->plsrun,
  188. lsdevPres, (LPCWSTR) &wchtl, 1,
  189. pdispin->dup, lstflow, (int*) &dupCh, &dupSum, (LONG*) &i);
  190. if (lserr != lserrNone) return lserr;
  191. if (i == 0 || dupCh <= 0) dupCh = 1;
  192. for (i = 0; i < TABBUFSIZE; ++i)
  193. {
  194. rgwch[i] = wchtl;
  195. rgdup[i] = dupCh;
  196. }
  197. /* advance to next multiple of dupCh
  198. dupAdj is the distance between "pt.z" and the next integral multiple of dupch.
  199. I.e. dupAdj = N * dupCh - "pt.x" where N is the smallest integer such that
  200. N * dupCh is not less than "pt.x" in Latin case.
  201. The starting pen position will be "rounded" to this "dupCh stop" by the assignment
  202. "pt.z += dupAdj" in the code below.
  203. Complications are:
  204. depending on lstflow "z" can be either x or y;
  205. depending on lstflow next can be bigger (Grow) or smaller;
  206. Simple formula dupAdj = (ptPen.x + dupCh - 1) / dupCh * dupCh - ptPen.x does not
  207. necessarily work if ptPen.x is negative;
  208. */
  209. if (lstflow & fUVertical)
  210. {
  211. z = pdispin->ptPen.y;
  212. }
  213. else
  214. {
  215. z = pdispin->ptPen.x;
  216. }
  217. if (lstflow & fUDirection)
  218. {
  219. fGrow = fFalse;
  220. }
  221. else
  222. {
  223. fGrow = fTrue;
  224. }
  225. zOnGrid = (z / dupCh) * dupCh;
  226. // zOnGrid is on grid, but maybe from the wrong side
  227. if (zOnGrid == z)
  228. {
  229. dupAdj = 0;
  230. }
  231. else if (zOnGrid > z)
  232. {
  233. if (fGrow)
  234. {
  235. dupAdj = zOnGrid - z; // zOnGrid is the point we want
  236. }
  237. else
  238. {
  239. dupAdj = dupCh - (zOnGrid - z); // zOnGrid is on the wrong side
  240. }
  241. }
  242. else // zOnGrid < z
  243. {
  244. if (!fGrow)
  245. {
  246. dupAdj = z - zOnGrid; // zOnGrid is the point we want
  247. }
  248. else
  249. {
  250. dupAdj = dupCh - (z - zOnGrid); // zOnGrid is on the wrong side
  251. }
  252. }
  253. cwch = (pdispin->dup - dupAdj) / dupCh; /* always round down */
  254. dupbuf = dupCh * TABBUFSIZE;
  255. #ifdef NEVER // We've decided to kill rcClip optimization for now.
  256. while (cwch > 0 && up <= pdispin->rcClip.right && lserr == lserrNone)
  257. #endif /* NEVER */
  258. while (cwch > 0 && lserr == lserrNone)
  259. {
  260. cwchout = cwch < TABBUFSIZE ? cwch : TABBUFSIZE;
  261. ptAdj.u = dupAdj;
  262. LsPointXYFromPointUV(&(pdispin->ptPen), lstflow, &ptAdj, &(pt));
  263. lserr = (*pilsobj->plscbk->pfnDrawTextRun)(pilsobj->pols, pdispin->plsrun,
  264. pdispin->fDrawStrikethrough, pdispin->fDrawUnderline,
  265. &pt, rgwch, (const int*) rgdup, cwchout,
  266. lstflow, pdispin->kDispMode, &pt, &(pdispin->heightsPres),
  267. dupCh * cwchout, pdispin->dupLimUnderline, pdispin->prcClip);
  268. cwch -= cwchout;
  269. dupAdj += dupbuf;
  270. }
  271. return lserr;
  272. }
  273. // %%Function: DisplayGlyphs
  274. // %%Contact: victork
  275. //
  276. static LSERR DisplayGlyphs(PTXTOBJ ptxtobj, PCDISPIN pdispin)
  277. {
  278. LSERR lserr;
  279. PLNOBJ plnobj = ptxtobj->plnobj;
  280. PILSOBJ pilsobj = plnobj->pilsobj;
  281. WCHAR* pwch;
  282. int iwch;
  283. int cwch;
  284. if (plnobj->fDrawInCharCodes)
  285. {
  286. // for meta-file output we call pfnDrawTextRun without widths
  287. iwch = ptxtobj->iwchFirst;
  288. pwch = ptxtobj->plnobj->pwch + iwch;
  289. cwch = ptxtobj->iwchLim - iwch;
  290. lserr = (*pilsobj->plscbk->pfnDrawTextRun)(pilsobj->pols, pdispin->plsrun,
  291. pdispin->fDrawStrikethrough, pdispin->fDrawUnderline,
  292. &(pdispin->ptPen), pwch, NULL, cwch,
  293. pdispin->lstflow, pdispin->kDispMode,
  294. &(pdispin->ptPen), &(pdispin->heightsPres),
  295. pdispin->dup, pdispin->dupLimUnderline, pdispin->prcClip);
  296. }
  297. else
  298. {
  299. lserr = (*pilsobj->plscbk->pfnDrawGlyphs)(pilsobj->pols, pdispin->plsrun,
  300. pdispin->fDrawStrikethrough, pdispin->fDrawUnderline,
  301. &plnobj->pgind[ptxtobj->igindFirst],
  302. (const int*)&plnobj->pdupGind[ptxtobj->igindFirst],
  303. (const int*)&plnobj->pdupBeforeJust[ptxtobj->igindFirst],
  304. &plnobj->pgoffs[ptxtobj->igindFirst],
  305. &plnobj->pgprop[ptxtobj->igindFirst],
  306. &plnobj->pexpt[ptxtobj->igindFirst],
  307. ptxtobj->igindLim - ptxtobj->igindFirst,
  308. pdispin->lstflow, pdispin->kDispMode,
  309. &(pdispin->ptPen), &(pdispin->heightsPres),
  310. pdispin->dup, pdispin->dupLimUnderline, pdispin->prcClip);
  311. }
  312. return lserr;
  313. }
  314. // %%Function: CalcPresentationText
  315. // %%Contact: victork
  316. //
  317. /*
  318. * CalcPres for text is called only for the dnode between autonumbering dnode and main text.
  319. * The dnode should contain one character (space).
  320. */
  321. LSERR WINAPI CalcPresentationText(PDOBJ pdobj, long dup, LSKJUST lskj, BOOL fLastOnLine)
  322. {
  323. PTXTOBJ ptxtobj = (PTXTOBJ)pdobj;
  324. Unreferenced(lskj);
  325. Unreferenced(fLastOnLine);
  326. Assert(ptxtobj->txtkind == txtkindRegular);
  327. Assert(ptxtobj->iwchFirst + 1 == ptxtobj->iwchLim);
  328. (ptxtobj->plnobj->pdup)[ptxtobj->iwchFirst] = dup;
  329. return lserrNone;
  330. }