PageRenderTime 60ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 1ms

/src/harfbuzz-shaper.cpp

https://bitbucket.org/cyanogenmod/android_external_harfbuzz
C++ | 1352 lines | 1010 code | 138 blank | 204 comment | 295 complexity | 6039c6b7da231eb00f21e9cd2175c0b7 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
  3. *
  4. * This is part of HarfBuzz, an OpenType Layout engine library.
  5. *
  6. * Permission is hereby granted, without written agreement and without
  7. * license or royalty fees, to use, copy, modify, and distribute this
  8. * software and its documentation for any purpose, provided that the
  9. * above copyright notice and the following two paragraphs appear in
  10. * all copies of this software.
  11. *
  12. * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  13. * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  14. * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
  15. * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  16. * DAMAGE.
  17. *
  18. * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  19. * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  20. * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
  21. * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  22. * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  23. */
  24. #include "harfbuzz-shaper.h"
  25. #include "harfbuzz-shaper-private.h"
  26. extern "C" {
  27. #include "harfbuzz-debug.h"
  28. }
  29. #include "harfbuzz-stream-private.h"
  30. #include <assert.h>
  31. #include <stdio.h>
  32. #define HB_MIN(a, b) ((a) < (b) ? (a) : (b))
  33. #define HB_MAX(a, b) ((a) > (b) ? (a) : (b))
  34. // -----------------------------------------------------------------------------------------------------
  35. //
  36. // The line break algorithm. See http://www.unicode.org/reports/tr14/tr14-13.html
  37. //
  38. // -----------------------------------------------------------------------------------------------------
  39. /* The Unicode algorithm does in our opinion allow line breaks at some
  40. places they shouldn't be allowed. The following changes were thus
  41. made in comparison to the Unicode reference:
  42. EX->AL from DB to IB
  43. SY->AL from DB to IB
  44. SY->PO from DB to IB
  45. SY->PR from DB to IB
  46. SY->OP from DB to IB
  47. AL->PR from DB to IB
  48. AL->PO from DB to IB
  49. PR->PR from DB to IB
  50. PO->PO from DB to IB
  51. PR->PO from DB to IB
  52. PO->PR from DB to IB
  53. HY->PO from DB to IB
  54. HY->PR from DB to IB
  55. HY->OP from DB to IB
  56. NU->EX from PB to IB
  57. EX->PO from DB to IB
  58. */
  59. // The following line break classes are not treated by the table:
  60. // AI, BK, CB, CR, LF, NL, SA, SG, SP, XX
  61. enum break_class {
  62. // the first 4 values have to agree with the enum in QCharAttributes
  63. ProhibitedBreak, // PB in table
  64. DirectBreak, // DB in table
  65. IndirectBreak, // IB in table
  66. CombiningIndirectBreak, // CI in table
  67. CombiningProhibitedBreak // CP in table
  68. };
  69. #define DB DirectBreak
  70. #define IB IndirectBreak
  71. #define CI CombiningIndirectBreak
  72. #define CP CombiningProhibitedBreak
  73. #define PB ProhibitedBreak
  74. static const hb_uint8 breakTable[HB_LineBreak_JT+1][HB_LineBreak_JT+1] =
  75. {
  76. /* OP CL QU GL NS EX SY IS PR PO NU AL ID IN HY BA BB B2 ZW CM WJ H2 H3 JL JV JT */
  77. /* OP */ { PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, CP, PB, PB, PB, PB, PB, PB },
  78. /* CL */ { DB, PB, IB, IB, PB, PB, PB, PB, IB, IB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
  79. /* QU */ { PB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
  80. /* GL */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
  81. /* NS */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
  82. /* EX */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
  83. /* SY */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
  84. /* IS */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
  85. /* PR */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, DB, IB, IB, DB, DB, PB, CI, PB, IB, IB, IB, IB, IB },
  86. /* PO */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
  87. /* NU */ { IB, PB, IB, IB, IB, IB, PB, PB, IB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
  88. /* AL */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
  89. /* ID */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
  90. /* IN */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
  91. /* HY */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, DB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
  92. /* BA */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
  93. /* BB */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
  94. /* B2 */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, DB, PB, PB, CI, PB, DB, DB, DB, DB, DB },
  95. /* ZW */ { DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, PB, DB, DB, DB, DB, DB, DB, DB },
  96. /* CM */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
  97. /* WJ */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
  98. /* H2 */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, IB, IB },
  99. /* H3 */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, IB },
  100. /* JL */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, IB, IB, IB, IB, DB },
  101. /* JV */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, IB, IB },
  102. /* JT */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, IB }
  103. };
  104. #undef DB
  105. #undef IB
  106. #undef CI
  107. #undef CP
  108. #undef PB
  109. static const hb_uint8 graphemeTable[HB_Grapheme_LVT + 1][HB_Grapheme_LVT + 1] =
  110. {
  111. // Other, CR, LF, Control,Extend,L, V, T, LV, LVT
  112. { true , true , true , true , true , true , true , true , true , true }, // Other,
  113. { true , true , true , true , true , true , true , true , true , true }, // CR,
  114. { true , false, true , true , true , true , true , true , true , true }, // LF,
  115. { true , true , true , true , true , true , true , true , true , true }, // Control,
  116. { false, true , true , true , false, false, false, false, false, false }, // Extend,
  117. { true , true , true , true , true , false, true , true , true , true }, // L,
  118. { true , true , true , true , true , false, false, true , false, true }, // V,
  119. { true , true , true , true , true , true , false, false, false, false }, // T,
  120. { true , true , true , true , true , false, true , true , true , true }, // LV,
  121. { true , true , true , true , true , false, true , true , true , true }, // LVT
  122. };
  123. static void calcLineBreaks(const HB_UChar16 *uc, hb_uint32 len, HB_CharAttributes *charAttributes)
  124. {
  125. if (!len)
  126. return;
  127. // ##### can this fail if the first char is a surrogate?
  128. HB_LineBreakClass cls;
  129. HB_GraphemeClass grapheme;
  130. HB_GetGraphemeAndLineBreakClass(*uc, &grapheme, &cls);
  131. // handle case where input starts with an LF
  132. if (cls == HB_LineBreak_LF)
  133. cls = HB_LineBreak_BK;
  134. charAttributes[0].whiteSpace = (cls == HB_LineBreak_SP || cls == HB_LineBreak_BK);
  135. charAttributes[0].charStop = true;
  136. int lcls = cls;
  137. for (hb_uint32 i = 1; i < len; ++i) {
  138. charAttributes[i].whiteSpace = false;
  139. charAttributes[i].charStop = true;
  140. HB_UChar32 code = uc[i];
  141. HB_GraphemeClass ngrapheme;
  142. HB_LineBreakClass ncls;
  143. HB_GetGraphemeAndLineBreakClass(code, &ngrapheme, &ncls);
  144. charAttributes[i].charStop = graphemeTable[ngrapheme][grapheme];
  145. // handle surrogates
  146. if (ncls == HB_LineBreak_SG) {
  147. if (HB_IsHighSurrogate(uc[i]) && i < len - 1 && HB_IsLowSurrogate(uc[i+1])) {
  148. continue;
  149. } else if (HB_IsLowSurrogate(uc[i]) && HB_IsHighSurrogate(uc[i-1])) {
  150. code = HB_SurrogateToUcs4(uc[i-1], uc[i]);
  151. HB_GetGraphemeAndLineBreakClass(code, &ngrapheme, &ncls);
  152. charAttributes[i].charStop = false;
  153. } else {
  154. ncls = HB_LineBreak_AL;
  155. }
  156. }
  157. // set white space and char stop flag
  158. if (ncls >= HB_LineBreak_SP)
  159. charAttributes[i].whiteSpace = true;
  160. HB_LineBreakType lineBreakType = HB_NoBreak;
  161. if (cls >= HB_LineBreak_LF) {
  162. lineBreakType = HB_ForcedBreak;
  163. } else if(cls == HB_LineBreak_CR) {
  164. lineBreakType = (ncls == HB_LineBreak_LF) ? HB_NoBreak : HB_ForcedBreak;
  165. }
  166. if (ncls == HB_LineBreak_SP)
  167. goto next_no_cls_update;
  168. if (ncls >= HB_LineBreak_CR)
  169. goto next;
  170. {
  171. int tcls = ncls;
  172. // for south east asian chars that require a complex (dictionary analysis), the unicode
  173. // standard recommends to treat them as AL. thai_attributes and other attribute methods that
  174. // do dictionary analysis can override
  175. if (tcls >= HB_LineBreak_SA)
  176. tcls = HB_LineBreak_AL;
  177. if (cls >= HB_LineBreak_SA)
  178. cls = HB_LineBreak_AL;
  179. int brk = breakTable[cls][tcls];
  180. switch (brk) {
  181. case DirectBreak:
  182. lineBreakType = HB_Break;
  183. if (uc[i-1] == 0xad) // soft hyphen
  184. lineBreakType = HB_SoftHyphen;
  185. break;
  186. case IndirectBreak:
  187. lineBreakType = (lcls == HB_LineBreak_SP) ? HB_Break : HB_NoBreak;
  188. break;
  189. case CombiningIndirectBreak:
  190. lineBreakType = HB_NoBreak;
  191. if (lcls == HB_LineBreak_SP){
  192. if (i > 1)
  193. charAttributes[i-2].lineBreakType = HB_Break;
  194. } else {
  195. goto next_no_cls_update;
  196. }
  197. break;
  198. case CombiningProhibitedBreak:
  199. lineBreakType = HB_NoBreak;
  200. if (lcls != HB_LineBreak_SP)
  201. goto next_no_cls_update;
  202. case ProhibitedBreak:
  203. default:
  204. break;
  205. }
  206. }
  207. next:
  208. cls = ncls;
  209. next_no_cls_update:
  210. lcls = ncls;
  211. grapheme = ngrapheme;
  212. charAttributes[i-1].lineBreakType = lineBreakType;
  213. }
  214. charAttributes[len-1].lineBreakType = HB_ForcedBreak;
  215. }
  216. // --------------------------------------------------------------------------------------------------------------------------------------------
  217. //
  218. // Basic processing
  219. //
  220. // --------------------------------------------------------------------------------------------------------------------------------------------
  221. static inline void positionCluster(HB_ShaperItem *item, int gfrom, int glast)
  222. {
  223. int nmarks = glast - gfrom;
  224. assert(nmarks > 0);
  225. HB_Glyph *glyphs = item->glyphs;
  226. HB_GlyphAttributes *attributes = item->attributes;
  227. HB_GlyphMetrics baseMetrics;
  228. item->font->klass->getGlyphMetrics(item->font, glyphs[gfrom], &baseMetrics);
  229. if (item->item.script == HB_Script_Hebrew
  230. && (-baseMetrics.y) > baseMetrics.height)
  231. // we need to attach below the baseline, because of the hebrew iud.
  232. baseMetrics.height = -baseMetrics.y;
  233. // qDebug("---> positionCluster: cluster from %d to %d", gfrom, glast);
  234. // qDebug("baseInfo: %f/%f (%f/%f) off=%f/%f", baseInfo.x, baseInfo.y, baseInfo.width, baseInfo.height, baseInfo.xoff, baseInfo.yoff);
  235. HB_Fixed size = item->font->klass->getFontMetric(item->font, HB_FontAscent) / 10;
  236. HB_Fixed offsetBase = HB_FIXED_CONSTANT(1) + (size - HB_FIXED_CONSTANT(4)) / 4;
  237. if (size > HB_FIXED_CONSTANT(4))
  238. offsetBase += HB_FIXED_CONSTANT(4);
  239. else
  240. offsetBase += size;
  241. //qreal offsetBase = (size - 4) / 4 + qMin<qreal>(size, 4) + 1;
  242. // qDebug("offset = %f", offsetBase);
  243. bool rightToLeft = item->item.bidiLevel % 2;
  244. int i;
  245. unsigned char lastCmb = 0;
  246. HB_GlyphMetrics attachmentRect;
  247. memset(&attachmentRect, 0, sizeof(attachmentRect));
  248. for(i = 1; i <= nmarks; i++) {
  249. HB_Glyph mark = glyphs[gfrom+i];
  250. HB_GlyphMetrics markMetrics;
  251. item->font->klass->getGlyphMetrics(item->font, mark, &markMetrics);
  252. HB_FixedPoint p;
  253. p.x = p.y = 0;
  254. // qDebug("markInfo: %f/%f (%f/%f) off=%f/%f", markInfo.x, markInfo.y, markInfo.width, markInfo.height, markInfo.xoff, markInfo.yoff);
  255. HB_Fixed offset = offsetBase;
  256. unsigned char cmb = attributes[gfrom+i].combiningClass;
  257. // ### maybe the whole position determination should move down to heuristicSetGlyphAttributes. Would save some
  258. // bits in the glyphAttributes structure.
  259. if (cmb < 200) {
  260. // fixed position classes. We approximate by mapping to one of the others.
  261. // currently I added only the ones for arabic, hebrew, lao and thai.
  262. // for Lao and Thai marks with class 0, see below (heuristicSetGlyphAttributes)
  263. // add a bit more offset to arabic, a bit hacky
  264. if (cmb >= 27 && cmb <= 36 && offset < 3)
  265. offset +=1;
  266. // below
  267. if ((cmb >= 10 && cmb <= 18) ||
  268. cmb == 20 || cmb == 22 ||
  269. cmb == 29 || cmb == 32)
  270. cmb = HB_Combining_Below;
  271. // above
  272. else if (cmb == 23 || cmb == 27 || cmb == 28 ||
  273. cmb == 30 || cmb == 31 || (cmb >= 33 && cmb <= 36))
  274. cmb = HB_Combining_Above;
  275. //below-right
  276. else if (cmb == 9 || cmb == 103 || cmb == 118)
  277. cmb = HB_Combining_BelowRight;
  278. // above-right
  279. else if (cmb == 24 || cmb == 107 || cmb == 122)
  280. cmb = HB_Combining_AboveRight;
  281. else if (cmb == 25)
  282. cmb = HB_Combining_AboveLeft;
  283. // fixed:
  284. // 19 21
  285. }
  286. // combining marks of different class don't interact. Reset the rectangle.
  287. if (cmb != lastCmb) {
  288. //qDebug("resetting rect");
  289. attachmentRect = baseMetrics;
  290. }
  291. switch(cmb) {
  292. case HB_Combining_DoubleBelow:
  293. // ### wrong in rtl context!
  294. case HB_Combining_BelowLeft:
  295. p.y += offset;
  296. case HB_Combining_BelowLeftAttached:
  297. p.x += attachmentRect.x - markMetrics.x;
  298. p.y += (attachmentRect.y + attachmentRect.height) - markMetrics.y;
  299. break;
  300. case HB_Combining_Below:
  301. p.y += offset;
  302. case HB_Combining_BelowAttached:
  303. p.x += attachmentRect.x - markMetrics.x;
  304. p.y += (attachmentRect.y + attachmentRect.height) - markMetrics.y;
  305. p.x += (attachmentRect.width - markMetrics.width) / 2;
  306. break;
  307. case HB_Combining_BelowRight:
  308. p.y += offset;
  309. case HB_Combining_BelowRightAttached:
  310. p.x += attachmentRect.x + attachmentRect.width - markMetrics.width - markMetrics.x;
  311. p.y += attachmentRect.y + attachmentRect.height - markMetrics.y;
  312. break;
  313. case HB_Combining_Left:
  314. p.x -= offset;
  315. case HB_Combining_LeftAttached:
  316. break;
  317. case HB_Combining_Right:
  318. p.x += offset;
  319. case HB_Combining_RightAttached:
  320. break;
  321. case HB_Combining_DoubleAbove:
  322. // ### wrong in RTL context!
  323. case HB_Combining_AboveLeft:
  324. p.y -= offset;
  325. case HB_Combining_AboveLeftAttached:
  326. p.x += attachmentRect.x - markMetrics.x;
  327. p.y += attachmentRect.y - markMetrics.y - markMetrics.height;
  328. break;
  329. case HB_Combining_Above:
  330. p.y -= offset;
  331. case HB_Combining_AboveAttached:
  332. p.x += attachmentRect.x - markMetrics.x;
  333. p.y += attachmentRect.y - markMetrics.y - markMetrics.height;
  334. p.x += (attachmentRect.width - markMetrics.width) / 2;
  335. break;
  336. case HB_Combining_AboveRight:
  337. p.y -= offset;
  338. case HB_Combining_AboveRightAttached:
  339. p.x += attachmentRect.x + attachmentRect.width - markMetrics.x - markMetrics.width;
  340. p.y += attachmentRect.y - markMetrics.y - markMetrics.height;
  341. break;
  342. case HB_Combining_IotaSubscript:
  343. default:
  344. break;
  345. }
  346. // qDebug("char=%x combiningClass = %d offset=%f/%f", mark, cmb, p.x(), p.y());
  347. markMetrics.x += p.x;
  348. markMetrics.y += p.y;
  349. HB_GlyphMetrics unitedAttachmentRect = attachmentRect;
  350. unitedAttachmentRect.x = HB_MIN(attachmentRect.x, markMetrics.x);
  351. unitedAttachmentRect.y = HB_MIN(attachmentRect.y, markMetrics.y);
  352. unitedAttachmentRect.width = HB_MAX(attachmentRect.x + attachmentRect.width, markMetrics.x + markMetrics.width) - unitedAttachmentRect.x;
  353. unitedAttachmentRect.height = HB_MAX(attachmentRect.y + attachmentRect.height, markMetrics.y + markMetrics.height) - unitedAttachmentRect.y;
  354. attachmentRect = unitedAttachmentRect;
  355. lastCmb = cmb;
  356. if (rightToLeft) {
  357. item->offsets[gfrom+i].x = p.x;
  358. item->offsets[gfrom+i].y = p.y;
  359. } else {
  360. item->offsets[gfrom+i].x = p.x - baseMetrics.xOffset;
  361. item->offsets[gfrom+i].y = p.y - baseMetrics.yOffset;
  362. }
  363. item->advances[gfrom+i] = 0;
  364. }
  365. }
  366. void HB_HeuristicPosition(HB_ShaperItem *item)
  367. {
  368. HB_GetGlyphAdvances(item);
  369. HB_GlyphAttributes *attributes = item->attributes;
  370. int cEnd = -1;
  371. int i = item->num_glyphs;
  372. while (i--) {
  373. if (cEnd == -1 && attributes[i].mark) {
  374. cEnd = i;
  375. } else if (cEnd != -1 && !attributes[i].mark) {
  376. positionCluster(item, i, cEnd);
  377. cEnd = -1;
  378. }
  379. }
  380. }
  381. // set the glyph attributes heuristically. Assumes a 1 to 1 relationship between chars and glyphs
  382. // and no reordering.
  383. // also computes logClusters heuristically
  384. void HB_HeuristicSetGlyphAttributes(HB_ShaperItem *item)
  385. {
  386. const HB_UChar16 *uc = item->string + item->item.pos;
  387. hb_uint32 length = item->item.length;
  388. // ### zeroWidth and justification are missing here!!!!!
  389. // BEGIN android-changed
  390. // We apply the same fix for Chrome to Android.
  391. // Chrome team will talk with upsteam about it.
  392. assert(length <= item->num_glyphs);
  393. // END android-changed
  394. // qDebug("QScriptEngine::heuristicSetGlyphAttributes, num_glyphs=%d", item->num_glyphs);
  395. HB_GlyphAttributes *attributes = item->attributes;
  396. unsigned short *logClusters = item->log_clusters;
  397. hb_uint32 glyph_pos = 0;
  398. hb_uint32 i;
  399. for (i = 0; i < length; i++) {
  400. if (HB_IsHighSurrogate(uc[i]) && i < length - 1
  401. && HB_IsLowSurrogate(uc[i + 1])) {
  402. logClusters[i] = glyph_pos;
  403. logClusters[++i] = glyph_pos;
  404. } else {
  405. logClusters[i] = glyph_pos;
  406. }
  407. ++glyph_pos;
  408. }
  409. // BEGIN android-removed
  410. // We apply the same fix for Chrome to Android.
  411. // Chrome team will talk with upsteam about it
  412. //
  413. // assert(glyph_pos == item->num_glyphs);
  414. //
  415. // END android-removed
  416. // first char in a run is never (treated as) a mark
  417. int cStart = 0;
  418. const bool symbolFont = item->face->isSymbolFont;
  419. attributes[0].mark = false;
  420. attributes[0].clusterStart = true;
  421. attributes[0].dontPrint = (!symbolFont && uc[0] == 0x00ad) || HB_IsControlChar(uc[0]);
  422. int pos = 0;
  423. HB_CharCategory lastCat;
  424. int dummy;
  425. HB_GetUnicodeCharProperties(uc[0], &lastCat, &dummy);
  426. for (i = 1; i < length; ++i) {
  427. if (logClusters[i] == pos)
  428. // same glyph
  429. continue;
  430. ++pos;
  431. while (pos < logClusters[i]) {
  432. attributes[pos] = attributes[pos-1];
  433. ++pos;
  434. }
  435. // hide soft-hyphens by default
  436. if ((!symbolFont && uc[i] == 0x00ad) || HB_IsControlChar(uc[i]))
  437. attributes[pos].dontPrint = true;
  438. HB_CharCategory cat;
  439. int cmb;
  440. HB_GetUnicodeCharProperties(uc[i], &cat, &cmb);
  441. if (cat != HB_Mark_NonSpacing) {
  442. attributes[pos].mark = false;
  443. attributes[pos].clusterStart = true;
  444. attributes[pos].combiningClass = 0;
  445. cStart = logClusters[i];
  446. } else {
  447. if (cmb == 0) {
  448. // Fix 0 combining classes
  449. if ((uc[pos] & 0xff00) == 0x0e00) {
  450. // thai or lao
  451. if (uc[pos] == 0xe31 ||
  452. uc[pos] == 0xe34 ||
  453. uc[pos] == 0xe35 ||
  454. uc[pos] == 0xe36 ||
  455. uc[pos] == 0xe37 ||
  456. uc[pos] == 0xe47 ||
  457. uc[pos] == 0xe4c ||
  458. uc[pos] == 0xe4d ||
  459. uc[pos] == 0xe4e) {
  460. cmb = HB_Combining_AboveRight;
  461. } else if (uc[pos] == 0xeb1 ||
  462. uc[pos] == 0xeb4 ||
  463. uc[pos] == 0xeb5 ||
  464. uc[pos] == 0xeb6 ||
  465. uc[pos] == 0xeb7 ||
  466. uc[pos] == 0xebb ||
  467. uc[pos] == 0xecc ||
  468. uc[pos] == 0xecd) {
  469. cmb = HB_Combining_Above;
  470. } else if (uc[pos] == 0xebc) {
  471. cmb = HB_Combining_Below;
  472. }
  473. }
  474. }
  475. attributes[pos].mark = true;
  476. attributes[pos].clusterStart = false;
  477. attributes[pos].combiningClass = cmb;
  478. logClusters[i] = cStart;
  479. }
  480. // one gets an inter character justification point if the current char is not a non spacing mark.
  481. // as then the current char belongs to the last one and one gets a space justification point
  482. // after the space char.
  483. if (lastCat == HB_Separator_Space)
  484. attributes[pos-1].justification = HB_Space;
  485. else if (cat != HB_Mark_NonSpacing)
  486. attributes[pos-1].justification = HB_Character;
  487. else
  488. attributes[pos-1].justification = HB_NoJustification;
  489. lastCat = cat;
  490. }
  491. pos = logClusters[length-1];
  492. if (lastCat == HB_Separator_Space)
  493. attributes[pos].justification = HB_Space;
  494. else
  495. attributes[pos].justification = HB_Character;
  496. }
  497. #ifndef NO_OPENTYPE
  498. static const HB_OpenTypeFeature basic_features[] = {
  499. { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
  500. { HB_MAKE_TAG('l', 'i', 'g', 'a'), CcmpProperty },
  501. { HB_MAKE_TAG('c', 'l', 'i', 'g'), CcmpProperty },
  502. {0, 0}
  503. };
  504. #endif
  505. HB_Bool HB_ConvertStringToGlyphIndices(HB_ShaperItem *shaper_item)
  506. {
  507. if (shaper_item->glyphIndicesPresent) {
  508. shaper_item->num_glyphs = shaper_item->initialGlyphCount;
  509. shaper_item->glyphIndicesPresent = false;
  510. return true;
  511. }
  512. return shaper_item->font->klass
  513. ->convertStringToGlyphIndices(shaper_item->font,
  514. shaper_item->string + shaper_item->item.pos, shaper_item->item.length,
  515. shaper_item->glyphs, &shaper_item->num_glyphs,
  516. shaper_item->item.bidiLevel % 2);
  517. }
  518. HB_Bool HB_BasicShape(HB_ShaperItem *shaper_item)
  519. {
  520. #ifndef NO_OPENTYPE
  521. const int availableGlyphs = shaper_item->num_glyphs;
  522. #endif
  523. if (!HB_ConvertStringToGlyphIndices(shaper_item))
  524. return false;
  525. HB_HeuristicSetGlyphAttributes(shaper_item);
  526. #ifndef NO_OPENTYPE
  527. if (HB_SelectScript(shaper_item, basic_features)) {
  528. HB_OpenTypeShape(shaper_item, /*properties*/0);
  529. return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters*/true);
  530. }
  531. #endif
  532. HB_HeuristicPosition(shaper_item);
  533. return true;
  534. }
  535. const HB_ScriptEngine HB_ScriptEngines[] = {
  536. // Common
  537. { HB_BasicShape, 0},
  538. // Greek
  539. { HB_GreekShape, 0},
  540. // Cyrillic
  541. { HB_BasicShape, 0},
  542. // Armenian
  543. { HB_BasicShape, 0},
  544. // Hebrew
  545. { HB_HebrewShape, 0 },
  546. // Arabic
  547. { HB_ArabicShape, 0},
  548. // Syriac
  549. { HB_ArabicShape, 0},
  550. // Thaana
  551. { HB_BasicShape, 0 },
  552. // Devanagari
  553. { HB_IndicShape, HB_IndicAttributes },
  554. // Bengali
  555. { HB_IndicShape, HB_IndicAttributes },
  556. // Gurmukhi
  557. { HB_IndicShape, HB_IndicAttributes },
  558. // Gujarati
  559. { HB_IndicShape, HB_IndicAttributes },
  560. // Oriya
  561. { HB_IndicShape, HB_IndicAttributes },
  562. // Tamil
  563. { HB_IndicShape, HB_IndicAttributes },
  564. // Telugu
  565. { HB_IndicShape, HB_IndicAttributes },
  566. // Kannada
  567. { HB_IndicShape, HB_IndicAttributes },
  568. // Malayalam
  569. { HB_IndicShape, HB_IndicAttributes },
  570. // Sinhala
  571. { HB_IndicShape, HB_IndicAttributes },
  572. // Thai
  573. { HB_BasicShape, HB_ThaiAttributes },
  574. // Lao
  575. { HB_BasicShape, 0 },
  576. // Tibetan
  577. { HB_TibetanShape, HB_TibetanAttributes },
  578. // Myanmar
  579. { HB_MyanmarShape, HB_MyanmarAttributes },
  580. // Georgian
  581. { HB_BasicShape, 0 },
  582. // Hangul
  583. { HB_HangulShape, 0 },
  584. // Ogham
  585. { HB_BasicShape, 0 },
  586. // Runic
  587. { HB_BasicShape, 0 },
  588. // Khmer
  589. { HB_KhmerShape, HB_KhmerAttributes },
  590. // N'Ko
  591. { HB_ArabicShape, 0}
  592. };
  593. void HB_GetCharAttributes(const HB_UChar16 *string, hb_uint32 stringLength,
  594. const HB_ScriptItem *items, hb_uint32 numItems,
  595. HB_CharAttributes *attributes)
  596. {
  597. calcLineBreaks(string, stringLength, attributes);
  598. for (hb_uint32 i = 0; i < numItems; ++i) {
  599. HB_Script script = items[i].script;
  600. if (script == HB_Script_Inherited)
  601. script = HB_Script_Common;
  602. HB_AttributeFunction attributeFunction = HB_ScriptEngines[script].charAttributes;
  603. if (!attributeFunction)
  604. continue;
  605. attributeFunction(script, string, items[i].pos, items[i].length, attributes);
  606. }
  607. }
  608. enum BreakRule { NoBreak = 0, Break = 1, Middle = 2 };
  609. static const hb_uint8 wordbreakTable[HB_Word_ExtendNumLet + 1][HB_Word_ExtendNumLet + 1] = {
  610. // Other Format Katakana ALetter MidLetter MidNum Numeric ExtendNumLet
  611. { Break, Break, Break, Break, Break, Break, Break, Break }, // Other
  612. { Break, Break, Break, Break, Break, Break, Break, Break }, // Format
  613. { Break, Break, NoBreak, Break, Break, Break, Break, NoBreak }, // Katakana
  614. { Break, Break, Break, NoBreak, Middle, Break, NoBreak, NoBreak }, // ALetter
  615. { Break, Break, Break, Break, Break, Break, Break, Break }, // MidLetter
  616. { Break, Break, Break, Break, Break, Break, Break, Break }, // MidNum
  617. { Break, Break, Break, NoBreak, Break, Middle, NoBreak, NoBreak }, // Numeric
  618. { Break, Break, NoBreak, NoBreak, Break, Break, NoBreak, NoBreak }, // ExtendNumLet
  619. };
  620. void HB_GetWordBoundaries(const HB_UChar16 *string, hb_uint32 stringLength,
  621. const HB_ScriptItem * /*items*/, hb_uint32 /*numItems*/,
  622. HB_CharAttributes *attributes)
  623. {
  624. if (stringLength == 0)
  625. return;
  626. unsigned int brk = HB_GetWordClass(string[0]);
  627. attributes[0].wordBoundary = true;
  628. for (hb_uint32 i = 1; i < stringLength; ++i) {
  629. if (!attributes[i].charStop) {
  630. attributes[i].wordBoundary = false;
  631. continue;
  632. }
  633. hb_uint32 nbrk = HB_GetWordClass(string[i]);
  634. if (nbrk == HB_Word_Format) {
  635. attributes[i].wordBoundary = (HB_GetSentenceClass(string[i-1]) == HB_Sentence_Sep);
  636. continue;
  637. }
  638. BreakRule rule = (BreakRule)wordbreakTable[brk][nbrk];
  639. if (rule == Middle) {
  640. rule = Break;
  641. hb_uint32 lookahead = i + 1;
  642. while (lookahead < stringLength) {
  643. hb_uint32 testbrk = HB_GetWordClass(string[lookahead]);
  644. if (testbrk == HB_Word_Format && HB_GetSentenceClass(string[lookahead]) != HB_Sentence_Sep) {
  645. ++lookahead;
  646. continue;
  647. }
  648. if (testbrk == brk) {
  649. rule = NoBreak;
  650. while (i < lookahead)
  651. attributes[i++].wordBoundary = false;
  652. nbrk = testbrk;
  653. }
  654. break;
  655. }
  656. }
  657. attributes[i].wordBoundary = (rule == Break);
  658. brk = nbrk;
  659. }
  660. }
  661. enum SentenceBreakStates {
  662. SB_Initial,
  663. SB_Upper,
  664. SB_UpATerm,
  665. SB_ATerm,
  666. SB_ATermC,
  667. SB_ACS,
  668. SB_STerm,
  669. SB_STermC,
  670. SB_SCS,
  671. SB_BAfter,
  672. SB_Break,
  673. SB_Look
  674. };
  675. static const hb_uint8 sentenceBreakTable[HB_Sentence_Close + 1][HB_Sentence_Close + 1] = {
  676. // Other Sep Format Sp Lower Upper OLetter Numeric ATerm STerm Close
  677. { SB_Initial, SB_BAfter , SB_Initial, SB_Initial, SB_Initial, SB_Upper , SB_Initial, SB_Initial, SB_ATerm , SB_STerm , SB_Initial }, // SB_Initial,
  678. { SB_Initial, SB_BAfter , SB_Upper , SB_Initial, SB_Initial, SB_Upper , SB_Initial, SB_Initial, SB_UpATerm, SB_STerm , SB_Initial }, // SB_Upper
  679. { SB_Look , SB_BAfter , SB_UpATerm, SB_ACS , SB_Initial, SB_Upper , SB_Break , SB_Initial, SB_ATerm , SB_STerm , SB_ATermC }, // SB_UpATerm
  680. { SB_Look , SB_BAfter , SB_ATerm , SB_ACS , SB_Initial, SB_Break , SB_Break , SB_Initial, SB_ATerm , SB_STerm , SB_ATermC }, // SB_ATerm
  681. { SB_Look , SB_BAfter , SB_ATermC , SB_ACS , SB_Initial, SB_Break , SB_Break , SB_Look , SB_ATerm , SB_STerm , SB_ATermC }, // SB_ATermC,
  682. { SB_Look , SB_BAfter , SB_ACS , SB_ACS , SB_Initial, SB_Break , SB_Break , SB_Look , SB_ATerm , SB_STerm , SB_Look }, // SB_ACS,
  683. { SB_Break , SB_BAfter , SB_STerm , SB_SCS , SB_Break , SB_Break , SB_Break , SB_Break , SB_ATerm , SB_STerm , SB_STermC }, // SB_STerm,
  684. { SB_Break , SB_BAfter , SB_STermC , SB_SCS , SB_Break , SB_Break , SB_Break , SB_Break , SB_ATerm , SB_STerm , SB_STermC }, // SB_STermC,
  685. { SB_Break , SB_BAfter , SB_SCS , SB_SCS , SB_Break , SB_Break , SB_Break , SB_Break , SB_ATerm , SB_STerm , SB_Break }, // SB_SCS,
  686. { SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break }, // SB_BAfter,
  687. };
  688. void HB_GetSentenceBoundaries(const HB_UChar16 *string, hb_uint32 stringLength,
  689. const HB_ScriptItem * /*items*/, hb_uint32 /*numItems*/,
  690. HB_CharAttributes *attributes)
  691. {
  692. if (stringLength == 0)
  693. return;
  694. hb_uint32 brk = sentenceBreakTable[SB_Initial][HB_GetSentenceClass(string[0])];
  695. attributes[0].sentenceBoundary = true;
  696. for (hb_uint32 i = 1; i < stringLength; ++i) {
  697. if (!attributes[i].charStop) {
  698. attributes[i].sentenceBoundary = false;
  699. continue;
  700. }
  701. brk = sentenceBreakTable[brk][HB_GetSentenceClass(string[i])];
  702. if (brk == SB_Look) {
  703. brk = SB_Break;
  704. hb_uint32 lookahead = i + 1;
  705. while (lookahead < stringLength) {
  706. hb_uint32 sbrk = HB_GetSentenceClass(string[lookahead]);
  707. if (sbrk != HB_Sentence_Other && sbrk != HB_Sentence_Numeric && sbrk != HB_Sentence_Close) {
  708. break;
  709. } else if (sbrk == HB_Sentence_Lower) {
  710. brk = SB_Initial;
  711. break;
  712. }
  713. ++lookahead;
  714. }
  715. if (brk == SB_Initial) {
  716. while (i < lookahead)
  717. attributes[i++].sentenceBoundary = false;
  718. }
  719. }
  720. if (brk == SB_Break) {
  721. attributes[i].sentenceBoundary = true;
  722. brk = sentenceBreakTable[SB_Initial][HB_GetSentenceClass(string[i])];
  723. } else {
  724. attributes[i].sentenceBoundary = false;
  725. }
  726. }
  727. }
  728. static inline char *tag_to_string(HB_UInt tag)
  729. {
  730. static char string[5];
  731. string[0] = (tag >> 24)&0xff;
  732. string[1] = (tag >> 16)&0xff;
  733. string[2] = (tag >> 8)&0xff;
  734. string[3] = tag&0xff;
  735. string[4] = 0;
  736. return string;
  737. }
  738. #ifdef OT_DEBUG
  739. static void dump_string(HB_Buffer buffer)
  740. {
  741. for (uint i = 0; i < buffer->in_length; ++i) {
  742. qDebug(" %x: cluster=%d", buffer->in_string[i].gindex, buffer->in_string[i].cluster);
  743. }
  744. }
  745. #define DEBUG printf
  746. #else
  747. #define DEBUG HBDebug
  748. #endif
  749. #define DefaultLangSys 0xffff
  750. #define DefaultScript HB_MAKE_TAG('D', 'F', 'L', 'T')
  751. enum {
  752. RequiresGsub = 1,
  753. RequiresGpos = 2
  754. };
  755. struct OTScripts {
  756. unsigned int tag;
  757. int flags;
  758. };
  759. static const OTScripts ot_scripts [] = {
  760. // Common
  761. { HB_MAKE_TAG('l', 'a', 't', 'n'), 0 },
  762. // Greek
  763. { HB_MAKE_TAG('g', 'r', 'e', 'k'), 0 },
  764. // Cyrillic
  765. { HB_MAKE_TAG('c', 'y', 'r', 'l'), 0 },
  766. // Armenian
  767. { HB_MAKE_TAG('a', 'r', 'm', 'n'), 0 },
  768. // Hebrew
  769. { HB_MAKE_TAG('h', 'e', 'b', 'r'), 1 },
  770. // Arabic
  771. { HB_MAKE_TAG('a', 'r', 'a', 'b'), 1 },
  772. // Syriac
  773. { HB_MAKE_TAG('s', 'y', 'r', 'c'), 1 },
  774. // Thaana
  775. { HB_MAKE_TAG('t', 'h', 'a', 'a'), 1 },
  776. // Devanagari
  777. { HB_MAKE_TAG('d', 'e', 'v', 'a'), 1 },
  778. // Bengali
  779. { HB_MAKE_TAG('b', 'e', 'n', 'g'), 1 },
  780. // Gurmukhi
  781. { HB_MAKE_TAG('g', 'u', 'r', 'u'), 1 },
  782. // Gujarati
  783. { HB_MAKE_TAG('g', 'u', 'j', 'r'), 1 },
  784. // Oriya
  785. { HB_MAKE_TAG('o', 'r', 'y', 'a'), 1 },
  786. // Tamil
  787. { HB_MAKE_TAG('t', 'a', 'm', 'l'), 1 },
  788. // Telugu
  789. { HB_MAKE_TAG('t', 'e', 'l', 'u'), 1 },
  790. // Kannada
  791. { HB_MAKE_TAG('k', 'n', 'd', 'a'), 1 },
  792. // Malayalam
  793. { HB_MAKE_TAG('m', 'l', 'y', 'm'), 1 },
  794. // Sinhala
  795. { HB_MAKE_TAG('s', 'i', 'n', 'h'), 1 },
  796. // Thai
  797. { HB_MAKE_TAG('t', 'h', 'a', 'i'), 1 },
  798. // Lao
  799. { HB_MAKE_TAG('l', 'a', 'o', ' '), 1 },
  800. // Tibetan
  801. { HB_MAKE_TAG('t', 'i', 'b', 't'), 1 },
  802. // Myanmar
  803. { HB_MAKE_TAG('m', 'y', 'm', 'r'), 1 },
  804. // Georgian
  805. { HB_MAKE_TAG('g', 'e', 'o', 'r'), 0 },
  806. // Hangul
  807. { HB_MAKE_TAG('h', 'a', 'n', 'g'), 1 },
  808. // Ogham
  809. { HB_MAKE_TAG('o', 'g', 'a', 'm'), 0 },
  810. // Runic
  811. { HB_MAKE_TAG('r', 'u', 'n', 'r'), 0 },
  812. // Khmer
  813. { HB_MAKE_TAG('k', 'h', 'm', 'r'), 1 },
  814. // N'Ko
  815. { HB_MAKE_TAG('n', 'k', 'o', ' '), 1 }
  816. };
  817. enum { NumOTScripts = sizeof(ot_scripts)/sizeof(OTScripts) };
  818. static HB_Bool checkScript(HB_Face face, int script)
  819. {
  820. assert(script < HB_ScriptCount);
  821. if (!face->gsub && !face->gpos)
  822. return false;
  823. unsigned int tag = ot_scripts[script].tag;
  824. int requirements = ot_scripts[script].flags;
  825. if (requirements & RequiresGsub) {
  826. if (!face->gsub)
  827. return false;
  828. HB_UShort script_index;
  829. HB_Error error = HB_GSUB_Select_Script(face->gsub, tag, &script_index);
  830. if (error) {
  831. DEBUG("could not select script %d in GSub table: %d", (int)script, error);
  832. error = HB_GSUB_Select_Script(face->gsub, HB_MAKE_TAG('D', 'F', 'L', 'T'), &script_index);
  833. if (error)
  834. return false;
  835. }
  836. }
  837. if (requirements & RequiresGpos) {
  838. if (!face->gpos)
  839. return false;
  840. HB_UShort script_index;
  841. HB_Error error = HB_GPOS_Select_Script(face->gpos, script, &script_index);
  842. if (error) {
  843. DEBUG("could not select script in gpos table: %d", error);
  844. error = HB_GPOS_Select_Script(face->gpos, HB_MAKE_TAG('D', 'F', 'L', 'T'), &script_index);
  845. if (error)
  846. return false;
  847. }
  848. }
  849. return true;
  850. }
  851. static HB_Stream getTableStream(void *font, HB_GetFontTableFunc tableFunc, HB_Tag tag)
  852. {
  853. HB_Error error;
  854. HB_UInt length = 0;
  855. HB_Stream stream = 0;
  856. if (!font)
  857. return 0;
  858. error = tableFunc(font, tag, 0, &length);
  859. if (error)
  860. return 0;
  861. stream = (HB_Stream)malloc(sizeof(HB_StreamRec));
  862. if (!stream)
  863. return 0;
  864. stream->base = (HB_Byte*)malloc(length);
  865. if (!stream->base) {
  866. free(stream);
  867. return 0;
  868. }
  869. error = tableFunc(font, tag, stream->base, &length);
  870. if (error) {
  871. _hb_close_stream(stream);
  872. return 0;
  873. }
  874. stream->size = length;
  875. stream->pos = 0;
  876. stream->cursor = NULL;
  877. return stream;
  878. }
  879. HB_Face HB_NewFace(void *font, HB_GetFontTableFunc tableFunc)
  880. {
  881. HB_Face face = (HB_Face )malloc(sizeof(HB_FaceRec));
  882. if (!face)
  883. return 0;
  884. face->isSymbolFont = false;
  885. face->gdef = 0;
  886. face->gpos = 0;
  887. face->gsub = 0;
  888. face->current_script = HB_ScriptCount;
  889. face->current_flags = HB_ShaperFlag_Default;
  890. face->has_opentype_kerning = false;
  891. face->tmpAttributes = 0;
  892. face->tmpLogClusters = 0;
  893. face->glyphs_substituted = false;
  894. face->buffer = 0;
  895. HB_Error error = HB_Err_Ok;
  896. HB_Stream stream;
  897. HB_Stream gdefStream;
  898. gdefStream = getTableStream(font, tableFunc, TTAG_GDEF);
  899. error = HB_Err_Not_Covered;
  900. if (!gdefStream || (error = HB_Load_GDEF_Table(gdefStream, &face->gdef))) {
  901. //DEBUG("error loading gdef table: %d", error);
  902. face->gdef = 0;
  903. }
  904. //DEBUG() << "trying to load gsub table";
  905. stream = getTableStream(font, tableFunc, TTAG_GSUB);
  906. error = HB_Err_Not_Covered;
  907. if (!stream || (error = HB_Load_GSUB_Table(stream, &face->gsub, face->gdef, gdefStream))) {
  908. face->gsub = 0;
  909. if (error != HB_Err_Not_Covered) {
  910. //DEBUG("error loading gsub table: %d", error);
  911. } else {
  912. //DEBUG("face doesn't have a gsub table");
  913. }
  914. }
  915. _hb_close_stream(stream);
  916. stream = getTableStream(font, tableFunc, TTAG_GPOS);
  917. error = HB_Err_Not_Covered;
  918. if (!stream || (error = HB_Load_GPOS_Table(stream, &face->gpos, face->gdef, gdefStream))) {
  919. face->gpos = 0;
  920. DEBUG("error loading gpos table: %d", error);
  921. }
  922. _hb_close_stream(stream);
  923. _hb_close_stream(gdefStream);
  924. for (unsigned int i = 0; i < HB_ScriptCount; ++i)
  925. face->supported_scripts[i] = checkScript(face, i);
  926. if (hb_buffer_new(&face->buffer) != HB_Err_Ok) {
  927. HB_FreeFace(face);
  928. return 0;
  929. }
  930. return face;
  931. }
  932. void HB_FreeFace(HB_Face face)
  933. {
  934. if (!face)
  935. return;
  936. if (face->gpos)
  937. HB_Done_GPOS_Table(face->gpos);
  938. if (face->gsub)
  939. HB_Done_GSUB_Table(face->gsub);
  940. if (face->gdef)
  941. HB_Done_GDEF_Table(face->gdef);
  942. if (face->buffer)
  943. hb_buffer_free(face->buffer);
  944. if (face->tmpAttributes)
  945. free(face->tmpAttributes);
  946. if (face->tmpLogClusters)
  947. free(face->tmpLogClusters);
  948. free(face);
  949. }
  950. HB_Bool HB_SelectScript(HB_ShaperItem *shaper_item, const HB_OpenTypeFeature *features)
  951. {
  952. HB_Script script = shaper_item->item.script;
  953. if (!shaper_item->face->supported_scripts[script])
  954. return false;
  955. HB_Face face = shaper_item->face;
  956. if (face->current_script == script && face->current_flags == shaper_item->shaperFlags)
  957. return true;
  958. face->current_script = script;
  959. face->current_flags = shaper_item->shaperFlags;
  960. assert(script < HB_ScriptCount);
  961. // find script in our list of supported scripts.
  962. unsigned int tag = ot_scripts[script].tag;
  963. if (face->gsub && features) {
  964. #ifdef OT_DEBUG
  965. {
  966. HB_FeatureList featurelist = face->gsub->FeatureList;
  967. int numfeatures = featurelist.FeatureCount;
  968. DEBUG("gsub table has %d features", numfeatures);
  969. for (int i = 0; i < numfeatures; i++) {
  970. HB_FeatureRecord *r = featurelist.FeatureRecord + i;
  971. DEBUG(" feature '%s'", tag_to_string(r->FeatureTag));
  972. }
  973. }
  974. #endif
  975. HB_GSUB_Clear_Features(face->gsub);
  976. HB_UShort script_index;
  977. HB_Error error = HB_GSUB_Select_Script(face->gsub, tag, &script_index);
  978. if (!error) {
  979. DEBUG("script %s has script index %d", tag_to_string(script), script_index);
  980. while (features->tag) {
  981. HB_UShort feature_index;
  982. error = HB_GSUB_Select_Feature(face->gsub, features->tag, script_index, 0xffff, &feature_index);
  983. if (!error) {
  984. DEBUG(" adding feature %s", tag_to_string(features->tag));
  985. HB_GSUB_Add_Feature(face->gsub, feature_index, features->property);
  986. }
  987. ++features;
  988. }
  989. }
  990. }
  991. // reset
  992. face->has_opentype_kerning = false;
  993. if (face->gpos) {
  994. HB_GPOS_Clear_Features(face->gpos);
  995. HB_UShort script_index;
  996. HB_Error error = HB_GPOS_Select_Script(face->gpos, tag, &script_index);
  997. if (!error) {
  998. #ifdef OT_DEBUG
  999. {
  1000. HB_FeatureList featurelist = face->gpos->FeatureList;
  1001. int numfeatures = featurelist.FeatureCount;
  1002. DEBUG("gpos table has %d features", numfeatures);
  1003. for(int i = 0; i < numfeatures; i++) {
  1004. HB_FeatureRecord *r = featurelist.FeatureRecord + i;
  1005. HB_UShort feature_index;
  1006. HB_GPOS_Select_Feature(face->gpos, r->FeatureTag, script_index, 0xffff, &feature_index);
  1007. DEBUG(" feature '%s'", tag_to_string(r->FeatureTag));
  1008. }
  1009. }
  1010. #endif
  1011. HB_UInt *feature_tag_list_buffer;
  1012. error = HB_GPOS_Query_Features(face->gpos, script_index, 0xffff, &feature_tag_list_buffer);
  1013. if (!error) {
  1014. HB_UInt *feature_tag_list = feature_tag_list_buffer;
  1015. while (*feature_tag_list) {
  1016. HB_UShort feature_index;
  1017. if (*feature_tag_list == HB_MAKE_TAG('k', 'e', 'r', 'n')) {
  1018. if (face->current_flags & HB_ShaperFlag_NoKerning) {
  1019. ++feature_tag_list;
  1020. continue;
  1021. }
  1022. face->has_opentype_kerning = true;
  1023. }
  1024. error = HB_GPOS_Select_Feature(face->gpos, *feature_tag_list, script_index, 0xffff, &feature_index);
  1025. if (!error)
  1026. HB_GPOS_Add_Feature(face->gpos, feature_index, PositioningProperties);
  1027. ++feature_tag_list;
  1028. }
  1029. FREE(feature_tag_list_buffer);
  1030. }
  1031. }
  1032. }
  1033. return true;
  1034. }
  1035. HB_Bool HB_OpenTypeShape(HB_ShaperItem *item, const hb_uint32 *properties)
  1036. {
  1037. HB_GlyphAttributes *tmpAttributes;
  1038. unsigned int *tmpLogClusters;
  1039. HB_Face face = item->face;
  1040. face->length = item->num_glyphs;
  1041. hb_buffer_clear(face->buffer);
  1042. tmpAttributes = (HB_GlyphAttributes *) realloc(face->tmpAttributes, face->length*sizeof(HB_GlyphAttributes));
  1043. if (!tmpAttributes)
  1044. return false;
  1045. face->tmpAttributes = tmpAttributes;
  1046. tmpLogClusters = (unsigned int *) realloc(face->tmpLogClusters, face->length*sizeof(unsigned int));
  1047. if (!tmpLogClusters)
  1048. return false;
  1049. face->tmpLogClusters = tmpLogClusters;
  1050. for (int i = 0; i < face->length; ++i) {
  1051. hb_buffer_add_glyph(face->buffer, item->glyphs[i], properties ? properties[i] : 0, i);
  1052. face->tmpAttributes[i] = item->attributes[i];
  1053. face->tmpLogClusters[i] = item->log_clusters[i];
  1054. }
  1055. #ifdef OT_DEBUG
  1056. DEBUG("-----------------------------------------");
  1057. // DEBUG("log clusters before shaping:");
  1058. // for (int j = 0; j < length; j++)
  1059. // DEBUG(" log[%d] = %d", j, item->log_clusters[j]);
  1060. DEBUG("original glyphs: %p", item->glyphs);
  1061. for (int i = 0; i < length; ++i)
  1062. DEBUG(" glyph=%4x", hb_buffer->in_string[i].gindex);
  1063. // dump_string(hb_buffer);
  1064. #endif
  1065. face->glyphs_substituted = false;
  1066. if (face->gsub) {
  1067. unsigned int error = HB_GSUB_Apply_String(face->gsub, face->buffer);
  1068. if (error && error != HB_Err_Not_Covered)
  1069. return false;
  1070. face->glyphs_substituted = (error != HB_Err_Not_Covered);
  1071. }
  1072. #ifdef OT_DEBUG
  1073. // DEBUG("log clusters before shaping:");
  1074. // for (int j = 0; j < length; j++)
  1075. // DEBUG(" log[%d] = %d", j, item->log_clusters[j]);
  1076. DEBUG("shaped glyphs:");
  1077. for (int i = 0; i < length; ++i)
  1078. DEBUG(" glyph=%4x", hb_buffer->in_string[i].gindex);
  1079. DEBUG("-----------------------------------------");
  1080. // dump_string(hb_buffer);
  1081. #endif
  1082. return true;
  1083. }
  1084. HB_Bool HB_OpenTypePosition(HB_ShaperItem *item, int availableGlyphs, HB_Bool doLogClusters)
  1085. {
  1086. HB_Face face = item->face;
  1087. bool glyphs_positioned = false;
  1088. if (face->gpos) {
  1089. if (face->buffer->positions)
  1090. memset(face->buffer->positions, 0, face->buffer->in_length*sizeof(HB_PositionRec));
  1091. // #### check that passing "false,false" is correct
  1092. glyphs_positioned = HB_GPOS_Apply_String(item->font, face->gpos, face->current_flags, face->buffer, false, false) != HB_Err_Not_Covered;
  1093. }
  1094. if (!face->glyphs_substituted && !glyphs_positioned) {
  1095. HB_GetGlyphAdvances(item);
  1096. return true; // nothing to do for us
  1097. }
  1098. // make sure we have enough space to write everything back
  1099. if (availableGlyphs < (int)face->buffer->in_length) {
  1100. item->num_glyphs = face->buffer->in_length;
  1101. return false;
  1102. }
  1103. HB_Glyph *glyphs = item->glyphs;
  1104. HB_GlyphAttributes *attributes = item->attributes;
  1105. for (unsigned int i = 0; i < face->buffer->in_length; ++i) {
  1106. glyphs[i] = face->buffer->in_string[i].gindex;
  1107. attributes[i] = face->tmpAttributes[face->buffer->in_string[i].cluster];
  1108. if (i && face->buffer->in_string[i].cluster == face->buffer->in_string[i-1].cluster)
  1109. attributes[i].clusterStart = false;
  1110. }
  1111. item->num_glyphs = face->buffer->in_length;
  1112. if (doLogClusters && face->glyphs_substituted) {
  1113. // we can't do this for indic, as we pass the stuf in syllables and it's easier to do it in the shaper.
  1114. unsigned short *logClusters = item->log_clusters;
  1115. int clusterStart = 0;
  1116. int oldCi = 0;
  1117. // #### the reconstruction of the logclusters currently does not work if the original string
  1118. // contains surrogate pairs
  1119. for (unsigned int i = 0; i < face->buffer->in_length; ++i) {
  1120. int ci = face->buffer->in_string[i].cluster;
  1121. // DEBUG(" ci[%d] = %d mark=%d, cmb=%d, cs=%d",
  1122. // i, ci, glyphAttributes[i].mark, glyphAttributes[i].combiningClass, glyphAttributes[i].clusterStart);
  1123. if (!attributes[i].mark && attributes[i].clusterStart && ci != oldCi) {
  1124. for (int j = oldCi; j < ci; j++)
  1125. logClusters[j] = clusterStart;
  1126. clusterStart = i;
  1127. oldCi = ci;
  1128. }
  1129. }
  1130. for (int j = oldCi; j < face->length; j++)
  1131. logClusters[j] = clusterStart;
  1132. }
  1133. // calulate the advances for the shaped glyphs
  1134. // DEBUG("unpositioned: ");
  1135. // positioning code:
  1136. if (glyphs_positioned) {
  1137. HB_GetGlyphAdvances(item);
  1138. HB_Position positions = face->buffer->positions;
  1139. HB_Fixed *advances = item->advances;
  1140. // DEBUG("positioned glyphs:");
  1141. for (unsigned int i = 0; i < face->buffer->in_length; i++) {
  1142. // DEBUG(" %d:\t orig advance: (%d/%d)\tadv=(%d/%d)\tpos=(%d/%d)\tback=%d\tnew_advance=%d", i,
  1143. // glyphs[i].advance.x.toInt(), glyphs[i].advance.y.toInt(),
  1144. // (int)(positions[i].x_advance >> 6), (int)(positions[i].y_advance >> 6),
  1145. // (int)(positions[i].x_pos >> 6), (int)(positions[i].y_pos >> 6),
  1146. // positions[i].back, positions[i].new_advance);
  1147. HB_Fixed adjustment = positions[i].x_advance;
  1148. if (!(face->current_flags & HB_ShaperFlag_UseDesignMetrics))
  1149. adjustment = HB_FIXED_ROUND(adjustment);
  1150. if (positions[i].new_advance) {
  1151. advances[i] = adjustment;
  1152. } else {
  1153. advances[i] += adjustment;
  1154. }
  1155. int back = 0;
  1156. HB_FixedPoint *offsets = item->offsets;
  1157. offsets[i].x = positions[i].x_pos;
  1158. offsets[i].y = positions[i].y_pos;
  1159. while (positions[i - back].back) {
  1160. back += positions[i - back].back;
  1161. offsets[i].x += positions[i - back].x_pos;
  1162. offsets[i].y += positions[i - back].y_pos;
  1163. }
  1164. offsets[i].y = -offsets[i].y;
  1165. if (item->item.bidiLevel % 2) {
  1166. // ### may need to go back multiple glyphs like in ltr
  1167. back = positions[i].back;
  1168. while (back--)
  1169. offsets[i].x -= advances[i-back];
  1170. } else {
  1171. back = 0;
  1172. while (positions[i - back].back) {
  1173. back += positions[i - back].back;
  1174. offsets[i].x -= advances[i-back];
  1175. }
  1176. }
  1177. // DEBUG(" ->\tadv=%d\tpos=(%d/%d)",
  1178. // glyphs[i].advance.x.toInt(), glyphs[i].offset.x.toInt(), gl…

Large files files are truncated, but you can click here to view the full file