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.

543 lines
14 KiB

  1. #include "dispmisc.h"
  2. #include "lsdnode.h"
  3. #include "lssubl.h"
  4. static long AddSublineAdvanceWidth(PLSSUBL plssubl);
  5. static PLSDNODE AdvanceToNextVisualDnodeCore(PLSDNODE, LSTFLOW, POINTUV*);
  6. static PLSDNODE NextVisualDnodeOnTheLevel(PLSDNODE pdn, LSTFLOW lstflowMain);
  7. #define fUVerticalPlusVDirection (fUVertical|fVDirection) // see comments in lstfset.c
  8. // Has this dnode submitted subline(s) for display?
  9. #define FIsSubmittingDnode(pdn) (FIsDnodeReal(pdn) && (pdn)->u.real.pinfosubl != NULL && \
  10. (pdn)->u.real.pinfosubl->fUseForDisplay)
  11. // Has this dnode accepted subline(s) for display?
  12. #define FIsAcceptingDnode(pdn) (FIsDnodeReal(pdn) && (pdn)->u.real.pinfosubl != NULL && \
  13. ((pdn)->u.real.pinfosubl->rgpsubl)[0]->fAcceptedForDisplay)
  14. // %%Function: CreateDisplayTree
  15. // %%Contact: victork
  16. //
  17. /* CreateDisplayTree sets plsdnUpTemp in sublines to be displayed with given subline,
  18. * rejects wrong sublines, submitted for display, sets fAcceptedForDisplay in good ones
  19. */
  20. void CreateDisplayTree(PLSSUBL plssubl)
  21. {
  22. LSTFLOW lstflowMain = plssubl->lstflow;
  23. PLSDNODE pdn = plssubl->plsdnFirst;
  24. long dupSum;
  25. BOOL fAccept;
  26. DWORD i;
  27. LSTFLOW lstflowSubline;
  28. while (pdn != NULL) /* don't care about break */
  29. {
  30. if (FIsSubmittingDnode(pdn))
  31. {
  32. Assert(pdn->u.real.pinfosubl->cSubline > 0);
  33. fAccept = fTrue;
  34. lstflowSubline = ((pdn->u.real.pinfosubl->rgpsubl)[0])->lstflow;
  35. // reject if one tflow is vertical, another is horizontal or v-directions are not the same
  36. // (see explanation of bits meaning in lstfset.c)
  37. if ((lstflowSubline ^ lstflowMain) & fUVerticalPlusVDirection)
  38. {
  39. fAccept = fFalse;
  40. }
  41. dupSum = 0;
  42. for (i = 0; i < pdn->u.real.pinfosubl->cSubline; i++)
  43. {
  44. dupSum += AddSublineAdvanceWidth((pdn->u.real.pinfosubl->rgpsubl)[i]);
  45. // all tflows should be the same
  46. if (((pdn->u.real.pinfosubl->rgpsubl)[i])->lstflow != lstflowSubline)
  47. {
  48. fAccept = fFalse;
  49. }
  50. // Submitting empty sublines is prohibited
  51. if (((pdn->u.real.pinfosubl->rgpsubl)[i])->plsdnFirst == NULL)
  52. {
  53. fAccept = fFalse;
  54. }
  55. }
  56. // reject if sublines don't sum up to the dnode width
  57. if (dupSum != pdn->u.real.dup)
  58. {
  59. fAccept = fFalse;
  60. }
  61. if (fAccept)
  62. {
  63. for (i = 0; i < pdn->u.real.pinfosubl->cSubline; i++)
  64. {
  65. ((pdn->u.real.pinfosubl->rgpsubl)[i])->plsdnUpTemp = pdn;
  66. ((pdn->u.real.pinfosubl->rgpsubl)[i])->fAcceptedForDisplay = fTrue;
  67. CreateDisplayTree((pdn->u.real.pinfosubl->rgpsubl)[i]);
  68. }
  69. }
  70. }
  71. pdn = pdn->plsdnNext;
  72. }
  73. }
  74. // %%Function: DestroyDisplayTree
  75. // %%Contact: victork
  76. //
  77. /*
  78. * DestroyDisplayTree nulls plsdnUpTemp in sublines displayed with given subline.
  79. */
  80. void DestroyDisplayTree(PLSSUBL plssubl)
  81. {
  82. PLSDNODE pdn = plssubl->plsdnFirst;
  83. DWORD i;
  84. while (pdn != NULL) /* don't care about break */
  85. {
  86. if (FIsAcceptingDnode(pdn))
  87. {
  88. for (i = 0; i < pdn->u.real.pinfosubl->cSubline; i++)
  89. {
  90. ((pdn->u.real.pinfosubl->rgpsubl)[i])->plsdnUpTemp = NULL;
  91. ((pdn->u.real.pinfosubl->rgpsubl)[i])->fAcceptedForDisplay = fFalse;
  92. DestroyDisplayTree((pdn->u.real.pinfosubl->rgpsubl)[i]);
  93. }
  94. }
  95. pdn = pdn->plsdnNext;
  96. }
  97. }
  98. // %%Function: AdvanceToNextDnode
  99. // %%Contact: victork
  100. //
  101. /*
  102. * Advance to the next (visual) node and update pen position, skipping submitting dnodes.
  103. */
  104. PLSDNODE AdvanceToNextDnode(PLSDNODE pdn, LSTFLOW lstflowMain, POINTUV* pptpen)
  105. {
  106. // move to the next
  107. pdn = AdvanceToNextVisualDnodeCore(pdn, lstflowMain, pptpen);
  108. // skip submitting dnodes
  109. while (pdn != NULL && FIsAcceptingDnode(pdn))
  110. {
  111. pdn = AdvanceToNextVisualDnodeCore(pdn, lstflowMain, pptpen);
  112. }
  113. return pdn;
  114. }
  115. // %%Function: AdvanceToFirstDnode
  116. // %%Contact: victork
  117. //
  118. PLSDNODE AdvanceToFirstDnode(PLSSUBL plssubl, LSTFLOW lstflowMain, POINTUV* pptpen)
  119. {
  120. PLSDNODE pdn = plssubl->plsdnFirst;
  121. if (pdn != NULL && FIsAcceptingDnode(pdn))
  122. {
  123. pdn = AdvanceToNextDnode(pdn, lstflowMain, pptpen);
  124. }
  125. return pdn;
  126. }
  127. // %%Function: AdvanceToNextSubmittingDnode
  128. // %%Contact: victork
  129. //
  130. /*
  131. * Advance to the next (visual) node and update pen position, stopping only at submitting dnodes.
  132. */
  133. PLSDNODE AdvanceToNextSubmittingDnode(PLSDNODE pdn, LSTFLOW lstflowMain, POINTUV* pptpen)
  134. {
  135. // move to the next
  136. pdn = AdvanceToNextVisualDnodeCore(pdn, lstflowMain, pptpen);
  137. // skip non-submitting dnodes
  138. while (pdn != NULL && !FIsAcceptingDnode(pdn))
  139. {
  140. pdn = AdvanceToNextVisualDnodeCore(pdn, lstflowMain, pptpen);
  141. }
  142. return pdn;
  143. }
  144. // %%Function: AdvanceToFirstSubmittingDnode
  145. // %%Contact: victork
  146. //
  147. PLSDNODE AdvanceToFirstSubmittingDnode(PLSSUBL plssubl, LSTFLOW lstflowMain, POINTUV* pptpen)
  148. {
  149. PLSDNODE pdn = plssubl->plsdnFirst;
  150. if (pdn != NULL && !FIsAcceptingDnode(pdn))
  151. {
  152. pdn = AdvanceToNextSubmittingDnode(pdn, lstflowMain, pptpen);
  153. }
  154. return pdn;
  155. }
  156. // %%Function: AdvanceToNextVisualDnodeCore
  157. // %%Contact: victork
  158. //
  159. /*
  160. * Advance to the next node and update pen position
  161. * Goes into sublines, submitted for display, traversing the whole display tree.
  162. * Stops at dnodes that submitted subline on the way down, skips them going up, so that
  163. * every dnode is visited once with pen position at the start of it in visual order.
  164. */
  165. static PLSDNODE AdvanceToNextVisualDnodeCore(PLSDNODE pdn, LSTFLOW lstflowMain, POINTUV* pptpen)
  166. {
  167. PLSDNODE pdnNextVisual, pdnTop;
  168. PLSSUBL plssublCurrent;
  169. long cSublines, i;
  170. PLSSUBL* rgpsubl;
  171. if (FIsAcceptingDnode(pdn))
  172. {
  173. // Last time we stopped at submitting dnode -
  174. // now don't move pen point, go down to the VisualStart of the VisualFirst subline.
  175. rgpsubl = pdn->u.real.pinfosubl->rgpsubl;
  176. cSublines = pdn->u.real.pinfosubl->cSubline;
  177. if (rgpsubl[0]->lstflow == lstflowMain)
  178. {
  179. pdnNextVisual = rgpsubl[0]->plsdnFirst;
  180. }
  181. else
  182. {
  183. pdnNextVisual = rgpsubl[cSublines - 1]->plsdnLastDisplay;
  184. }
  185. }
  186. else
  187. {
  188. // update pen position - we always move to the (visual) right, all vs are the same tflow
  189. if (pdn->klsdn == klsdnReal)
  190. {
  191. pptpen->u += pdn->u.real.dup;
  192. }
  193. else
  194. {
  195. pptpen->u += pdn->u.pen.dup;
  196. pptpen->v += pdn->u.pen.dvp;
  197. }
  198. plssublCurrent = pdn->plssubl;
  199. // go to the next dnode of the current subline in visual order
  200. pdnNextVisual = NextVisualDnodeOnTheLevel(pdn, lstflowMain);
  201. // If current subline is ended, (try) change subline.
  202. if (pdnNextVisual == NULL)
  203. {
  204. // Change subline
  205. //
  206. // In the loop: pdnNextVisual != NULL signals that next dnode is successfully found.
  207. // If pdnNextVisual == NULL, plssublCurrent is the subline just exhausted.
  208. // One run of the loop replaces current subline with another subline on the same level
  209. // (such change always ends the loop) or with parent subline.
  210. while (pdnNextVisual == NULL && plssublCurrent->plsdnUpTemp != NULL)
  211. {
  212. // find (the index of) the current subline in the list of submitted sublines
  213. pdnTop = plssublCurrent->plsdnUpTemp;
  214. rgpsubl = pdnTop->u.real.pinfosubl->rgpsubl;
  215. cSublines = pdnTop->u.real.pinfosubl->cSubline;
  216. for (i=0; i < cSublines && plssublCurrent != rgpsubl[i]; i++);
  217. Assert(i < cSublines);
  218. // do we have "next" subline? If we do, pdnNextVisual we seek "starts" it.
  219. if (pdnTop->plssubl->lstflow == lstflowMain)
  220. {
  221. i++;
  222. if (i < cSublines)
  223. {
  224. plssublCurrent = rgpsubl[i];
  225. pdnNextVisual = plssublCurrent->plsdnFirst;
  226. }
  227. }
  228. else
  229. {
  230. i--;
  231. if (i >= 0)
  232. {
  233. plssublCurrent = rgpsubl[i];
  234. pdnNextVisual = plssublCurrent->plsdnLastDisplay;
  235. }
  236. }
  237. // We don't, let's try next dnode on the upper level.
  238. if (pdnNextVisual == NULL)
  239. {
  240. plssublCurrent = pdnTop->plssubl;
  241. pdnNextVisual = NextVisualDnodeOnTheLevel(pdnTop, lstflowMain);
  242. }
  243. }
  244. }
  245. }
  246. return pdnNextVisual;
  247. }
  248. // %%Function: NextVisualDnodeOnTheLevel
  249. // %%Contact: victork
  250. //
  251. // find next dnode on the level moving right or left, signalling end with a NULL
  252. static PLSDNODE NextVisualDnodeOnTheLevel(PLSDNODE pdn, LSTFLOW lstflowMain)
  253. {
  254. if (pdn->plssubl->lstflow == lstflowMain)
  255. {
  256. if (pdn == pdn->plssubl->plsdnLastDisplay)
  257. {
  258. return NULL;
  259. }
  260. else
  261. {
  262. return pdn->plsdnNext;
  263. }
  264. }
  265. return pdn->plsdnPrev;
  266. }
  267. // %%Function: AddSublineAdvanceWidth
  268. // %%Contact: victork
  269. //
  270. // Note: It is not subline width as calculated in GetObjDimSubline
  271. static long AddSublineAdvanceWidth(PLSSUBL plssubl)
  272. {
  273. long dupSum;
  274. PLSDNODE pdn;
  275. pdn = plssubl->plsdnFirst;
  276. dupSum = 0;
  277. while (pdn != NULL)
  278. {
  279. if (pdn->klsdn == klsdnReal)
  280. {
  281. dupSum += pdn->u.real.dup;
  282. }
  283. else /* pen, border */
  284. {
  285. dupSum += pdn->u.pen.dup;
  286. }
  287. if (pdn == plssubl->plsdnLastDisplay)
  288. {
  289. pdn = NULL;
  290. }
  291. else
  292. {
  293. pdn = pdn->plsdnNext;
  294. Assert(pdn != NULL); // plsdnLastDisplay should prevent this
  295. }
  296. }
  297. return dupSum;
  298. }
  299. // NB Victork - following functions were used only for upClipLeft, upClipRight optimization.
  300. // If we'll decide that we do need that optimization after Word integration - I'll uncomment.
  301. #ifdef NEVER
  302. // %%Function: RectUVFromRectXY
  303. // %%Contact: victork
  304. //
  305. // There is an assymetry in the definition of the rectangle.
  306. // (Left, Top) belongs to rectangle and (Right, Bottom) doesn't,
  307. // It makes following procedures hard to understand and write.
  308. // So I first cut off the points that don't belong, then turn the rectangle, then add extra
  309. // points again and hope compiler will make it fast.
  310. // RectUVFromRectXY calculates (clip) rectangle in local (u,v) coordinates given
  311. // (clip) rectangle in (x,y) and point of origin
  312. void RectUVFromRectXY(const POINT* pptXY, /* IN: point of origin for local coordinates (x,y) */
  313. const RECT* prectXY, /* IN: input rectangle (x,y) */
  314. LSTFLOW lstflow, /* IN: local text flow */
  315. RECTUV* prectUV) /* OUT: output rectangle (u,v) */
  316. {
  317. switch (lstflow)
  318. {
  319. case lstflowES: /* latin */
  320. prectUV->upLeft = (prectXY->left - pptXY->x);
  321. prectUV->upRight = (prectXY->right - 1 - pptXY->x) + 1;
  322. prectUV->vpTop = -(prectXY->top - pptXY->y);
  323. prectUV->vpBottom = -(prectXY->bottom - 1 - pptXY->y) - 1;
  324. return;
  325. case lstflowSW: /* vertical FE */
  326. prectUV->upLeft = (prectXY->top - pptXY->y);
  327. prectUV->upRight = (prectXY->bottom - 1 - pptXY->y) + 1;
  328. prectUV->vpTop = (prectXY->right - 1 - pptXY->x);
  329. prectUV->vpBottom = (prectXY->left - pptXY->x) - 1;
  330. return;
  331. case lstflowWS: /* BiDi */
  332. prectUV->upLeft = -(prectXY->right - 1 - pptXY->x);
  333. prectUV->upRight = -(prectXY->left - pptXY->x) + 1;
  334. prectUV->vpTop = -(prectXY->top - pptXY->y);
  335. prectUV->vpBottom = -(prectXY->bottom - 1 - pptXY->y) - 1;
  336. return;
  337. case lstflowEN:
  338. prectUV->upLeft = (prectXY->left - pptXY->x);
  339. prectUV->upRight = (prectXY->right - 1 - pptXY->x) + 1;
  340. prectUV->vpTop = (prectXY->bottom - 1 - pptXY->y);
  341. prectUV->vpBottom = (prectXY->top - pptXY->y) - 1;
  342. return;
  343. case lstflowSE:
  344. prectUV->upLeft = (prectXY->top - pptXY->y);
  345. prectUV->upRight = (prectXY->bottom - 1 - pptXY->y) + 1;
  346. prectUV->vpTop = -(prectXY->left - pptXY->x);
  347. prectUV->vpBottom = -(prectXY->right - 1 - pptXY->x) - 1;
  348. return;
  349. case lstflowWN:
  350. prectUV->upLeft = -(prectXY->right - 1 - pptXY->x);
  351. prectUV->upRight = -(prectXY->left - pptXY->x) + 1;
  352. prectUV->vpTop = (prectXY->bottom - 1 - pptXY->y);
  353. prectUV->vpBottom = (prectXY->top - pptXY->y) - 1;
  354. return;
  355. case lstflowNE:
  356. prectUV->upLeft = -(prectXY->bottom - 1 - pptXY->y);
  357. prectUV->upRight = -(prectXY->top - pptXY->y) + 1;
  358. prectUV->vpTop = -(prectXY->left - pptXY->x);
  359. prectUV->vpBottom = -(prectXY->right - 1 - pptXY->x) - 1;
  360. return;
  361. case lstflowNW:
  362. prectUV->upLeft = -(prectXY->bottom - 1 - pptXY->y);
  363. prectUV->upRight = -(prectXY->top - pptXY->y) + 1;
  364. prectUV->vpTop = (prectXY->right - 1 - pptXY->x);
  365. prectUV->vpBottom = (prectXY->left - pptXY->x) - 1;
  366. return;
  367. default:
  368. NotReached();
  369. }
  370. }
  371. // %%Function: RectXYFromRectUV
  372. // %%Contact: victork
  373. //
  374. // RectXYFromRectUV calculates rectangle in (x,y) coordinates given rectangle in local (u,v)
  375. // and point of origin (x,y) for local coordinate system
  376. void RectXYFromRectUV(const POINT* pptXY, /* IN: point of origin for local coordinates (x,y) */
  377. PCRECTUV prectUV, /* IN: input rectangle (u,v) */
  378. LSTFLOW lstflow, /* IN: local text flow */
  379. RECT* prectXY) /* OUT: output rectangle (x,y) */
  380. {
  381. switch (lstflow)
  382. {
  383. case lstflowES: /* latin */
  384. prectXY->left = pptXY->x + prectUV->upLeft;
  385. prectXY->right = pptXY->x + (prectUV->upRight - 1) + 1;
  386. prectXY->top = pptXY->y - (prectUV->vpTop);
  387. prectXY->bottom = pptXY->y - (prectUV->vpBottom + 1) + 1;
  388. return;
  389. case lstflowSW: /* vertical FE */
  390. prectXY->left = pptXY->x + (prectUV->vpBottom + 1);
  391. prectXY->right = pptXY->x + (prectUV->vpTop) + 1;
  392. prectXY->top = pptXY->y + prectUV->upLeft;
  393. prectXY->bottom = pptXY->y + (prectUV->upRight - 1) + 1;
  394. return;
  395. case lstflowWS: /* BiDi */
  396. prectXY->left = pptXY->x - (prectUV->upRight - 1);
  397. prectXY->right = pptXY->x - prectUV->upLeft + 1;
  398. prectXY->top = pptXY->y - (prectUV->vpTop);
  399. prectXY->bottom = pptXY->y - (prectUV->vpBottom + 1) + 1;
  400. return;
  401. case lstflowEN:
  402. prectXY->left = pptXY->x + prectUV->upLeft;
  403. prectXY->right = pptXY->x + (prectUV->upRight - 1) + 1;
  404. prectXY->top = pptXY->y + (prectUV->vpBottom + 1);
  405. prectXY->bottom = pptXY->y + (prectUV->vpTop) + 1;
  406. return;
  407. case lstflowSE:
  408. prectXY->left = pptXY->x - (prectUV->vpTop);
  409. prectXY->right = pptXY->x - (prectUV->vpBottom + 1) + 1;
  410. prectXY->top = pptXY->y + prectUV->upLeft;
  411. prectXY->bottom = pptXY->y + (prectUV->upRight - 1) + 1;
  412. return;
  413. case lstflowWN:
  414. prectXY->left = pptXY->x - (prectUV->upRight - 1);
  415. prectXY->right = pptXY->x - prectUV->upLeft + 1;
  416. prectXY->top = pptXY->y + (prectUV->vpBottom + 1);
  417. prectXY->bottom = pptXY->y + (prectUV->vpTop) + 1;
  418. return;
  419. case lstflowNE:
  420. prectXY->left = pptXY->x - (prectUV->vpTop);
  421. prectXY->right = pptXY->x - (prectUV->vpBottom + 1) + 1;
  422. prectXY->top = pptXY->y - (prectUV->upRight - 1);
  423. prectXY->bottom = pptXY->y - prectUV->upLeft + 1;
  424. return;
  425. case lstflowNW:
  426. prectXY->left = pptXY->x + (prectUV->vpBottom + 1);
  427. prectXY->right = pptXY->x + (prectUV->vpTop) + 1;
  428. prectXY->top = pptXY->y - (prectUV->upRight - 1);
  429. prectXY->bottom = pptXY->y - prectUV->upLeft + 1;
  430. return;
  431. default:
  432. NotReached();
  433. }
  434. }
  435. #endif /* NEVER */