PageRenderTime 50ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh

https://bitbucket.org/ehsan/broken-inbound
C++ Header | 1414 lines | 1056 code | 240 blank | 118 comment | 164 complexity | 9064ac20cb9a075d06c9cf9d8d96e910 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-3.0, AGPL-1.0, MIT, LGPL-2.1, 0BSD, BSD-2-Clause, MPL-2.0, BSD-3-Clause, Apache-2.0, GPL-2.0, JSON
  1. /*
  2. * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
  3. * Copyright © 2010,2012 Google, Inc.
  4. *
  5. * This is part of HarfBuzz, a text shaping library.
  6. *
  7. * Permission is hereby granted, without written agreement and without
  8. * license or royalty fees, to use, copy, modify, and distribute this
  9. * software and its documentation for any purpose, provided that the
  10. * above copyright notice and the following two paragraphs appear in
  11. * all copies of this software.
  12. *
  13. * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  14. * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  15. * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
  16. * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  17. * DAMAGE.
  18. *
  19. * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  20. * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  21. * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
  22. * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  23. * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  24. *
  25. * Red Hat Author(s): Behdad Esfahbod
  26. * Google Author(s): Behdad Esfahbod
  27. */
  28. #ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
  29. #define HB_OT_LAYOUT_GSUB_TABLE_HH
  30. #include "hb-ot-layout-gsubgpos-private.hh"
  31. struct SingleSubstFormat1
  32. {
  33. friend struct SingleSubst;
  34. private:
  35. inline void closure (hb_closure_context_t *c) const
  36. {
  37. TRACE_CLOSURE ();
  38. Coverage::Iter iter;
  39. for (iter.init (this+coverage); iter.more (); iter.next ()) {
  40. hb_codepoint_t glyph_id = iter.get_glyph ();
  41. if (c->glyphs->has (glyph_id))
  42. c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF);
  43. }
  44. }
  45. inline const Coverage &get_coverage (void) const
  46. {
  47. return this+coverage;
  48. }
  49. inline bool apply (hb_apply_context_t *c) const
  50. {
  51. TRACE_APPLY ();
  52. hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
  53. unsigned int index = (this+coverage) (glyph_id);
  54. if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
  55. /* According to the Adobe Annotated OpenType Suite, result is always
  56. * limited to 16bit. */
  57. glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF;
  58. c->replace_glyph (glyph_id);
  59. return TRACE_RETURN (true);
  60. }
  61. inline bool sanitize (hb_sanitize_context_t *c) {
  62. TRACE_SANITIZE ();
  63. return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
  64. }
  65. protected:
  66. USHORT format; /* Format identifier--format = 1 */
  67. OffsetTo<Coverage>
  68. coverage; /* Offset to Coverage table--from
  69. * beginning of Substitution table */
  70. SHORT deltaGlyphID; /* Add to original GlyphID to get
  71. * substitute GlyphID */
  72. public:
  73. DEFINE_SIZE_STATIC (6);
  74. };
  75. struct SingleSubstFormat2
  76. {
  77. friend struct SingleSubst;
  78. private:
  79. inline void closure (hb_closure_context_t *c) const
  80. {
  81. TRACE_CLOSURE ();
  82. Coverage::Iter iter;
  83. for (iter.init (this+coverage); iter.more (); iter.next ()) {
  84. if (c->glyphs->has (iter.get_glyph ()))
  85. c->glyphs->add (substitute[iter.get_coverage ()]);
  86. }
  87. }
  88. inline const Coverage &get_coverage (void) const
  89. {
  90. return this+coverage;
  91. }
  92. inline bool apply (hb_apply_context_t *c) const
  93. {
  94. TRACE_APPLY ();
  95. hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
  96. unsigned int index = (this+coverage) (glyph_id);
  97. if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
  98. if (unlikely (index >= substitute.len)) return TRACE_RETURN (false);
  99. glyph_id = substitute[index];
  100. c->replace_glyph (glyph_id);
  101. return TRACE_RETURN (true);
  102. }
  103. inline bool sanitize (hb_sanitize_context_t *c) {
  104. TRACE_SANITIZE ();
  105. return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
  106. }
  107. protected:
  108. USHORT format; /* Format identifier--format = 2 */
  109. OffsetTo<Coverage>
  110. coverage; /* Offset to Coverage table--from
  111. * beginning of Substitution table */
  112. ArrayOf<GlyphID>
  113. substitute; /* Array of substitute
  114. * GlyphIDs--ordered by Coverage Index */
  115. public:
  116. DEFINE_SIZE_ARRAY (6, substitute);
  117. };
  118. struct SingleSubst
  119. {
  120. friend struct SubstLookupSubTable;
  121. private:
  122. inline void closure (hb_closure_context_t *c) const
  123. {
  124. TRACE_CLOSURE ();
  125. switch (u.format) {
  126. case 1: u.format1.closure (c); break;
  127. case 2: u.format2.closure (c); break;
  128. default: break;
  129. }
  130. }
  131. inline const Coverage &get_coverage (void) const
  132. {
  133. switch (u.format) {
  134. case 1: return u.format1.get_coverage ();
  135. case 2: return u.format2.get_coverage ();
  136. default:return Null(Coverage);
  137. }
  138. }
  139. inline bool apply (hb_apply_context_t *c) const
  140. {
  141. TRACE_APPLY ();
  142. switch (u.format) {
  143. case 1: return TRACE_RETURN (u.format1.apply (c));
  144. case 2: return TRACE_RETURN (u.format2.apply (c));
  145. default:return TRACE_RETURN (false);
  146. }
  147. }
  148. inline bool sanitize (hb_sanitize_context_t *c) {
  149. TRACE_SANITIZE ();
  150. if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  151. switch (u.format) {
  152. case 1: return TRACE_RETURN (u.format1.sanitize (c));
  153. case 2: return TRACE_RETURN (u.format2.sanitize (c));
  154. default:return TRACE_RETURN (true);
  155. }
  156. }
  157. protected:
  158. union {
  159. USHORT format; /* Format identifier */
  160. SingleSubstFormat1 format1;
  161. SingleSubstFormat2 format2;
  162. } u;
  163. };
  164. struct Sequence
  165. {
  166. friend struct MultipleSubstFormat1;
  167. private:
  168. inline void closure (hb_closure_context_t *c) const
  169. {
  170. TRACE_CLOSURE ();
  171. unsigned int count = substitute.len;
  172. for (unsigned int i = 0; i < count; i++)
  173. c->glyphs->add (substitute[i]);
  174. }
  175. inline bool apply (hb_apply_context_t *c) const
  176. {
  177. TRACE_APPLY ();
  178. if (unlikely (!substitute.len)) return TRACE_RETURN (false);
  179. unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE ? HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH : 0;
  180. unsigned int count = substitute.len;
  181. for (unsigned int i = 0; i < count; i++) {
  182. set_lig_props_for_component (c->buffer->cur(), i);
  183. c->output_glyph (substitute.array[i], klass);
  184. }
  185. c->buffer->skip_glyph ();
  186. return TRACE_RETURN (true);
  187. }
  188. public:
  189. inline bool sanitize (hb_sanitize_context_t *c) {
  190. TRACE_SANITIZE ();
  191. return TRACE_RETURN (substitute.sanitize (c));
  192. }
  193. protected:
  194. ArrayOf<GlyphID>
  195. substitute; /* String of GlyphIDs to substitute */
  196. public:
  197. DEFINE_SIZE_ARRAY (2, substitute);
  198. };
  199. struct MultipleSubstFormat1
  200. {
  201. friend struct MultipleSubst;
  202. private:
  203. inline void closure (hb_closure_context_t *c) const
  204. {
  205. TRACE_CLOSURE ();
  206. Coverage::Iter iter;
  207. for (iter.init (this+coverage); iter.more (); iter.next ()) {
  208. if (c->glyphs->has (iter.get_glyph ()))
  209. (this+sequence[iter.get_coverage ()]).closure (c);
  210. }
  211. }
  212. inline const Coverage &get_coverage (void) const
  213. {
  214. return this+coverage;
  215. }
  216. inline bool apply (hb_apply_context_t *c) const
  217. {
  218. TRACE_APPLY ();
  219. unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
  220. if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
  221. return TRACE_RETURN ((this+sequence[index]).apply (c));
  222. }
  223. inline bool sanitize (hb_sanitize_context_t *c) {
  224. TRACE_SANITIZE ();
  225. return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
  226. }
  227. protected:
  228. USHORT format; /* Format identifier--format = 1 */
  229. OffsetTo<Coverage>
  230. coverage; /* Offset to Coverage table--from
  231. * beginning of Substitution table */
  232. OffsetArrayOf<Sequence>
  233. sequence; /* Array of Sequence tables
  234. * ordered by Coverage Index */
  235. public:
  236. DEFINE_SIZE_ARRAY (6, sequence);
  237. };
  238. struct MultipleSubst
  239. {
  240. friend struct SubstLookupSubTable;
  241. private:
  242. inline void closure (hb_closure_context_t *c) const
  243. {
  244. TRACE_CLOSURE ();
  245. switch (u.format) {
  246. case 1: u.format1.closure (c); break;
  247. default: break;
  248. }
  249. }
  250. inline const Coverage &get_coverage (void) const
  251. {
  252. switch (u.format) {
  253. case 1: return u.format1.get_coverage ();
  254. default:return Null(Coverage);
  255. }
  256. }
  257. inline bool apply (hb_apply_context_t *c) const
  258. {
  259. TRACE_APPLY ();
  260. switch (u.format) {
  261. case 1: return TRACE_RETURN (u.format1.apply (c));
  262. default:return TRACE_RETURN (false);
  263. }
  264. }
  265. inline bool sanitize (hb_sanitize_context_t *c) {
  266. TRACE_SANITIZE ();
  267. if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  268. switch (u.format) {
  269. case 1: return TRACE_RETURN (u.format1.sanitize (c));
  270. default:return TRACE_RETURN (true);
  271. }
  272. }
  273. protected:
  274. union {
  275. USHORT format; /* Format identifier */
  276. MultipleSubstFormat1 format1;
  277. } u;
  278. };
  279. typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
  280. * arbitrary order */
  281. struct AlternateSubstFormat1
  282. {
  283. friend struct AlternateSubst;
  284. private:
  285. inline void closure (hb_closure_context_t *c) const
  286. {
  287. TRACE_CLOSURE ();
  288. Coverage::Iter iter;
  289. for (iter.init (this+coverage); iter.more (); iter.next ()) {
  290. if (c->glyphs->has (iter.get_glyph ())) {
  291. const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
  292. unsigned int count = alt_set.len;
  293. for (unsigned int i = 0; i < count; i++)
  294. c->glyphs->add (alt_set[i]);
  295. }
  296. }
  297. }
  298. inline const Coverage &get_coverage (void) const
  299. {
  300. return this+coverage;
  301. }
  302. inline bool apply (hb_apply_context_t *c) const
  303. {
  304. TRACE_APPLY ();
  305. hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
  306. unsigned int index = (this+coverage) (glyph_id);
  307. if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
  308. const AlternateSet &alt_set = this+alternateSet[index];
  309. if (unlikely (!alt_set.len)) return TRACE_RETURN (false);
  310. hb_mask_t glyph_mask = c->buffer->cur().mask;
  311. hb_mask_t lookup_mask = c->lookup_mask;
  312. /* Note: This breaks badly if two features enabled this lookup together. */
  313. unsigned int shift = _hb_ctz (lookup_mask);
  314. unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
  315. if (unlikely (alt_index > alt_set.len || alt_index == 0)) return TRACE_RETURN (false);
  316. glyph_id = alt_set[alt_index - 1];
  317. c->replace_glyph (glyph_id);
  318. return TRACE_RETURN (true);
  319. }
  320. inline bool sanitize (hb_sanitize_context_t *c) {
  321. TRACE_SANITIZE ();
  322. return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
  323. }
  324. protected:
  325. USHORT format; /* Format identifier--format = 1 */
  326. OffsetTo<Coverage>
  327. coverage; /* Offset to Coverage table--from
  328. * beginning of Substitution table */
  329. OffsetArrayOf<AlternateSet>
  330. alternateSet; /* Array of AlternateSet tables
  331. * ordered by Coverage Index */
  332. public:
  333. DEFINE_SIZE_ARRAY (6, alternateSet);
  334. };
  335. struct AlternateSubst
  336. {
  337. friend struct SubstLookupSubTable;
  338. private:
  339. inline void closure (hb_closure_context_t *c) const
  340. {
  341. TRACE_CLOSURE ();
  342. switch (u.format) {
  343. case 1: u.format1.closure (c); break;
  344. default: break;
  345. }
  346. }
  347. inline const Coverage &get_coverage (void) const
  348. {
  349. switch (u.format) {
  350. case 1: return u.format1.get_coverage ();
  351. default:return Null(Coverage);
  352. }
  353. }
  354. inline bool apply (hb_apply_context_t *c) const
  355. {
  356. TRACE_APPLY ();
  357. switch (u.format) {
  358. case 1: return TRACE_RETURN (u.format1.apply (c));
  359. default:return TRACE_RETURN (false);
  360. }
  361. }
  362. inline bool sanitize (hb_sanitize_context_t *c) {
  363. TRACE_SANITIZE ();
  364. if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  365. switch (u.format) {
  366. case 1: return TRACE_RETURN (u.format1.sanitize (c));
  367. default:return TRACE_RETURN (true);
  368. }
  369. }
  370. protected:
  371. union {
  372. USHORT format; /* Format identifier */
  373. AlternateSubstFormat1 format1;
  374. } u;
  375. };
  376. struct Ligature
  377. {
  378. friend struct LigatureSet;
  379. private:
  380. inline void closure (hb_closure_context_t *c) const
  381. {
  382. TRACE_CLOSURE ();
  383. unsigned int count = component.len;
  384. for (unsigned int i = 1; i < count; i++)
  385. if (!c->glyphs->has (component[i]))
  386. return;
  387. c->glyphs->add (ligGlyph);
  388. }
  389. inline bool would_apply (hb_would_apply_context_t *c) const
  390. {
  391. if (c->len != component.len)
  392. return false;
  393. for (unsigned int i = 1; i < c->len; i++)
  394. if (likely (c->glyphs[i] != component[i]))
  395. return false;
  396. return true;
  397. }
  398. inline bool apply (hb_apply_context_t *c) const
  399. {
  400. TRACE_APPLY ();
  401. unsigned int count = component.len;
  402. if (unlikely (count < 1)) return TRACE_RETURN (false);
  403. hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
  404. if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
  405. /*
  406. * This is perhaps the trickiest part of GSUB... Remarks:
  407. *
  408. * - If all components of the ligature were marks, we call this a mark ligature.
  409. *
  410. * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
  411. * it as a ligature glyph. Though, really, this will not really be used...
  412. *
  413. * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
  414. * the ligature to keep its old ligature id. This will allow it to attach to
  415. * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
  416. * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
  417. * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
  418. * later, we don't want them to lose their ligature id/component, otherwise
  419. * GPOS will fail to correctly position the mark ligature on top of the
  420. * LAM,LAM,HEH ligature. See:
  421. * https://bugzilla.gnome.org/show_bug.cgi?id=676343
  422. *
  423. * - If a ligature is formed of components that some of which are also ligatures
  424. * themselves, and those ligature components had marks attached to *their*
  425. * components, we have to attach the marks to the new ligature component
  426. * positions! Now *that*'s tricky! And these marks may be following the
  427. * last component of the whole sequence, so we should loop forward looking
  428. * for them and update them.
  429. *
  430. * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
  431. * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
  432. * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
  433. * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
  434. * the new ligature with a component value of 2.
  435. *
  436. * This in fact happened to a font... See:
  437. * https://bugzilla.gnome.org/show_bug.cgi?id=437633
  438. *
  439. * - Ligatures cannot be formed across glyphs attached to different components
  440. * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
  441. * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
  442. * However, it would be wrong to ligate that SHADDA,FATHA sequence.o
  443. * There is an exception to this: If a ligature tries ligating with marks that
  444. * belong to it itself, go ahead, assuming that the font designer knows what
  445. * they are doing (otherwise it can break Indic stuff when a matra wants to
  446. * ligate with a conjunct...)
  447. */
  448. bool is_mark_ligature = !!(c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
  449. unsigned int total_component_count = 0;
  450. total_component_count += get_lig_num_comps (c->buffer->cur());
  451. unsigned int first_lig_id = get_lig_id (c->buffer->cur());
  452. unsigned int first_lig_comp = get_lig_comp (c->buffer->cur());
  453. for (unsigned int i = 1; i < count; i++)
  454. {
  455. unsigned int property;
  456. if (!skippy_iter.next (&property)) return TRACE_RETURN (false);
  457. if (likely (c->buffer->info[skippy_iter.idx].codepoint != component[i])) return TRACE_RETURN (false);
  458. unsigned int this_lig_id = get_lig_id (c->buffer->info[skippy_iter.idx]);
  459. unsigned int this_lig_comp = get_lig_comp (c->buffer->info[skippy_iter.idx]);
  460. if (first_lig_id && first_lig_comp) {
  461. /* If first component was attached to a previous ligature component,
  462. * all subsequent components should be attached to the same ligature
  463. * component, otherwise we shouldn't ligate them. */
  464. if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
  465. return TRACE_RETURN (false);
  466. } else {
  467. /* If first component was NOT attached to a previous ligature component,
  468. * all subsequent components should also NOT be attached to any ligature
  469. * component, unless they are attached to the first component itself! */
  470. if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
  471. return TRACE_RETURN (false);
  472. }
  473. is_mark_ligature = is_mark_ligature && (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
  474. total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]);
  475. }
  476. /* Deal, we are forming the ligature. */
  477. c->buffer->merge_clusters (c->buffer->idx, skippy_iter.idx + 1);
  478. unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
  479. unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (c->buffer);
  480. unsigned int last_lig_id = get_lig_id (c->buffer->cur());
  481. unsigned int last_num_components = get_lig_num_comps (c->buffer->cur());
  482. unsigned int components_so_far = last_num_components;
  483. if (!is_mark_ligature)
  484. set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count);
  485. c->replace_glyph (ligGlyph, klass);
  486. for (unsigned int i = 1; i < count; i++)
  487. {
  488. while (c->should_mark_skip_current_glyph ())
  489. {
  490. if (!is_mark_ligature) {
  491. unsigned int new_lig_comp = components_so_far - last_num_components +
  492. MIN (MAX (get_lig_comp (c->buffer->cur()), 1u), last_num_components);
  493. set_lig_props_for_mark (c->buffer->cur(), lig_id, new_lig_comp);
  494. }
  495. c->buffer->next_glyph ();
  496. }
  497. last_lig_id = get_lig_id (c->buffer->cur());
  498. last_num_components = get_lig_num_comps (c->buffer->cur());
  499. components_so_far += last_num_components;
  500. /* Skip the base glyph */
  501. c->buffer->idx++;
  502. }
  503. if (!is_mark_ligature && last_lig_id) {
  504. /* Re-adjust components for any marks following. */
  505. for (unsigned int i = c->buffer->idx; i < c->buffer->len; i++) {
  506. if (last_lig_id == get_lig_id (c->buffer->info[i])) {
  507. unsigned int new_lig_comp = components_so_far - last_num_components +
  508. MIN (MAX (get_lig_comp (c->buffer->info[i]), 1u), last_num_components);
  509. set_lig_props_for_mark (c->buffer->info[i], lig_id, new_lig_comp);
  510. } else
  511. break;
  512. }
  513. }
  514. return TRACE_RETURN (true);
  515. }
  516. public:
  517. inline bool sanitize (hb_sanitize_context_t *c) {
  518. TRACE_SANITIZE ();
  519. return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
  520. }
  521. protected:
  522. GlyphID ligGlyph; /* GlyphID of ligature to substitute */
  523. HeadlessArrayOf<GlyphID>
  524. component; /* Array of component GlyphIDs--start
  525. * with the second component--ordered
  526. * in writing direction */
  527. public:
  528. DEFINE_SIZE_ARRAY (4, component);
  529. };
  530. struct LigatureSet
  531. {
  532. friend struct LigatureSubstFormat1;
  533. private:
  534. inline void closure (hb_closure_context_t *c) const
  535. {
  536. TRACE_CLOSURE ();
  537. unsigned int num_ligs = ligature.len;
  538. for (unsigned int i = 0; i < num_ligs; i++)
  539. (this+ligature[i]).closure (c);
  540. }
  541. inline bool would_apply (hb_would_apply_context_t *c) const
  542. {
  543. unsigned int num_ligs = ligature.len;
  544. for (unsigned int i = 0; i < num_ligs; i++)
  545. {
  546. const Ligature &lig = this+ligature[i];
  547. if (lig.would_apply (c))
  548. return true;
  549. }
  550. return false;
  551. }
  552. inline bool apply (hb_apply_context_t *c) const
  553. {
  554. TRACE_APPLY ();
  555. unsigned int num_ligs = ligature.len;
  556. for (unsigned int i = 0; i < num_ligs; i++)
  557. {
  558. const Ligature &lig = this+ligature[i];
  559. if (lig.apply (c)) return TRACE_RETURN (true);
  560. }
  561. return TRACE_RETURN (false);
  562. }
  563. public:
  564. inline bool sanitize (hb_sanitize_context_t *c) {
  565. TRACE_SANITIZE ();
  566. return TRACE_RETURN (ligature.sanitize (c, this));
  567. }
  568. protected:
  569. OffsetArrayOf<Ligature>
  570. ligature; /* Array LigatureSet tables
  571. * ordered by preference */
  572. public:
  573. DEFINE_SIZE_ARRAY (2, ligature);
  574. };
  575. struct LigatureSubstFormat1
  576. {
  577. friend struct LigatureSubst;
  578. private:
  579. inline void closure (hb_closure_context_t *c) const
  580. {
  581. TRACE_CLOSURE ();
  582. Coverage::Iter iter;
  583. for (iter.init (this+coverage); iter.more (); iter.next ()) {
  584. if (c->glyphs->has (iter.get_glyph ()))
  585. (this+ligatureSet[iter.get_coverage ()]).closure (c);
  586. }
  587. }
  588. inline const Coverage &get_coverage (void) const
  589. {
  590. return this+coverage;
  591. }
  592. inline bool would_apply (hb_would_apply_context_t *c) const
  593. {
  594. return (this+ligatureSet[(this+coverage) (c->glyphs[0])]).would_apply (c);
  595. }
  596. inline bool apply (hb_apply_context_t *c) const
  597. {
  598. TRACE_APPLY ();
  599. hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
  600. unsigned int index = (this+coverage) (glyph_id);
  601. if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
  602. const LigatureSet &lig_set = this+ligatureSet[index];
  603. return TRACE_RETURN (lig_set.apply (c));
  604. }
  605. inline bool sanitize (hb_sanitize_context_t *c) {
  606. TRACE_SANITIZE ();
  607. return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
  608. }
  609. protected:
  610. USHORT format; /* Format identifier--format = 1 */
  611. OffsetTo<Coverage>
  612. coverage; /* Offset to Coverage table--from
  613. * beginning of Substitution table */
  614. OffsetArrayOf<LigatureSet>
  615. ligatureSet; /* Array LigatureSet tables
  616. * ordered by Coverage Index */
  617. public:
  618. DEFINE_SIZE_ARRAY (6, ligatureSet);
  619. };
  620. struct LigatureSubst
  621. {
  622. friend struct SubstLookupSubTable;
  623. private:
  624. inline void closure (hb_closure_context_t *c) const
  625. {
  626. TRACE_CLOSURE ();
  627. switch (u.format) {
  628. case 1: u.format1.closure (c); break;
  629. default: break;
  630. }
  631. }
  632. inline const Coverage &get_coverage (void) const
  633. {
  634. switch (u.format) {
  635. case 1: return u.format1.get_coverage ();
  636. default:return Null(Coverage);
  637. }
  638. }
  639. inline bool would_apply (hb_would_apply_context_t *c) const
  640. {
  641. switch (u.format) {
  642. case 1: return u.format1.would_apply (c);
  643. default:return false;
  644. }
  645. }
  646. inline bool apply (hb_apply_context_t *c) const
  647. {
  648. TRACE_APPLY ();
  649. switch (u.format) {
  650. case 1: return TRACE_RETURN (u.format1.apply (c));
  651. default:return TRACE_RETURN (false);
  652. }
  653. }
  654. inline bool sanitize (hb_sanitize_context_t *c) {
  655. TRACE_SANITIZE ();
  656. if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  657. switch (u.format) {
  658. case 1: return TRACE_RETURN (u.format1.sanitize (c));
  659. default:return TRACE_RETURN (true);
  660. }
  661. }
  662. protected:
  663. union {
  664. USHORT format; /* Format identifier */
  665. LigatureSubstFormat1 format1;
  666. } u;
  667. };
  668. static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
  669. static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index);
  670. struct ContextSubst : Context
  671. {
  672. friend struct SubstLookupSubTable;
  673. private:
  674. inline void closure (hb_closure_context_t *c) const
  675. {
  676. TRACE_CLOSURE ();
  677. return Context::closure (c, closure_lookup);
  678. }
  679. inline bool apply (hb_apply_context_t *c) const
  680. {
  681. TRACE_APPLY ();
  682. return TRACE_RETURN (Context::apply (c, substitute_lookup));
  683. }
  684. };
  685. struct ChainContextSubst : ChainContext
  686. {
  687. friend struct SubstLookupSubTable;
  688. private:
  689. inline void closure (hb_closure_context_t *c) const
  690. {
  691. TRACE_CLOSURE ();
  692. return ChainContext::closure (c, closure_lookup);
  693. }
  694. inline bool apply (hb_apply_context_t *c) const
  695. {
  696. TRACE_APPLY ();
  697. return TRACE_RETURN (ChainContext::apply (c, substitute_lookup));
  698. }
  699. };
  700. struct ExtensionSubst : Extension
  701. {
  702. friend struct SubstLookupSubTable;
  703. friend struct SubstLookup;
  704. private:
  705. inline const struct SubstLookupSubTable& get_subtable (void) const
  706. {
  707. unsigned int offset = get_offset ();
  708. if (unlikely (!offset)) return Null(SubstLookupSubTable);
  709. return StructAtOffset<SubstLookupSubTable> (this, offset);
  710. }
  711. inline void closure (hb_closure_context_t *c) const;
  712. inline const Coverage &get_coverage (void) const;
  713. inline bool would_apply (hb_would_apply_context_t *c) const;
  714. inline bool apply (hb_apply_context_t *c) const;
  715. inline bool sanitize (hb_sanitize_context_t *c);
  716. inline bool is_reverse (void) const;
  717. };
  718. struct ReverseChainSingleSubstFormat1
  719. {
  720. friend struct ReverseChainSingleSubst;
  721. private:
  722. inline void closure (hb_closure_context_t *c) const
  723. {
  724. TRACE_CLOSURE ();
  725. const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  726. unsigned int count;
  727. count = backtrack.len;
  728. for (unsigned int i = 0; i < count; i++)
  729. if (!(this+backtrack[i]).intersects (c->glyphs))
  730. return;
  731. count = lookahead.len;
  732. for (unsigned int i = 0; i < count; i++)
  733. if (!(this+lookahead[i]).intersects (c->glyphs))
  734. return;
  735. const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
  736. Coverage::Iter iter;
  737. for (iter.init (this+coverage); iter.more (); iter.next ()) {
  738. if (c->glyphs->has (iter.get_glyph ()))
  739. c->glyphs->add (substitute[iter.get_coverage ()]);
  740. }
  741. }
  742. inline const Coverage &get_coverage (void) const
  743. {
  744. return this+coverage;
  745. }
  746. inline bool apply (hb_apply_context_t *c) const
  747. {
  748. TRACE_APPLY ();
  749. if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
  750. return TRACE_RETURN (false); /* No chaining to this type */
  751. unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
  752. if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
  753. const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  754. const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
  755. if (match_backtrack (c,
  756. backtrack.len, (USHORT *) backtrack.array,
  757. match_coverage, this) &&
  758. match_lookahead (c,
  759. lookahead.len, (USHORT *) lookahead.array,
  760. match_coverage, this,
  761. 1))
  762. {
  763. c->replace_glyph_inplace (substitute[index]);
  764. c->buffer->idx--; /* Reverse! */
  765. return TRACE_RETURN (true);
  766. }
  767. return TRACE_RETURN (false);
  768. }
  769. inline bool sanitize (hb_sanitize_context_t *c) {
  770. TRACE_SANITIZE ();
  771. if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
  772. return TRACE_RETURN (false);
  773. OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  774. if (!lookahead.sanitize (c, this))
  775. return TRACE_RETURN (false);
  776. ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
  777. return TRACE_RETURN (substitute.sanitize (c));
  778. }
  779. protected:
  780. USHORT format; /* Format identifier--format = 1 */
  781. OffsetTo<Coverage>
  782. coverage; /* Offset to Coverage table--from
  783. * beginning of table */
  784. OffsetArrayOf<Coverage>
  785. backtrack; /* Array of coverage tables
  786. * in backtracking sequence, in glyph
  787. * sequence order */
  788. OffsetArrayOf<Coverage>
  789. lookaheadX; /* Array of coverage tables
  790. * in lookahead sequence, in glyph
  791. * sequence order */
  792. ArrayOf<GlyphID>
  793. substituteX; /* Array of substitute
  794. * GlyphIDs--ordered by Coverage Index */
  795. public:
  796. DEFINE_SIZE_MIN (10);
  797. };
  798. struct ReverseChainSingleSubst
  799. {
  800. friend struct SubstLookupSubTable;
  801. private:
  802. inline void closure (hb_closure_context_t *c) const
  803. {
  804. TRACE_CLOSURE ();
  805. switch (u.format) {
  806. case 1: u.format1.closure (c); break;
  807. default: break;
  808. }
  809. }
  810. inline const Coverage &get_coverage (void) const
  811. {
  812. switch (u.format) {
  813. case 1: return u.format1.get_coverage ();
  814. default:return Null(Coverage);
  815. }
  816. }
  817. inline bool apply (hb_apply_context_t *c) const
  818. {
  819. TRACE_APPLY ();
  820. switch (u.format) {
  821. case 1: return TRACE_RETURN (u.format1.apply (c));
  822. default:return TRACE_RETURN (false);
  823. }
  824. }
  825. inline bool sanitize (hb_sanitize_context_t *c) {
  826. TRACE_SANITIZE ();
  827. if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  828. switch (u.format) {
  829. case 1: return TRACE_RETURN (u.format1.sanitize (c));
  830. default:return TRACE_RETURN (true);
  831. }
  832. }
  833. protected:
  834. union {
  835. USHORT format; /* Format identifier */
  836. ReverseChainSingleSubstFormat1 format1;
  837. } u;
  838. };
  839. /*
  840. * SubstLookup
  841. */
  842. struct SubstLookupSubTable
  843. {
  844. friend struct SubstLookup;
  845. enum Type {
  846. Single = 1,
  847. Multiple = 2,
  848. Alternate = 3,
  849. Ligature = 4,
  850. Context = 5,
  851. ChainContext = 6,
  852. Extension = 7,
  853. ReverseChainSingle = 8
  854. };
  855. inline void closure (hb_closure_context_t *c,
  856. unsigned int lookup_type) const
  857. {
  858. TRACE_CLOSURE ();
  859. switch (lookup_type) {
  860. case Single: u.single.closure (c); break;
  861. case Multiple: u.multiple.closure (c); break;
  862. case Alternate: u.alternate.closure (c); break;
  863. case Ligature: u.ligature.closure (c); break;
  864. case Context: u.context.closure (c); break;
  865. case ChainContext: u.chainContext.closure (c); break;
  866. case Extension: u.extension.closure (c); break;
  867. case ReverseChainSingle: u.reverseChainContextSingle.closure (c); break;
  868. default: break;
  869. }
  870. }
  871. inline const Coverage &get_coverage (unsigned int lookup_type) const
  872. {
  873. switch (lookup_type) {
  874. case Single: return u.single.get_coverage ();
  875. case Multiple: return u.multiple.get_coverage ();
  876. case Alternate: return u.alternate.get_coverage ();
  877. case Ligature: return u.ligature.get_coverage ();
  878. case Context: return u.context.get_coverage ();
  879. case ChainContext: return u.chainContext.get_coverage ();
  880. case Extension: return u.extension.get_coverage ();
  881. case ReverseChainSingle: return u.reverseChainContextSingle.get_coverage ();
  882. default: return Null(Coverage);
  883. }
  884. }
  885. inline bool would_apply (hb_would_apply_context_t *c,
  886. unsigned int lookup_type) const
  887. {
  888. TRACE_WOULD_APPLY ();
  889. if (get_coverage (lookup_type).get_coverage (c->glyphs[0]) == NOT_COVERED) return false;
  890. if (c->len == 1) {
  891. switch (lookup_type) {
  892. case Single:
  893. case Multiple:
  894. case Alternate:
  895. case ReverseChainSingle:
  896. return true;
  897. }
  898. }
  899. /* Only need to look further for lookups that support substitutions
  900. * of input longer than 1. */
  901. switch (lookup_type) {
  902. case Ligature: return u.ligature.would_apply (c);
  903. case Context: return u.context.would_apply (c);
  904. case ChainContext: return u.chainContext.would_apply (c);
  905. case Extension: return u.extension.would_apply (c);
  906. default: return false;
  907. }
  908. }
  909. inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
  910. {
  911. TRACE_APPLY ();
  912. switch (lookup_type) {
  913. case Single: return TRACE_RETURN (u.single.apply (c));
  914. case Multiple: return TRACE_RETURN (u.multiple.apply (c));
  915. case Alternate: return TRACE_RETURN (u.alternate.apply (c));
  916. case Ligature: return TRACE_RETURN (u.ligature.apply (c));
  917. case Context: return TRACE_RETURN (u.context.apply (c));
  918. case ChainContext: return TRACE_RETURN (u.chainContext.apply (c));
  919. case Extension: return TRACE_RETURN (u.extension.apply (c));
  920. case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.apply (c));
  921. default: return TRACE_RETURN (false);
  922. }
  923. }
  924. inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
  925. TRACE_SANITIZE ();
  926. if (!u.header.sub_format.sanitize (c))
  927. return TRACE_RETURN (false);
  928. switch (lookup_type) {
  929. case Single: return TRACE_RETURN (u.single.sanitize (c));
  930. case Multiple: return TRACE_RETURN (u.multiple.sanitize (c));
  931. case Alternate: return TRACE_RETURN (u.alternate.sanitize (c));
  932. case Ligature: return TRACE_RETURN (u.ligature.sanitize (c));
  933. case Context: return TRACE_RETURN (u.context.sanitize (c));
  934. case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c));
  935. case Extension: return TRACE_RETURN (u.extension.sanitize (c));
  936. case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c));
  937. default: return TRACE_RETURN (true);
  938. }
  939. }
  940. protected:
  941. union {
  942. struct {
  943. USHORT sub_format;
  944. } header;
  945. SingleSubst single;
  946. MultipleSubst multiple;
  947. AlternateSubst alternate;
  948. LigatureSubst ligature;
  949. ContextSubst context;
  950. ChainContextSubst chainContext;
  951. ExtensionSubst extension;
  952. ReverseChainSingleSubst reverseChainContextSingle;
  953. } u;
  954. public:
  955. DEFINE_SIZE_UNION (2, header.sub_format);
  956. };
  957. struct SubstLookup : Lookup
  958. {
  959. inline const SubstLookupSubTable& get_subtable (unsigned int i) const
  960. { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
  961. inline static bool lookup_type_is_reverse (unsigned int lookup_type)
  962. { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
  963. inline bool is_reverse (void) const
  964. {
  965. unsigned int type = get_type ();
  966. if (unlikely (type == SubstLookupSubTable::Extension))
  967. return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
  968. return lookup_type_is_reverse (type);
  969. }
  970. inline void closure (hb_closure_context_t *c) const
  971. {
  972. unsigned int lookup_type = get_type ();
  973. unsigned int count = get_subtable_count ();
  974. for (unsigned int i = 0; i < count; i++)
  975. get_subtable (i).closure (c, lookup_type);
  976. }
  977. template <typename set_t>
  978. inline void add_coverage (set_t *glyphs) const
  979. {
  980. const Coverage *last = NULL;
  981. unsigned int count = get_subtable_count ();
  982. for (unsigned int i = 0; i < count; i++) {
  983. const Coverage *c = &get_subtable (i).get_coverage (get_type ());
  984. if (c != last) {
  985. c->add_coverage (glyphs);
  986. last = c;
  987. }
  988. }
  989. }
  990. inline bool would_apply (hb_would_apply_context_t *c) const
  991. {
  992. if (unlikely (!c->len)) return false;
  993. if (!c->digest.may_have (c->glyphs[0])) return false;
  994. unsigned int lookup_type = get_type ();
  995. unsigned int count = get_subtable_count ();
  996. for (unsigned int i = 0; i < count; i++)
  997. if (get_subtable (i).would_apply (c, lookup_type))
  998. return true;
  999. return false;
  1000. }
  1001. inline bool apply_once (hb_apply_context_t *c) const
  1002. {
  1003. unsigned int lookup_type = get_type ();
  1004. if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
  1005. return false;
  1006. unsigned int count = get_subtable_count ();
  1007. for (unsigned int i = 0; i < count; i++)
  1008. if (get_subtable (i).apply (c, lookup_type))
  1009. return true;
  1010. return false;
  1011. }
  1012. inline bool apply_string (hb_apply_context_t *c) const
  1013. {
  1014. bool ret = false;
  1015. if (unlikely (!c->buffer->len))
  1016. return false;
  1017. c->set_lookup (*this);
  1018. if (likely (!is_reverse ()))
  1019. {
  1020. /* in/out forward substitution */
  1021. c->buffer->clear_output ();
  1022. c->buffer->idx = 0;
  1023. while (c->buffer->idx < c->buffer->len)
  1024. {
  1025. if ((c->buffer->cur().mask & c->lookup_mask) &&
  1026. c->digest.may_have (c->buffer->cur().codepoint) &&
  1027. apply_once (c))
  1028. ret = true;
  1029. else
  1030. c->buffer->next_glyph ();
  1031. }
  1032. if (ret)
  1033. c->buffer->swap_buffers ();
  1034. }
  1035. else
  1036. {
  1037. /* in-place backward substitution */
  1038. c->buffer->idx = c->buffer->len - 1;
  1039. do
  1040. {
  1041. if ((c->buffer->cur().mask & c->lookup_mask) &&
  1042. c->digest.may_have (c->buffer->cur().codepoint) &&
  1043. apply_once (c))
  1044. ret = true;
  1045. else
  1046. c->buffer->idx--;
  1047. }
  1048. while ((int) c->buffer->idx >= 0);
  1049. }
  1050. return ret;
  1051. }
  1052. inline bool sanitize (hb_sanitize_context_t *c) {
  1053. TRACE_SANITIZE ();
  1054. if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
  1055. OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
  1056. if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false);
  1057. if (unlikely (get_type () == SubstLookupSubTable::Extension))
  1058. {
  1059. /* The spec says all subtables of an Extension lookup should
  1060. * have the same type. This is specially important if one has
  1061. * a reverse type!
  1062. *
  1063. * We just check that they are all either forward, or reverse. */
  1064. unsigned int type = get_subtable (0).u.extension.get_type ();
  1065. unsigned int count = get_subtable_count ();
  1066. for (unsigned int i = 1; i < count; i++)
  1067. if (get_subtable (i).u.extension.get_type () != type)
  1068. return TRACE_RETURN (false);
  1069. }
  1070. return TRACE_RETURN (true);
  1071. }
  1072. };
  1073. typedef OffsetListOf<SubstLookup> SubstLookupList;
  1074. /*
  1075. * GSUB -- The Glyph Substitution Table
  1076. */
  1077. struct GSUB : GSUBGPOS
  1078. {
  1079. static const hb_tag_t Tag = HB_OT_TAG_GSUB;
  1080. inline const SubstLookup& get_lookup (unsigned int i) const
  1081. { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
  1082. template <typename set_t>
  1083. inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const
  1084. { get_lookup (lookup_index).add_coverage (glyphs); }
  1085. inline bool would_substitute_lookup (hb_would_apply_context_t *c, unsigned int lookup_index) const
  1086. { return get_lookup (lookup_index).would_apply (c); }
  1087. inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index) const
  1088. { return get_lookup (lookup_index).apply_string (c); }
  1089. static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
  1090. static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
  1091. inline void closure_lookup (hb_closure_context_t *c,
  1092. unsigned int lookup_index) const
  1093. { return get_lookup (lookup_index).closure (c); }
  1094. inline bool sanitize (hb_sanitize_context_t *c) {
  1095. TRACE_SANITIZE ();
  1096. if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
  1097. OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
  1098. return TRACE_RETURN (list.sanitize (c, this));
  1099. }
  1100. public:
  1101. DEFINE_SIZE_STATIC (10);
  1102. };
  1103. void
  1104. GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
  1105. {
  1106. HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
  1107. HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
  1108. HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
  1109. const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
  1110. unsigned int count = buffer->len;
  1111. for (unsigned int i = 0; i < count; i++) {
  1112. buffer->info[i].lig_props() = buffer->info[i].syllable() = 0;
  1113. buffer->info[i].glyph_props() = gdef.get_glyph_props (buffer->info[i].codepoint);
  1114. }
  1115. }
  1116. void
  1117. GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
  1118. {
  1119. }
  1120. /* Out-of-class implementation for methods recursing */
  1121. inline void ExtensionSubst::closure (hb_closure_context_t *c) const
  1122. {
  1123. get_subtable ().closure (c, get_type ());
  1124. }
  1125. inline const Coverage & ExtensionSubst::get_coverage (void) const
  1126. {
  1127. return get_subtable ().get_coverage (get_type ());
  1128. }
  1129. inline bool ExtensionSubst::would_apply (hb_would_apply_context_t *c) const
  1130. {
  1131. return get_subtable ().would_apply (c, get_type ());
  1132. }
  1133. inline bool ExtensionSubst::apply (hb_apply_context_t *c) const
  1134. {
  1135. TRACE_APPLY ();
  1136. return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
  1137. }
  1138. inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
  1139. {
  1140. TRACE_SANITIZE ();
  1141. if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
  1142. unsigned int offset = get_offset ();
  1143. if (unlikely (!offset)) return TRACE_RETURN (true);
  1144. return TRACE_RETURN (StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ()));
  1145. }
  1146. inline bool ExtensionSubst::is_reverse (void) const
  1147. {
  1148. unsigned int type = get_type ();
  1149. if (unlikely (type == SubstLookupSubTable::Extension))
  1150. return CastR<ExtensionSubst> (get_subtable()).is_reverse ();
  1151. return SubstLookup::lookup_type_is_reverse (type);
  1152. }
  1153. static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index)
  1154. {
  1155. const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
  1156. const SubstLookup &l = gsub.get_lookup (lookup_index);
  1157. if (unlikely (c->nesting_level_left == 0))
  1158. return;
  1159. c->nesting_level_left--;
  1160. l.closure (c);
  1161. c->nesting_level_left++;
  1162. }
  1163. static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
  1164. {
  1165. const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
  1166. const SubstLookup &l = gsub.get_lookup (lookup_index);
  1167. if (unlikely (c->nesting_level_left == 0))
  1168. return false;
  1169. hb_apply_context_t new_c (*c);
  1170. new_c.nesting_level_left--;
  1171. new_c.set_lookup (l);
  1172. return l.apply_once (&new_c);
  1173. }
  1174. #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */