PageRenderTime 74ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp

https://bitbucket.org/ultra_iter/qt-vtl
C++ | 1387 lines | 1050 code | 140 blank | 197 comment | 308 complexity | 3d0118d60cae177c6fd4ee94b036eb59 MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-3.0, BSD-3-Clause, CC0-1.0, CC-BY-SA-4.0, LGPL-2.1, GPL-3.0, Apache-2.0

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

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