PageRenderTime 48ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh

https://bitbucket.org/kennethendfinger/chromium
C++ Header | 944 lines | 702 code | 170 blank | 72 comment | 90 complexity | 8bf5d804daec1085dd92bd0937000458 MD5 | raw file
Possible License(s): AGPL-3.0, GPL-3.0, LGPL-2.1, CC-BY-SA-3.0, BSD-2-Clause, CC-BY-3.0, AGPL-1.0, Unlicense, 0BSD, MPL-2.0, LGPL-2.0, Apache-2.0, GPL-2.0, LGPL-3.0, BSD-3-Clause, MPL-2.0-no-copyleft-exception, MIT
  1. /*
  2. * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
  3. * Copyright © 2010 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 bool apply (hb_apply_context_t *c) const
  36. {
  37. TRACE_APPLY ();
  38. hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint;
  39. unsigned int index = (this+coverage) (glyph_id);
  40. if (likely (index == NOT_COVERED))
  41. return false;
  42. /* According to the Adobe Annotated OpenType Suite, result is always
  43. * limited to 16bit. */
  44. glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF;
  45. c->replace_glyph (glyph_id);
  46. return true;
  47. }
  48. inline bool sanitize (hb_sanitize_context_t *c) {
  49. TRACE_SANITIZE ();
  50. return coverage.sanitize (c, this)
  51. && deltaGlyphID.sanitize (c);
  52. }
  53. private:
  54. USHORT format; /* Format identifier--format = 1 */
  55. OffsetTo<Coverage>
  56. coverage; /* Offset to Coverage table--from
  57. * beginning of Substitution table */
  58. SHORT deltaGlyphID; /* Add to original GlyphID to get
  59. * substitute GlyphID */
  60. public:
  61. DEFINE_SIZE_STATIC (6);
  62. };
  63. struct SingleSubstFormat2
  64. {
  65. friend struct SingleSubst;
  66. private:
  67. inline bool apply (hb_apply_context_t *c) const
  68. {
  69. TRACE_APPLY ();
  70. hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint;
  71. unsigned int index = (this+coverage) (glyph_id);
  72. if (likely (index == NOT_COVERED))
  73. return false;
  74. if (unlikely (index >= substitute.len))
  75. return false;
  76. glyph_id = substitute[index];
  77. c->replace_glyph (glyph_id);
  78. return true;
  79. }
  80. inline bool sanitize (hb_sanitize_context_t *c) {
  81. TRACE_SANITIZE ();
  82. return coverage.sanitize (c, this)
  83. && substitute.sanitize (c);
  84. }
  85. private:
  86. USHORT format; /* Format identifier--format = 2 */
  87. OffsetTo<Coverage>
  88. coverage; /* Offset to Coverage table--from
  89. * beginning of Substitution table */
  90. ArrayOf<GlyphID>
  91. substitute; /* Array of substitute
  92. * GlyphIDs--ordered by Coverage Index */
  93. public:
  94. DEFINE_SIZE_ARRAY (6, substitute);
  95. };
  96. struct SingleSubst
  97. {
  98. friend struct SubstLookupSubTable;
  99. private:
  100. inline bool apply (hb_apply_context_t *c) const
  101. {
  102. TRACE_APPLY ();
  103. switch (u.format) {
  104. case 1: return u.format1.apply (c);
  105. case 2: return u.format2.apply (c);
  106. default:return false;
  107. }
  108. }
  109. inline bool sanitize (hb_sanitize_context_t *c) {
  110. TRACE_SANITIZE ();
  111. if (!u.format.sanitize (c)) return false;
  112. switch (u.format) {
  113. case 1: return u.format1.sanitize (c);
  114. case 2: return u.format2.sanitize (c);
  115. default:return true;
  116. }
  117. }
  118. private:
  119. union {
  120. USHORT format; /* Format identifier */
  121. SingleSubstFormat1 format1;
  122. SingleSubstFormat2 format2;
  123. } u;
  124. };
  125. struct Sequence
  126. {
  127. friend struct MultipleSubstFormat1;
  128. private:
  129. inline bool apply (hb_apply_context_t *c) const
  130. {
  131. TRACE_APPLY ();
  132. if (unlikely (!substitute.len))
  133. return false;
  134. if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)
  135. c->guess_glyph_class (HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH);
  136. c->replace_glyphs_be16 (1, substitute.len, (const uint16_t *) substitute.array);
  137. return true;
  138. }
  139. public:
  140. inline bool sanitize (hb_sanitize_context_t *c) {
  141. TRACE_SANITIZE ();
  142. return substitute.sanitize (c);
  143. }
  144. private:
  145. ArrayOf<GlyphID>
  146. substitute; /* String of GlyphIDs to substitute */
  147. public:
  148. DEFINE_SIZE_ARRAY (2, substitute);
  149. };
  150. struct MultipleSubstFormat1
  151. {
  152. friend struct MultipleSubst;
  153. private:
  154. inline bool apply (hb_apply_context_t *c) const
  155. {
  156. TRACE_APPLY ();
  157. unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
  158. if (likely (index == NOT_COVERED))
  159. return false;
  160. return (this+sequence[index]).apply (c);
  161. }
  162. inline bool sanitize (hb_sanitize_context_t *c) {
  163. TRACE_SANITIZE ();
  164. return coverage.sanitize (c, this)
  165. && sequence.sanitize (c, this);
  166. }
  167. private:
  168. USHORT format; /* Format identifier--format = 1 */
  169. OffsetTo<Coverage>
  170. coverage; /* Offset to Coverage table--from
  171. * beginning of Substitution table */
  172. OffsetArrayOf<Sequence>
  173. sequence; /* Array of Sequence tables
  174. * ordered by Coverage Index */
  175. public:
  176. DEFINE_SIZE_ARRAY (6, sequence);
  177. };
  178. struct MultipleSubst
  179. {
  180. friend struct SubstLookupSubTable;
  181. private:
  182. inline bool apply (hb_apply_context_t *c) const
  183. {
  184. TRACE_APPLY ();
  185. switch (u.format) {
  186. case 1: return u.format1.apply (c);
  187. default:return false;
  188. }
  189. }
  190. inline bool sanitize (hb_sanitize_context_t *c) {
  191. TRACE_SANITIZE ();
  192. if (!u.format.sanitize (c)) return false;
  193. switch (u.format) {
  194. case 1: return u.format1.sanitize (c);
  195. default:return true;
  196. }
  197. }
  198. private:
  199. union {
  200. USHORT format; /* Format identifier */
  201. MultipleSubstFormat1 format1;
  202. } u;
  203. };
  204. typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
  205. * arbitrary order */
  206. struct AlternateSubstFormat1
  207. {
  208. friend struct AlternateSubst;
  209. private:
  210. inline bool apply (hb_apply_context_t *c) const
  211. {
  212. TRACE_APPLY ();
  213. hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint;
  214. hb_mask_t glyph_mask = c->buffer->info[c->buffer->idx].mask;
  215. hb_mask_t lookup_mask = c->lookup_mask;
  216. unsigned int index = (this+coverage) (glyph_id);
  217. if (likely (index == NOT_COVERED))
  218. return false;
  219. const AlternateSet &alt_set = this+alternateSet[index];
  220. if (unlikely (!alt_set.len))
  221. return false;
  222. /* Note: This breaks badly if two features enabled this lookup together. */
  223. unsigned int shift = _hb_ctz (lookup_mask);
  224. unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
  225. if (unlikely (alt_index > alt_set.len || alt_index == 0))
  226. return false;
  227. glyph_id = alt_set[alt_index - 1];
  228. c->replace_glyph (glyph_id);
  229. return true;
  230. }
  231. inline bool sanitize (hb_sanitize_context_t *c) {
  232. TRACE_SANITIZE ();
  233. return coverage.sanitize (c, this)
  234. && alternateSet.sanitize (c, this);
  235. }
  236. private:
  237. USHORT format; /* Format identifier--format = 1 */
  238. OffsetTo<Coverage>
  239. coverage; /* Offset to Coverage table--from
  240. * beginning of Substitution table */
  241. OffsetArrayOf<AlternateSet>
  242. alternateSet; /* Array of AlternateSet tables
  243. * ordered by Coverage Index */
  244. public:
  245. DEFINE_SIZE_ARRAY (6, alternateSet);
  246. };
  247. struct AlternateSubst
  248. {
  249. friend struct SubstLookupSubTable;
  250. private:
  251. inline bool apply (hb_apply_context_t *c) const
  252. {
  253. TRACE_APPLY ();
  254. switch (u.format) {
  255. case 1: return u.format1.apply (c);
  256. default:return false;
  257. }
  258. }
  259. inline bool sanitize (hb_sanitize_context_t *c) {
  260. TRACE_SANITIZE ();
  261. if (!u.format.sanitize (c)) return false;
  262. switch (u.format) {
  263. case 1: return u.format1.sanitize (c);
  264. default:return true;
  265. }
  266. }
  267. private:
  268. union {
  269. USHORT format; /* Format identifier */
  270. AlternateSubstFormat1 format1;
  271. } u;
  272. };
  273. struct Ligature
  274. {
  275. friend struct LigatureSet;
  276. private:
  277. inline bool apply (hb_apply_context_t *c) const
  278. {
  279. TRACE_APPLY ();
  280. unsigned int count = component.len;
  281. if (unlikely (count < 2))
  282. return false;
  283. hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
  284. if (skippy_iter.has_no_chance ())
  285. return false;
  286. bool first_was_mark = (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
  287. bool found_non_mark = false;
  288. for (unsigned int i = 1; i < count; i++)
  289. {
  290. unsigned int property;
  291. if (!skippy_iter.next (&property))
  292. return false;
  293. found_non_mark |= !(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
  294. if (likely (c->buffer->info[skippy_iter.idx].codepoint != component[i]))
  295. return false;
  296. }
  297. if (first_was_mark && found_non_mark)
  298. c->guess_glyph_class (HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE);
  299. /* Allocate new ligature id */
  300. unsigned int lig_id = allocate_lig_id (c->buffer);
  301. c->buffer->info[c->buffer->idx].lig_comp() = 0;
  302. c->buffer->info[c->buffer->idx].lig_id() = lig_id;
  303. if (skippy_iter.idx < c->buffer->idx + count) /* No input glyphs skipped */
  304. {
  305. c->replace_glyphs_be16 (count, 1, (const uint16_t *) &ligGlyph);
  306. }
  307. else
  308. {
  309. c->replace_glyph (ligGlyph);
  310. /* Now we must do a second loop to copy the skipped glyphs to
  311. `out' and assign component values to it. We start with the
  312. glyph after the first component. Glyphs between component
  313. i and i+1 belong to component i. Together with the lig_id
  314. value it is later possible to check whether a specific
  315. component value really belongs to a given ligature. */
  316. for (unsigned int i = 1; i < count; i++)
  317. {
  318. while (c->should_mark_skip_current_glyph ())
  319. {
  320. c->buffer->info[c->buffer->idx].lig_comp() = i;
  321. c->buffer->info[c->buffer->idx].lig_id() = lig_id;
  322. c->replace_glyph (c->buffer->info[c->buffer->idx].codepoint);
  323. }
  324. /* Skip the base glyph */
  325. c->buffer->idx++;
  326. }
  327. }
  328. return true;
  329. }
  330. public:
  331. inline bool sanitize (hb_sanitize_context_t *c) {
  332. TRACE_SANITIZE ();
  333. return ligGlyph.sanitize (c)
  334. && component.sanitize (c);
  335. }
  336. private:
  337. GlyphID ligGlyph; /* GlyphID of ligature to substitute */
  338. HeadlessArrayOf<GlyphID>
  339. component; /* Array of component GlyphIDs--start
  340. * with the second component--ordered
  341. * in writing direction */
  342. public:
  343. DEFINE_SIZE_ARRAY (4, component);
  344. };
  345. struct LigatureSet
  346. {
  347. friend struct LigatureSubstFormat1;
  348. private:
  349. inline bool apply (hb_apply_context_t *c) const
  350. {
  351. TRACE_APPLY ();
  352. unsigned int num_ligs = ligature.len;
  353. for (unsigned int i = 0; i < num_ligs; i++)
  354. {
  355. const Ligature &lig = this+ligature[i];
  356. if (lig.apply (c))
  357. return true;
  358. }
  359. return false;
  360. }
  361. public:
  362. inline bool sanitize (hb_sanitize_context_t *c) {
  363. TRACE_SANITIZE ();
  364. return ligature.sanitize (c, this);
  365. }
  366. private:
  367. OffsetArrayOf<Ligature>
  368. ligature; /* Array LigatureSet tables
  369. * ordered by preference */
  370. public:
  371. DEFINE_SIZE_ARRAY (2, ligature);
  372. };
  373. struct LigatureSubstFormat1
  374. {
  375. friend struct LigatureSubst;
  376. private:
  377. inline bool apply (hb_apply_context_t *c) const
  378. {
  379. TRACE_APPLY ();
  380. hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint;
  381. unsigned int index = (this+coverage) (glyph_id);
  382. if (likely (index == NOT_COVERED))
  383. return false;
  384. const LigatureSet &lig_set = this+ligatureSet[index];
  385. return lig_set.apply (c);
  386. }
  387. inline bool sanitize (hb_sanitize_context_t *c) {
  388. TRACE_SANITIZE ();
  389. return coverage.sanitize (c, this)
  390. && ligatureSet.sanitize (c, this);
  391. }
  392. private:
  393. USHORT format; /* Format identifier--format = 1 */
  394. OffsetTo<Coverage>
  395. coverage; /* Offset to Coverage table--from
  396. * beginning of Substitution table */
  397. OffsetArrayOf<LigatureSet>
  398. ligatureSet; /* Array LigatureSet tables
  399. * ordered by Coverage Index */
  400. public:
  401. DEFINE_SIZE_ARRAY (6, ligatureSet);
  402. };
  403. struct LigatureSubst
  404. {
  405. friend struct SubstLookupSubTable;
  406. private:
  407. inline bool apply (hb_apply_context_t *c) const
  408. {
  409. TRACE_APPLY ();
  410. switch (u.format) {
  411. case 1: return u.format1.apply (c);
  412. default:return false;
  413. }
  414. }
  415. inline bool sanitize (hb_sanitize_context_t *c) {
  416. TRACE_SANITIZE ();
  417. if (!u.format.sanitize (c)) return false;
  418. switch (u.format) {
  419. case 1: return u.format1.sanitize (c);
  420. default:return true;
  421. }
  422. }
  423. private:
  424. union {
  425. USHORT format; /* Format identifier */
  426. LigatureSubstFormat1 format1;
  427. } u;
  428. };
  429. static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
  430. struct ContextSubst : Context
  431. {
  432. friend struct SubstLookupSubTable;
  433. private:
  434. inline bool apply (hb_apply_context_t *c) const
  435. {
  436. TRACE_APPLY ();
  437. return Context::apply (c, substitute_lookup);
  438. }
  439. };
  440. struct ChainContextSubst : ChainContext
  441. {
  442. friend struct SubstLookupSubTable;
  443. private:
  444. inline bool apply (hb_apply_context_t *c) const
  445. {
  446. TRACE_APPLY ();
  447. return ChainContext::apply (c, substitute_lookup);
  448. }
  449. };
  450. struct ExtensionSubst : Extension
  451. {
  452. friend struct SubstLookupSubTable;
  453. friend struct SubstLookup;
  454. private:
  455. inline const struct SubstLookupSubTable& get_subtable (void) const
  456. {
  457. unsigned int offset = get_offset ();
  458. if (unlikely (!offset)) return Null(SubstLookupSubTable);
  459. return StructAtOffset<SubstLookupSubTable> (this, offset);
  460. }
  461. inline bool apply (hb_apply_context_t *c) const;
  462. inline bool sanitize (hb_sanitize_context_t *c);
  463. inline bool is_reverse (void) const;
  464. };
  465. struct ReverseChainSingleSubstFormat1
  466. {
  467. friend struct ReverseChainSingleSubst;
  468. private:
  469. inline bool apply (hb_apply_context_t *c) const
  470. {
  471. TRACE_APPLY ();
  472. if (unlikely (c->context_length != NO_CONTEXT))
  473. return false; /* No chaining to this type */
  474. unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
  475. if (likely (index == NOT_COVERED))
  476. return false;
  477. const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  478. const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
  479. if (match_backtrack (c,
  480. backtrack.len, (USHORT *) backtrack.array,
  481. match_coverage, this) &&
  482. match_lookahead (c,
  483. lookahead.len, (USHORT *) lookahead.array,
  484. match_coverage, this,
  485. 1))
  486. {
  487. c->buffer->info[c->buffer->idx].codepoint = substitute[index];
  488. c->buffer->idx--; /* Reverse! */
  489. return true;
  490. }
  491. return false;
  492. }
  493. inline bool sanitize (hb_sanitize_context_t *c) {
  494. TRACE_SANITIZE ();
  495. if (!(coverage.sanitize (c, this)
  496. && backtrack.sanitize (c, this)))
  497. return false;
  498. OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  499. if (!lookahead.sanitize (c, this))
  500. return false;
  501. ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
  502. return substitute.sanitize (c);
  503. }
  504. private:
  505. USHORT format; /* Format identifier--format = 1 */
  506. OffsetTo<Coverage>
  507. coverage; /* Offset to Coverage table--from
  508. * beginning of table */
  509. OffsetArrayOf<Coverage>
  510. backtrack; /* Array of coverage tables
  511. * in backtracking sequence, in glyph
  512. * sequence order */
  513. OffsetArrayOf<Coverage>
  514. lookaheadX; /* Array of coverage tables
  515. * in lookahead sequence, in glyph
  516. * sequence order */
  517. ArrayOf<GlyphID>
  518. substituteX; /* Array of substitute
  519. * GlyphIDs--ordered by Coverage Index */
  520. public:
  521. DEFINE_SIZE_MIN (10);
  522. };
  523. struct ReverseChainSingleSubst
  524. {
  525. friend struct SubstLookupSubTable;
  526. private:
  527. inline bool apply (hb_apply_context_t *c) const
  528. {
  529. TRACE_APPLY ();
  530. switch (u.format) {
  531. case 1: return u.format1.apply (c);
  532. default:return false;
  533. }
  534. }
  535. inline bool sanitize (hb_sanitize_context_t *c) {
  536. TRACE_SANITIZE ();
  537. if (!u.format.sanitize (c)) return false;
  538. switch (u.format) {
  539. case 1: return u.format1.sanitize (c);
  540. default:return true;
  541. }
  542. }
  543. private:
  544. union {
  545. USHORT format; /* Format identifier */
  546. ReverseChainSingleSubstFormat1 format1;
  547. } u;
  548. };
  549. /*
  550. * SubstLookup
  551. */
  552. struct SubstLookupSubTable
  553. {
  554. friend struct SubstLookup;
  555. enum {
  556. Single = 1,
  557. Multiple = 2,
  558. Alternate = 3,
  559. Ligature = 4,
  560. Context = 5,
  561. ChainContext = 6,
  562. Extension = 7,
  563. ReverseChainSingle = 8
  564. };
  565. inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
  566. {
  567. TRACE_APPLY ();
  568. switch (lookup_type) {
  569. case Single: return u.single.apply (c);
  570. case Multiple: return u.multiple.apply (c);
  571. case Alternate: return u.alternate.apply (c);
  572. case Ligature: return u.ligature.apply (c);
  573. case Context: return u.c.apply (c);
  574. case ChainContext: return u.chainContext.apply (c);
  575. case Extension: return u.extension.apply (c);
  576. case ReverseChainSingle: return u.reverseChainContextSingle.apply (c);
  577. default:return false;
  578. }
  579. }
  580. inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
  581. TRACE_SANITIZE ();
  582. switch (lookup_type) {
  583. case Single: return u.single.sanitize (c);
  584. case Multiple: return u.multiple.sanitize (c);
  585. case Alternate: return u.alternate.sanitize (c);
  586. case Ligature: return u.ligature.sanitize (c);
  587. case Context: return u.c.sanitize (c);
  588. case ChainContext: return u.chainContext.sanitize (c);
  589. case Extension: return u.extension.sanitize (c);
  590. case ReverseChainSingle: return u.reverseChainContextSingle.sanitize (c);
  591. default:return true;
  592. }
  593. }
  594. private:
  595. union {
  596. USHORT sub_format;
  597. SingleSubst single;
  598. MultipleSubst multiple;
  599. AlternateSubst alternate;
  600. LigatureSubst ligature;
  601. ContextSubst c;
  602. ChainContextSubst chainContext;
  603. ExtensionSubst extension;
  604. ReverseChainSingleSubst reverseChainContextSingle;
  605. } u;
  606. public:
  607. DEFINE_SIZE_UNION (2, sub_format);
  608. };
  609. struct SubstLookup : Lookup
  610. {
  611. inline const SubstLookupSubTable& get_subtable (unsigned int i) const
  612. { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
  613. inline static bool lookup_type_is_reverse (unsigned int lookup_type)
  614. { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
  615. inline bool is_reverse (void) const
  616. {
  617. unsigned int type = get_type ();
  618. if (unlikely (type == SubstLookupSubTable::Extension))
  619. return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
  620. return lookup_type_is_reverse (type);
  621. }
  622. inline bool apply_once (hb_face_t *face,
  623. hb_buffer_t *buffer,
  624. hb_mask_t lookup_mask,
  625. unsigned int context_length,
  626. unsigned int nesting_level_left) const
  627. {
  628. unsigned int lookup_type = get_type ();
  629. hb_apply_context_t c[1] = {{0}};
  630. c->face = face;
  631. c->buffer = buffer;
  632. c->direction = buffer->props.direction;
  633. c->lookup_mask = lookup_mask;
  634. c->context_length = context_length;
  635. c->nesting_level_left = nesting_level_left;
  636. c->lookup_props = get_props ();
  637. if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, &c->property))
  638. return false;
  639. if (unlikely (lookup_type == SubstLookupSubTable::Extension))
  640. {
  641. /* The spec says all subtables should have the same type.
  642. * This is specially important if one has a reverse type!
  643. *
  644. * This is rather slow to do this here for every glyph,
  645. * but it's easiest, and who uses extension lookups anyway?!*/
  646. unsigned int count = get_subtable_count ();
  647. unsigned int type = get_subtable(0).u.extension.get_type ();
  648. for (unsigned int i = 1; i < count; i++)
  649. if (get_subtable(i).u.extension.get_type () != type)
  650. return false;
  651. }
  652. unsigned int count = get_subtable_count ();
  653. for (unsigned int i = 0; i < count; i++)
  654. if (get_subtable (i).apply (c, lookup_type))
  655. return true;
  656. return false;
  657. }
  658. inline bool apply_string (hb_face_t *face,
  659. hb_buffer_t *buffer,
  660. hb_mask_t mask) const
  661. {
  662. bool ret = false;
  663. if (unlikely (!buffer->len))
  664. return false;
  665. if (likely (!is_reverse ()))
  666. {
  667. /* in/out forward substitution */
  668. buffer->clear_output ();
  669. buffer->idx = 0;
  670. while (buffer->idx < buffer->len)
  671. {
  672. if ((buffer->info[buffer->idx].mask & mask) &&
  673. apply_once (face, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
  674. ret = true;
  675. else
  676. buffer->next_glyph ();
  677. }
  678. if (ret)
  679. buffer->swap_buffers ();
  680. }
  681. else
  682. {
  683. /* in-place backward substitution */
  684. buffer->idx = buffer->len - 1;
  685. do
  686. {
  687. if ((buffer->info[buffer->idx].mask & mask) &&
  688. apply_once (face, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
  689. ret = true;
  690. else
  691. buffer->idx--;
  692. }
  693. while ((int) buffer->idx >= 0);
  694. }
  695. return ret;
  696. }
  697. inline bool sanitize (hb_sanitize_context_t *c) {
  698. TRACE_SANITIZE ();
  699. if (unlikely (!Lookup::sanitize (c))) return false;
  700. OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
  701. return list.sanitize (c, this, get_type ());
  702. }
  703. };
  704. typedef OffsetListOf<SubstLookup> SubstLookupList;
  705. /*
  706. * GSUB -- The Glyph Substitution Table
  707. */
  708. struct GSUB : GSUBGPOS
  709. {
  710. static const hb_tag_t Tag = HB_OT_TAG_GSUB;
  711. inline const SubstLookup& get_lookup (unsigned int i) const
  712. { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
  713. inline bool substitute_lookup (hb_face_t *face,
  714. hb_buffer_t *buffer,
  715. unsigned int lookup_index,
  716. hb_mask_t mask) const
  717. { return get_lookup (lookup_index).apply_string (face, buffer, mask); }
  718. static inline void substitute_start (hb_buffer_t *buffer);
  719. static inline void substitute_finish (hb_buffer_t *buffer);
  720. inline bool sanitize (hb_sanitize_context_t *c) {
  721. TRACE_SANITIZE ();
  722. if (unlikely (!GSUBGPOS::sanitize (c))) return false;
  723. OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
  724. return list.sanitize (c, this);
  725. }
  726. public:
  727. DEFINE_SIZE_STATIC (10);
  728. };
  729. void
  730. GSUB::substitute_start (hb_buffer_t *buffer)
  731. {
  732. HB_BUFFER_ALLOCATE_VAR (buffer, props_cache);
  733. HB_BUFFER_ALLOCATE_VAR (buffer, lig_id);
  734. HB_BUFFER_ALLOCATE_VAR (buffer, lig_comp);
  735. unsigned int count = buffer->len;
  736. for (unsigned int i = 0; i < count; i++)
  737. buffer->info[i].props_cache() = buffer->info[i].lig_id() = buffer->info[i].lig_comp() = 0;
  738. }
  739. void
  740. GSUB::substitute_finish (hb_buffer_t *buffer)
  741. {
  742. }
  743. /* Out-of-class implementation for methods recursing */
  744. inline bool ExtensionSubst::apply (hb_apply_context_t *c) const
  745. {
  746. TRACE_APPLY ();
  747. return get_subtable ().apply (c, get_type ());
  748. }
  749. inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
  750. {
  751. TRACE_SANITIZE ();
  752. if (unlikely (!Extension::sanitize (c))) return false;
  753. unsigned int offset = get_offset ();
  754. if (unlikely (!offset)) return true;
  755. return StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ());
  756. }
  757. inline bool ExtensionSubst::is_reverse (void) const
  758. {
  759. unsigned int type = get_type ();
  760. if (unlikely (type == SubstLookupSubTable::Extension))
  761. return CastR<ExtensionSubst> (get_subtable()).is_reverse ();
  762. return SubstLookup::lookup_type_is_reverse (type);
  763. }
  764. static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
  765. {
  766. const GSUB &gsub = *(c->face->ot_layout->gsub);
  767. const SubstLookup &l = gsub.get_lookup (lookup_index);
  768. if (unlikely (c->nesting_level_left == 0))
  769. return false;
  770. if (unlikely (c->context_length < 1))
  771. return false;
  772. return l.apply_once (c->face, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1);
  773. }
  774. #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */