PageRenderTime 105ms CodeModel.GetById 73ms RepoModel.GetById 0ms app.codeStats 1ms

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

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