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

/video-player/src/hb-ot-layout-gsub-private.hh

https://review.tizen.org/git/
C++ Header | 947 lines | 709 code | 168 blank | 70 comment | 93 complexity | 0f9d67bf9d6477768813742cc15dad21 MD5 | raw file
Possible License(s): GPL-3.0, AGPL-3.0, GPL-2.0, MPL-2.0, JSON, WTFPL, CC-BY-SA-4.0, CC-BY-3.0, BSD-3-Clause, LGPL-2.0, MPL-2.0-no-copyleft-exception, AGPL-1.0, 0BSD, Zlib, Unlicense, BSD-2-Clause, Apache-2.0, LGPL-3.0, ISC, MIT, CC-BY-SA-3.0, CC0-1.0, LGPL-2.1
  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_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->idx].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->idx].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->idx].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->idx].codepoint;
  213. hb_mask_t glyph_mask = c->buffer->info[c->buffer->idx].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->idx + c->context_length);
  282. if (unlikely (count < 2 || c->buffer->idx + 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->idx + 1; i < count; i++, j++)
  287. {
  288. unsigned int property;
  289. while (_hb_ot_layout_skip_mark (c->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->idx].lig_comp() = 0;
  304. c->buffer->info[c->buffer->idx].lig_id() = lig_id;
  305. if (j == c->buffer->idx + 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->face, &c->buffer->info[c->buffer->idx], c->lookup_props, NULL))
  321. {
  322. c->buffer->info[c->buffer->idx].lig_comp() = i;
  323. c->buffer->info[c->buffer->idx].lig_id() = lig_id;
  324. c->replace_glyph (c->buffer->info[c->buffer->idx].codepoint);
  325. }
  326. /* Skip the base glyph */
  327. c->buffer->idx++;
  328. }
  329. }
  330. return true;
  331. }
  332. public:
  333. inline bool sanitize (hb_sanitize_context_t *c) {
  334. TRACE_SANITIZE ();
  335. return ligGlyph.sanitize (c)
  336. && component.sanitize (c);
  337. }
  338. private:
  339. GlyphID ligGlyph; /* GlyphID of ligature to substitute */
  340. HeadlessArrayOf<GlyphID>
  341. component; /* Array of component GlyphIDs--start
  342. * with the second component--ordered
  343. * in writing direction */
  344. public:
  345. DEFINE_SIZE_ARRAY (4, component);
  346. };
  347. struct LigatureSet
  348. {
  349. friend struct LigatureSubstFormat1;
  350. private:
  351. inline bool apply (hb_apply_context_t *c) const
  352. {
  353. TRACE_APPLY ();
  354. unsigned int num_ligs = ligature.len;
  355. for (unsigned int i = 0; i < num_ligs; i++)
  356. {
  357. const Ligature &lig = this+ligature[i];
  358. if (lig.apply (c))
  359. return true;
  360. }
  361. return false;
  362. }
  363. public:
  364. inline bool sanitize (hb_sanitize_context_t *c) {
  365. TRACE_SANITIZE ();
  366. return ligature.sanitize (c, this);
  367. }
  368. private:
  369. OffsetArrayOf<Ligature>
  370. ligature; /* Array LigatureSet tables
  371. * ordered by preference */
  372. public:
  373. DEFINE_SIZE_ARRAY (2, ligature);
  374. };
  375. struct LigatureSubstFormat1
  376. {
  377. friend struct LigatureSubst;
  378. private:
  379. inline bool apply (hb_apply_context_t *c) const
  380. {
  381. TRACE_APPLY ();
  382. hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint;
  383. unsigned int index = (this+coverage) (glyph_id);
  384. if (likely (index == NOT_COVERED))
  385. return false;
  386. const LigatureSet &lig_set = this+ligatureSet[index];
  387. return lig_set.apply (c);
  388. }
  389. inline bool sanitize (hb_sanitize_context_t *c) {
  390. TRACE_SANITIZE ();
  391. return coverage.sanitize (c, this)
  392. && ligatureSet.sanitize (c, this);
  393. }
  394. private:
  395. USHORT format; /* Format identifier--format = 1 */
  396. OffsetTo<Coverage>
  397. coverage; /* Offset to Coverage table--from
  398. * beginning of Substitution table */
  399. OffsetArrayOf<LigatureSet>
  400. ligatureSet; /* Array LigatureSet tables
  401. * ordered by Coverage Index */
  402. public:
  403. DEFINE_SIZE_ARRAY (6, ligatureSet);
  404. };
  405. struct LigatureSubst
  406. {
  407. friend struct SubstLookupSubTable;
  408. private:
  409. inline bool apply (hb_apply_context_t *c) const
  410. {
  411. TRACE_APPLY ();
  412. switch (u.format) {
  413. case 1: return u.format1.apply (c);
  414. default:return false;
  415. }
  416. }
  417. inline bool sanitize (hb_sanitize_context_t *c) {
  418. TRACE_SANITIZE ();
  419. if (!u.format.sanitize (c)) return false;
  420. switch (u.format) {
  421. case 1: return u.format1.sanitize (c);
  422. default:return true;
  423. }
  424. }
  425. private:
  426. union {
  427. USHORT format; /* Format identifier */
  428. LigatureSubstFormat1 format1;
  429. } u;
  430. };
  431. HB_BEGIN_DECLS
  432. static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
  433. HB_END_DECLS
  434. struct ContextSubst : Context
  435. {
  436. friend struct SubstLookupSubTable;
  437. private:
  438. inline bool apply (hb_apply_context_t *c) const
  439. {
  440. TRACE_APPLY ();
  441. return Context::apply (c, substitute_lookup);
  442. }
  443. };
  444. struct ChainContextSubst : ChainContext
  445. {
  446. friend struct SubstLookupSubTable;
  447. private:
  448. inline bool apply (hb_apply_context_t *c) const
  449. {
  450. TRACE_APPLY ();
  451. return ChainContext::apply (c, substitute_lookup);
  452. }
  453. };
  454. struct ExtensionSubst : Extension
  455. {
  456. friend struct SubstLookupSubTable;
  457. friend struct SubstLookup;
  458. private:
  459. inline const struct SubstLookupSubTable& get_subtable (void) const
  460. {
  461. unsigned int offset = get_offset ();
  462. if (unlikely (!offset)) return Null(SubstLookupSubTable);
  463. return StructAtOffset<SubstLookupSubTable> (this, offset);
  464. }
  465. inline bool apply (hb_apply_context_t *c) const;
  466. inline bool sanitize (hb_sanitize_context_t *c);
  467. inline bool is_reverse (void) const;
  468. };
  469. struct ReverseChainSingleSubstFormat1
  470. {
  471. friend struct ReverseChainSingleSubst;
  472. private:
  473. inline bool apply (hb_apply_context_t *c) const
  474. {
  475. TRACE_APPLY ();
  476. if (unlikely (c->context_length != NO_CONTEXT))
  477. return false; /* No chaining to this type */
  478. unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
  479. if (likely (index == NOT_COVERED))
  480. return false;
  481. const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  482. const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
  483. if (match_backtrack (c,
  484. backtrack.len, (USHORT *) backtrack.array,
  485. match_coverage, this) &&
  486. match_lookahead (c,
  487. lookahead.len, (USHORT *) lookahead.array,
  488. match_coverage, this,
  489. 1))
  490. {
  491. c->buffer->info[c->buffer->idx].codepoint = substitute[index];
  492. c->buffer->idx--; /* Reverse! */
  493. return true;
  494. }
  495. return false;
  496. }
  497. inline bool sanitize (hb_sanitize_context_t *c) {
  498. TRACE_SANITIZE ();
  499. if (!(coverage.sanitize (c, this)
  500. && backtrack.sanitize (c, this)))
  501. return false;
  502. OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  503. if (!lookahead.sanitize (c, this))
  504. return false;
  505. ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
  506. return substitute.sanitize (c);
  507. }
  508. private:
  509. USHORT format; /* Format identifier--format = 1 */
  510. OffsetTo<Coverage>
  511. coverage; /* Offset to Coverage table--from
  512. * beginning of table */
  513. OffsetArrayOf<Coverage>
  514. backtrack; /* Array of coverage tables
  515. * in backtracking sequence, in glyph
  516. * sequence order */
  517. OffsetArrayOf<Coverage>
  518. lookaheadX; /* Array of coverage tables
  519. * in lookahead sequence, in glyph
  520. * sequence order */
  521. ArrayOf<GlyphID>
  522. substituteX; /* Array of substitute
  523. * GlyphIDs--ordered by Coverage Index */
  524. public:
  525. DEFINE_SIZE_MIN (10);
  526. };
  527. struct ReverseChainSingleSubst
  528. {
  529. friend struct SubstLookupSubTable;
  530. private:
  531. inline bool apply (hb_apply_context_t *c) const
  532. {
  533. TRACE_APPLY ();
  534. switch (u.format) {
  535. case 1: return u.format1.apply (c);
  536. default:return false;
  537. }
  538. }
  539. inline bool sanitize (hb_sanitize_context_t *c) {
  540. TRACE_SANITIZE ();
  541. if (!u.format.sanitize (c)) return false;
  542. switch (u.format) {
  543. case 1: return u.format1.sanitize (c);
  544. default:return true;
  545. }
  546. }
  547. private:
  548. union {
  549. USHORT format; /* Format identifier */
  550. ReverseChainSingleSubstFormat1 format1;
  551. } u;
  552. };
  553. /*
  554. * SubstLookup
  555. */
  556. struct SubstLookupSubTable
  557. {
  558. friend struct SubstLookup;
  559. enum {
  560. Single = 1,
  561. Multiple = 2,
  562. Alternate = 3,
  563. Ligature = 4,
  564. Context = 5,
  565. ChainContext = 6,
  566. Extension = 7,
  567. ReverseChainSingle = 8
  568. };
  569. inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
  570. {
  571. TRACE_APPLY ();
  572. switch (lookup_type) {
  573. case Single: return u.single.apply (c);
  574. case Multiple: return u.multiple.apply (c);
  575. case Alternate: return u.alternate.apply (c);
  576. case Ligature: return u.ligature.apply (c);
  577. case Context: return u.c.apply (c);
  578. case ChainContext: return u.chainContext.apply (c);
  579. case Extension: return u.extension.apply (c);
  580. case ReverseChainSingle: return u.reverseChainContextSingle.apply (c);
  581. default:return false;
  582. }
  583. }
  584. inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
  585. TRACE_SANITIZE ();
  586. switch (lookup_type) {
  587. case Single: return u.single.sanitize (c);
  588. case Multiple: return u.multiple.sanitize (c);
  589. case Alternate: return u.alternate.sanitize (c);
  590. case Ligature: return u.ligature.sanitize (c);
  591. case Context: return u.c.sanitize (c);
  592. case ChainContext: return u.chainContext.sanitize (c);
  593. case Extension: return u.extension.sanitize (c);
  594. case ReverseChainSingle: return u.reverseChainContextSingle.sanitize (c);
  595. default:return true;
  596. }
  597. }
  598. private:
  599. union {
  600. USHORT sub_format;
  601. SingleSubst single;
  602. MultipleSubst multiple;
  603. AlternateSubst alternate;
  604. LigatureSubst ligature;
  605. ContextSubst c;
  606. ChainContextSubst chainContext;
  607. ExtensionSubst extension;
  608. ReverseChainSingleSubst reverseChainContextSingle;
  609. } u;
  610. public:
  611. DEFINE_SIZE_UNION (2, sub_format);
  612. };
  613. struct SubstLookup : Lookup
  614. {
  615. inline const SubstLookupSubTable& get_subtable (unsigned int i) const
  616. { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
  617. inline static bool lookup_type_is_reverse (unsigned int lookup_type)
  618. { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
  619. inline bool is_reverse (void) const
  620. {
  621. unsigned int type = get_type ();
  622. if (unlikely (type == SubstLookupSubTable::Extension))
  623. return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
  624. return lookup_type_is_reverse (type);
  625. }
  626. inline bool apply_once (hb_face_t *face,
  627. hb_buffer_t *buffer,
  628. hb_mask_t lookup_mask,
  629. unsigned int context_length,
  630. unsigned int nesting_level_left) const
  631. {
  632. unsigned int lookup_type = get_type ();
  633. hb_apply_context_t c[1] = {{0}};
  634. c->face = face;
  635. c->buffer = buffer;
  636. c->direction = buffer->props.direction;
  637. c->lookup_mask = lookup_mask;
  638. c->context_length = context_length;
  639. c->nesting_level_left = nesting_level_left;
  640. c->lookup_props = get_props ();
  641. if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, &c->property))
  642. return false;
  643. if (unlikely (lookup_type == SubstLookupSubTable::Extension))
  644. {
  645. /* The spec says all subtables should have the same type.
  646. * This is specially important if one has a reverse type!
  647. *
  648. * This is rather slow to do this here for every glyph,
  649. * but it's easiest, and who uses extension lookups anyway?!*/
  650. unsigned int count = get_subtable_count ();
  651. unsigned int type = get_subtable(0).u.extension.get_type ();
  652. for (unsigned int i = 1; i < count; i++)
  653. if (get_subtable(i).u.extension.get_type () != type)
  654. return false;
  655. }
  656. unsigned int count = get_subtable_count ();
  657. for (unsigned int i = 0; i < count; i++)
  658. if (get_subtable (i).apply (c, lookup_type))
  659. return true;
  660. return false;
  661. }
  662. inline bool apply_string (hb_face_t *face,
  663. hb_buffer_t *buffer,
  664. hb_mask_t mask) const
  665. {
  666. bool ret = false;
  667. if (unlikely (!buffer->len))
  668. return false;
  669. if (likely (!is_reverse ()))
  670. {
  671. /* in/out forward substitution */
  672. buffer->clear_output ();
  673. buffer->idx = 0;
  674. while (buffer->idx < buffer->len)
  675. {
  676. if ((buffer->info[buffer->idx].mask & mask) &&
  677. apply_once (face, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
  678. ret = true;
  679. else
  680. buffer->next_glyph ();
  681. }
  682. if (ret)
  683. buffer->swap_buffers ();
  684. }
  685. else
  686. {
  687. /* in-place backward substitution */
  688. buffer->idx = buffer->len - 1;
  689. do
  690. {
  691. if ((buffer->info[buffer->idx].mask & mask) &&
  692. apply_once (face, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
  693. ret = true;
  694. else
  695. buffer->idx--;
  696. }
  697. while ((int) buffer->idx >= 0);
  698. }
  699. return ret;
  700. }
  701. inline bool sanitize (hb_sanitize_context_t *c) {
  702. TRACE_SANITIZE ();
  703. if (unlikely (!Lookup::sanitize (c))) return false;
  704. OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
  705. return list.sanitize (c, this, get_type ());
  706. }
  707. };
  708. typedef OffsetListOf<SubstLookup> SubstLookupList;
  709. /*
  710. * GSUB
  711. */
  712. struct GSUB : GSUBGPOS
  713. {
  714. static const hb_tag_t Tag = HB_OT_TAG_GSUB;
  715. inline const SubstLookup& get_lookup (unsigned int i) const
  716. { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
  717. inline bool substitute_lookup (hb_face_t *face,
  718. hb_buffer_t *buffer,
  719. unsigned int lookup_index,
  720. hb_mask_t mask) const
  721. { return get_lookup (lookup_index).apply_string (face, buffer, mask); }
  722. static inline void substitute_start (hb_buffer_t *buffer);
  723. static inline void substitute_finish (hb_buffer_t *buffer);
  724. inline bool sanitize (hb_sanitize_context_t *c) {
  725. TRACE_SANITIZE ();
  726. if (unlikely (!GSUBGPOS::sanitize (c))) return false;
  727. OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
  728. return list.sanitize (c, this);
  729. }
  730. public:
  731. DEFINE_SIZE_STATIC (10);
  732. };
  733. void
  734. GSUB::substitute_start (hb_buffer_t *buffer)
  735. {
  736. HB_BUFFER_ALLOCATE_VAR (buffer, props_cache);
  737. HB_BUFFER_ALLOCATE_VAR (buffer, lig_id);
  738. HB_BUFFER_ALLOCATE_VAR (buffer, lig_comp);
  739. unsigned int count = buffer->len;
  740. for (unsigned int i = 0; i < count; i++)
  741. buffer->info[i].props_cache() = buffer->info[i].lig_id() = buffer->info[i].lig_comp() = 0;
  742. }
  743. void
  744. GSUB::substitute_finish (hb_buffer_t *buffer)
  745. {
  746. }
  747. /* Out-of-class implementation for methods recursing */
  748. inline bool ExtensionSubst::apply (hb_apply_context_t *c) const
  749. {
  750. TRACE_APPLY ();
  751. return get_subtable ().apply (c, get_type ());
  752. }
  753. inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
  754. {
  755. TRACE_SANITIZE ();
  756. if (unlikely (!Extension::sanitize (c))) return false;
  757. unsigned int offset = get_offset ();
  758. if (unlikely (!offset)) return true;
  759. return StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ());
  760. }
  761. inline bool ExtensionSubst::is_reverse (void) const
  762. {
  763. unsigned int type = get_type ();
  764. if (unlikely (type == SubstLookupSubTable::Extension))
  765. return CastR<ExtensionSubst> (get_subtable()).is_reverse ();
  766. return SubstLookup::lookup_type_is_reverse (type);
  767. }
  768. static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
  769. {
  770. const GSUB &gsub = *(c->face->ot_layout->gsub);
  771. const SubstLookup &l = gsub.get_lookup (lookup_index);
  772. if (unlikely (c->nesting_level_left == 0))
  773. return false;
  774. if (unlikely (c->context_length < 1))
  775. return false;
  776. return l.apply_once (c->face, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1);
  777. }
  778. HB_END_DECLS
  779. #endif /* HB_OT_LAYOUT_GSUB_PRIVATE_HH */