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.

520 lines
16 KiB

  1. #include "lstxtmap.h"
  2. #include "txtinf.h"
  3. #include "txtginf.h"
  4. #include "txtobj.h"
  5. #include "txtils.h"
  6. /* ============================================================== */
  7. /* IgndFirstFromIwch Find first GL index for a given IWCH */
  8. /* */
  9. /* Contact: antons */
  10. /* ============================================================== */
  11. long IgindFirstFromIwch(PTXTOBJ ptxtobj, long iwch)
  12. {
  13. PLNOBJ plnobj = ptxtobj->plnobj;
  14. Assert (FBetween (iwch, ptxtobj->iwchFirst, ptxtobj->iwchLim));
  15. /* Since "pilsobj->pgmap [iwch]" - */
  16. /* GL index is not absolute but RELATIVE to the first run shaped */
  17. /* with ptxtobj "together", we have to calculate required GL index */
  18. /* with the following folmula: */
  19. if (iwch == ptxtobj->iwchLim)
  20. return ptxtobj->igindLim;
  21. else
  22. return ptxtobj->igindFirst + plnobj->pgmap [iwch] -
  23. plnobj->pgmap [ptxtobj->iwchFirst];
  24. }
  25. /* ============================================================== */
  26. /* IgindFirstFromIwchVeryFirst */
  27. /* */
  28. /* Contact: antons */
  29. /* ============================================================== */
  30. long IgindFirstFromIwchVeryFirst (PTXTOBJ ptxtobj, long igindVeryFirst, long iwch)
  31. {
  32. Assert (ptxtobj->iwchLim > ptxtobj->iwchFirst);
  33. return igindVeryFirst + ptxtobj->plnobj->pgmap [iwch];
  34. }
  35. /* ============================================================== */
  36. /* IgindLastFromIwchVeryFirst */
  37. /* */
  38. /* Contact: antons */
  39. /* ============================================================== */
  40. long IgindLastFromIwchVeryFirst (PTXTOBJ ptxtobj, long igindVeryFirst, long iwch)
  41. {
  42. TXTGINF* pginf = ptxtobj->plnobj->pilsobj->pginf;
  43. long igindLast;
  44. Assert (ptxtobj->iwchLim > ptxtobj->iwchFirst);
  45. igindLast = IgindFirstFromIwchVeryFirst (ptxtobj, igindVeryFirst, iwch);
  46. while (! (pginf [igindLast] & ginffLastInContext)) igindLast++;
  47. return igindLast;
  48. }
  49. void GetIgindsFromTxtobj ( PTXTOBJ ptxtobj,
  50. long igindVeryFirst,
  51. long * pigindFirst,
  52. long * pigindLim )
  53. {
  54. PLNOBJ plnobj = ptxtobj->plnobj;
  55. PILSOBJ pilsobj = plnobj->pilsobj;
  56. TXTGINF* pginf = pilsobj->pginf;
  57. long igindLast;
  58. Assert (ptxtobj->iwchLim > ptxtobj->iwchFirst);
  59. Assert (pilsobj->ptxtinf [ptxtobj->iwchFirst].fFirstInContext);
  60. Assert (pilsobj->ptxtinf [ptxtobj->iwchLim-1].fLastInContext);
  61. *pigindFirst = igindVeryFirst + plnobj->pgmap [ptxtobj->iwchFirst];
  62. igindLast = IgindFirstFromIwch (ptxtobj, ptxtobj->iwchLim-1);
  63. while (! (pginf [igindLast] & ginffLastInContext)) igindLast++;
  64. *pigindLim = igindLast + 1;
  65. }
  66. /* ============================================================== */
  67. /* IgndLastFromIwch Find last GL index for a given IWCH */
  68. /* */
  69. /* Contact: antons */
  70. /* ============================================================== */
  71. long IgindLastFromIwch(PTXTOBJ ptxtobj, long iwch)
  72. {
  73. PILSOBJ pilsobj = ptxtobj->plnobj->pilsobj;
  74. TXTGINF* pginf = pilsobj->pginf;
  75. long igindLast;
  76. if (iwch < ptxtobj->iwchFirst)
  77. return -1;
  78. igindLast = IgindFirstFromIwch (ptxtobj, iwch);
  79. Assert (FBetween (iwch, ptxtobj->iwchFirst, ptxtobj->iwchLim-1));
  80. while (! (pginf [igindLast] & ginffLastInContext)) igindLast++;
  81. Assert (ptxtobj->igindLim == 0 || FBetween (igindLast, ptxtobj->igindFirst, ptxtobj->igindLim-1));
  82. return igindLast;
  83. }
  84. /* =================================================================== */
  85. /* IgindBaseFromIgind: */
  86. /* Returns last glyph with non-zero width before IGIND in this context */
  87. /* */
  88. /* Contact: antons */
  89. /* =================================================================== */
  90. long IgindBaseFromIgind(PILSOBJ pilsobj, long igind)
  91. {
  92. TXTGINF* pginf = pilsobj->pginf;
  93. /* Very simple... just scan back until <> 0 */
  94. while (pilsobj->pdurGind [igind] == 0 && !(pginf [igind] & ginffFirstInContext))
  95. {
  96. Assert (igind > 0);
  97. igind --;
  98. }
  99. return igind;
  100. }
  101. /* =================================================================== */
  102. /* IwchFirstFromIgind: */
  103. /* Returns first IWCH in the context for a given IGIND */
  104. /* */
  105. /* Contact: antons */
  106. /* =================================================================== */
  107. long IwchFirstFromIgind(PTXTOBJ ptxtobj, long igind)
  108. {
  109. PILSOBJ pilsobj = ptxtobj->plnobj->pilsobj;
  110. TXTINF* ptxtinf = pilsobj->ptxtinf;
  111. TXTGINF* pginf = pilsobj->pginf;
  112. long iwchFirst = ptxtobj->iwchFirst;
  113. long igindLast = ptxtobj->igindFirst;
  114. Assert (FBetween (igind, ptxtobj->igindFirst, ptxtobj->igindLim-1));
  115. /* Go ahead until we have found last GIND of the first conext in txtobj */
  116. while (! (pginf [igindLast] & ginffLastInContext)) igindLast++;
  117. /* The following LOOP goes ahead checking context after context /* beginning of txtobj
  118. INVARIANT:
  119. iwchFirst -- First IWCH of the current context
  120. igindLast -- Last GIND of the current context
  121. The second condition is true because of the "while" above
  122. */
  123. while (igindLast < igind)
  124. {
  125. /* Asserts to check that INVARIANT is true */
  126. Assert (ptxtinf [iwchFirst].fFirstInContext);
  127. Assert (pginf [igindLast] & ginffLastInContext);
  128. /* Move ahead by 1 context... it is easy */
  129. igindLast++;
  130. while (! (pginf [igindLast] & ginffLastInContext)) igindLast++;
  131. while (! (ptxtinf [iwchFirst]. fLastInContext)) iwchFirst++;
  132. iwchFirst++;
  133. };
  134. /* Asserts to check that we have not gone out from txtobj boundaries before reaching igind */
  135. Assert (FBetween (iwchFirst, ptxtobj->iwchFirst, ptxtobj->iwchLim-1));
  136. Assert (FBetween (igindLast, ptxtobj->igindFirst, ptxtobj->igindLim-1));
  137. /* Well, since INVARIANT is true and "igindLast >= igind",
  138. igind should belong to the current context. What we have to return
  139. is just iwchFirst
  140. */
  141. return iwchFirst;
  142. }
  143. /* =================================================================== */
  144. /* IwchLastFromIwch: */
  145. /* Returns last iwch of context from given iwch */
  146. /* */
  147. /* Contact: antons */
  148. /* =================================================================== */
  149. long IwchLastFromIwch(PTXTOBJ ptxtobj, long iwch)
  150. {
  151. PILSOBJ pilsobj = ptxtobj->plnobj->pilsobj;
  152. TXTINF* ptxtinf = pilsobj->ptxtinf;
  153. Assert(iwch >= ptxtobj->iwchFirst && iwch < ptxtobj->iwchLim);
  154. while (! (ptxtinf [iwch]. fLastInContext))
  155. iwch++;
  156. Assert(iwch >= ptxtobj->iwchFirst && iwch < ptxtobj->iwchLim);
  157. return iwch;
  158. }
  159. /* =================================================================== */
  160. /* IwchPrevLastFromIwch: */
  161. /* Returns last iwch of previous context from given iwch */
  162. /* */
  163. /* Contact: antons */
  164. /* =================================================================== */
  165. long IwchPrevLastFromIwch(PTXTOBJ ptxtobj, long iwch)
  166. {
  167. PILSOBJ pilsobj = ptxtobj->plnobj->pilsobj;
  168. TXTINF* ptxtinf = pilsobj->ptxtinf;
  169. long iwchFirst = ptxtobj->iwchFirst;
  170. iwch--;
  171. Assert(iwch >= ptxtobj->iwchFirst && iwch < ptxtobj->iwchLim);
  172. while (iwch >= iwchFirst && ! (ptxtinf [iwch]. fLastInContext))
  173. iwch--;
  174. return iwch;
  175. }
  176. /* =================================================================== */
  177. /* FIwchOneToOne: */
  178. /* Checks that IWCH belongs to 1:1 context */
  179. /* */
  180. /* Contact: antons */
  181. /* =================================================================== */
  182. BOOL FIwchOneToOne(PILSOBJ pilsobj, long iwch)
  183. {
  184. return pilsobj->ptxtinf [iwch].fOneToOne;
  185. }
  186. /* =================================================================== */
  187. /* FIwchLastInContext: */
  188. /* Checks that IWCH is last in the context */
  189. /* */
  190. /* Contact: antons */
  191. /* =================================================================== */
  192. BOOL FIwchLastInContext(PILSOBJ pilsobj, long iwch)
  193. {
  194. return pilsobj->ptxtinf [iwch].fLastInContext;
  195. }
  196. /* =================================================================== */
  197. /* FIwchFirstInContext: */
  198. /* Checks that IWCH is first in the context */
  199. /* */
  200. /* Contact: antons */
  201. /* =================================================================== */
  202. BOOL FIwchFirstInContext(PILSOBJ pilsobj, long iwch)
  203. {
  204. return pilsobj->ptxtinf [iwch].fFirstInContext;
  205. }
  206. /* =================================================================== */
  207. /* FIgindLastInContext: */
  208. /* Checks that a given GL index is last in the context */
  209. /* */
  210. /* Contact: antons */
  211. /* =================================================================== */
  212. BOOL FIgindLastInContext(PILSOBJ pilsobj, long igind)
  213. {
  214. return pilsobj->pginf [igind] & ginffLastInContext;
  215. }
  216. /* =================================================================== */
  217. /* FIgindFirstInContext: */
  218. /* Checks that a given GL index is first in the context */
  219. /* */
  220. /* Contact: antons */
  221. /* =================================================================== */
  222. BOOL FIgindFirstInContext(PILSOBJ pilsobj, long igind)
  223. {
  224. return pilsobj->pginf [igind] & ginffFirstInContext;
  225. }
  226. /* =================================================================== */
  227. /* DcpAfterContextFromDcp: */
  228. /* For a given DCP (from the beginning of txtobj) it returns DCP after */
  229. /* context bondary */
  230. /* */
  231. /* Function assumes that DCP starts with 1 and means */
  232. /* "number of characters" from the beginning of txtobj. The resulting */
  233. /* DCP (number of characters) will contain the rest of last context in */
  234. /* given DCP. If context was closed then it returns the same DCP */
  235. /* */
  236. /* Contact: antons */
  237. /* =================================================================== */
  238. long DcpAfterContextFromDcp(PTXTOBJ ptxtobj, long dcp)
  239. {
  240. PILSOBJ pilsobj = ptxtobj->plnobj->pilsobj;
  241. TXTINF* ptxtinf = pilsobj->ptxtinf;
  242. /* Translate dcp to iwchLast */
  243. long iwchLast = ptxtobj->iwchFirst + dcp - 1;
  244. /* Here we check that iwchLast "= dcp-1" is correct for a given txtobj */
  245. Assert (FBetween (iwchLast, ptxtobj->iwchFirst, ptxtobj->iwchLim-1));
  246. /* Just scan ahead until context finishes */
  247. while (! ptxtinf [iwchLast].fLastInContext) iwchLast++;
  248. /* Again check that we are in txtobj boundaries */
  249. Assert (FBetween (iwchLast, ptxtobj->iwchFirst, ptxtobj->iwchLim-1));
  250. /* Translate iwchLast back to dcp */
  251. return iwchLast - ptxtobj->iwchFirst + 1;
  252. }
  253. /* =================================================================== */
  254. /* InterpretMap */
  255. /* */
  256. /* Fills internal CH- and GL- based bits with context information */
  257. /* (the information is used by the rest functions in this file only) */
  258. /* */
  259. /* IN: pilsobj */
  260. /* iwchFirst - The first iwch in "shaped together" chunk */
  261. /* dwch - Number of characters in this chunk */
  262. /* igindFirst - The first gind in "shaped together chunk */
  263. /* cgind - Number of glyphs in this chunk */
  264. /* */
  265. /* OUT: (nothing) */
  266. /* */
  267. /* Contact: antons */
  268. /* =================================================================== */
  269. void InterpretMap(PLNOBJ plnobj, long iwchFirst, long dwch, long igindFirst, long cgind)
  270. {
  271. TXTINF* ptxtinf = plnobj->pilsobj->ptxtinf;
  272. TXTGINF* pginf = plnobj->pilsobj->pginf;
  273. GMAP* pgmap = plnobj->pgmap;
  274. /* Last possible iwch and gind (remember, they are "last", not "lim" */
  275. long iwchLast = iwchFirst + dwch - 1;
  276. long igindLast = igindFirst + cgind - 1;
  277. /* Two global variables for main loop */
  278. long iwchFirstInContext = iwchFirst;
  279. long igindFirstInContext = igindFirst;
  280. /* The following WHILE translates context after context
  281. INVARIANT:
  282. * iwchFirstInContext -- The first iwch in current context
  283. * igindFirstInContext -- The first gind in current context
  284. * All context to the left from current have been translated
  285. The loop translates current context and moves iwchFirstIn... &
  286. igindFirst... to the next context
  287. */
  288. while (iwchFirstInContext <= iwchLast)
  289. /* According to D.Gris I should have checked "!= iwchLast+1" but I do not
  290. like ship version to come to infinite loop even because of wrong data ;-)
  291. For debug, I will have Assert right after loop terminates */
  292. {
  293. /* Variables for last gind and iwch of the current context */
  294. long igindLastInContext;
  295. long iwchLastInContext = iwchFirstInContext;
  296. /* Just to make sure that igindFirst... corresponds to iwchFirst... */
  297. Assert ( pgmap [iwchFirstInContext] + igindFirst == igindFirstInContext );
  298. Assert (iwchLastInContext <= iwchLast);
  299. /* P.S. Since pgmap values are RELATIVE to the beginning of "shape together"
  300. chunk, we shall ALWAYS add igindFirst to pgmap value in order to get
  301. GL index in our meaning
  302. */
  303. /* Following simple loop with find correct iwchLastInContext */
  304. /* Note that we add igindFirst to pgmap value (see PS. above) */
  305. while ((iwchLastInContext <= iwchLast) && (pgmap [iwchLastInContext] + igindFirst == igindFirstInContext))
  306. iwchLastInContext++;
  307. iwchLastInContext--;
  308. /* Now we know iwchLastInContextare and we are ready to find igindLastInContext
  309. I will peep in pgmap value of the character following iwchLastInContext or take
  310. last avaiable GL index (igindLast) if iwchLastInContext is really last available
  311. */
  312. igindLastInContext = (iwchLastInContext < iwchLast ?
  313. pgmap [iwchLastInContext+1] + igindFirst - 1 :
  314. igindLast
  315. );
  316. /* Check that there is at least one GL inside our context */
  317. /* Note: we do not need to check the same for characters */
  318. Assert (igindFirstInContext <= igindLastInContext);
  319. /* It is time to set flags in our GL and CH arrays */
  320. if ( ( iwchFirstInContext == iwchLastInContext) &&
  321. (igindFirstInContext == igindLastInContext))
  322. {
  323. /* We have 1:1 mapping (I separate it for better perfomance) */
  324. ptxtinf [iwchFirstInContext].fOneToOne = fTrue;
  325. ptxtinf [iwchFirstInContext].fFirstInContext = fTrue;
  326. ptxtinf [iwchFirstInContext].fLastInContext = fTrue;
  327. /* See comments in "General case" */
  328. pginf [igindFirstInContext] |= ginffOneToOne | ginffFirstInContext | ginffLastInContext;
  329. }
  330. else
  331. {
  332. /* General case when there is not 1:1 mapping */
  333. long i; /* Variable for two loops */
  334. /* Set up character-based bits */
  335. for (i=iwchFirstInContext; i<=iwchLastInContext; i++)
  336. {
  337. ptxtinf [i].fOneToOne = fFalse; /* Of course, it is not 1:1 */
  338. /* I was considering whether to place boundary cases (first/last character
  339. in context) outside loop but finally came to the conclusion that it would
  340. cheaper both for code and perfomance to check it for each character as
  341. follows */
  342. ptxtinf [i].fFirstInContext = (i==iwchFirstInContext);
  343. ptxtinf [i].fLastInContext = (i==iwchLastInContext);
  344. };
  345. /* With glyph-based flags we can win some perfomance by setting all bits in
  346. one operation (since they are really bits, not booleans. Again I do not like
  347. to do separate job for context boundaries */
  348. for (i=igindFirstInContext; i<=igindLastInContext; i++)
  349. pginf [i] &= ~ (ginffOneToOne | ginffFirstInContext |
  350. ginffLastInContext);
  351. /* And finally I set corresponding bits for the first & last GLs in the context */
  352. pginf [igindFirstInContext] |= ginffFirstInContext;
  353. pginf [igindLastInContext] |= ginffLastInContext;
  354. };
  355. /* To start loop again we have to move to the next context. Now it is easy... */
  356. iwchFirstInContext = iwchLastInContext+1;
  357. igindFirstInContext = igindLastInContext+1;
  358. };
  359. /* See comments in the beginning of the loop */
  360. Assert (iwchFirstInContext == iwchLast + 1);
  361. Assert (igindFirstInContext == igindLast + 1);
  362. /* And according to INVARIANT, we are done */
  363. }