PageRenderTime 62ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://bitbucket.org/halwine/releases-mozilla-inbound
C++ Header | 1253 lines | 960 code | 221 blank | 72 comment | 139 complexity | 37eeb5460409a4eb5b3d97647c2c82d5 MD5 | raw file
Possible License(s): AGPL-1.0, JSON, 0BSD, BSD-2-Clause, GPL-2.0, Apache-2.0, LGPL-2.1, LGPL-3.0, MIT, MPL-2.0-no-copyleft-exception, MPL-2.0, BSD-3-Clause
  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 bool would_apply (hb_codepoint_t glyph_id) const
  46. {
  47. return (this+coverage) (glyph_id) != NOT_COVERED;
  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. private:
  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 bool would_apply (hb_codepoint_t glyph_id) const
  89. {
  90. return (this+coverage) (glyph_id) != NOT_COVERED;
  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. private:
  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 bool would_apply (hb_codepoint_t glyph_id) const
  132. {
  133. switch (u.format) {
  134. case 1: return u.format1.would_apply (glyph_id);
  135. case 2: return u.format2.would_apply (glyph_id);
  136. default:return false;
  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. private:
  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. c->replace_glyphs_be16 (1, substitute.len, (const uint16_t *) substitute.array, klass);
  181. return TRACE_RETURN (true);
  182. }
  183. public:
  184. inline bool sanitize (hb_sanitize_context_t *c) {
  185. TRACE_SANITIZE ();
  186. return TRACE_RETURN (substitute.sanitize (c));
  187. }
  188. private:
  189. ArrayOf<GlyphID>
  190. substitute; /* String of GlyphIDs to substitute */
  191. public:
  192. DEFINE_SIZE_ARRAY (2, substitute);
  193. };
  194. struct MultipleSubstFormat1
  195. {
  196. friend struct MultipleSubst;
  197. private:
  198. inline void closure (hb_closure_context_t *c) const
  199. {
  200. TRACE_CLOSURE ();
  201. Coverage::Iter iter;
  202. for (iter.init (this+coverage); iter.more (); iter.next ()) {
  203. if (c->glyphs->has (iter.get_glyph ()))
  204. (this+sequence[iter.get_coverage ()]).closure (c);
  205. }
  206. }
  207. inline bool would_apply (hb_codepoint_t glyph_id) const
  208. {
  209. return (this+coverage) (glyph_id) != NOT_COVERED;
  210. }
  211. inline bool apply (hb_apply_context_t *c) const
  212. {
  213. TRACE_APPLY ();
  214. unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
  215. if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
  216. return TRACE_RETURN ((this+sequence[index]).apply (c));
  217. }
  218. inline bool sanitize (hb_sanitize_context_t *c) {
  219. TRACE_SANITIZE ();
  220. return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
  221. }
  222. private:
  223. USHORT format; /* Format identifier--format = 1 */
  224. OffsetTo<Coverage>
  225. coverage; /* Offset to Coverage table--from
  226. * beginning of Substitution table */
  227. OffsetArrayOf<Sequence>
  228. sequence; /* Array of Sequence tables
  229. * ordered by Coverage Index */
  230. public:
  231. DEFINE_SIZE_ARRAY (6, sequence);
  232. };
  233. struct MultipleSubst
  234. {
  235. friend struct SubstLookupSubTable;
  236. private:
  237. inline void closure (hb_closure_context_t *c) const
  238. {
  239. TRACE_CLOSURE ();
  240. switch (u.format) {
  241. case 1: u.format1.closure (c); break;
  242. default: break;
  243. }
  244. }
  245. inline bool would_apply (hb_codepoint_t glyph_id) const
  246. {
  247. switch (u.format) {
  248. case 1: return u.format1.would_apply (glyph_id);
  249. default:return false;
  250. }
  251. }
  252. inline bool apply (hb_apply_context_t *c) const
  253. {
  254. TRACE_APPLY ();
  255. switch (u.format) {
  256. case 1: return TRACE_RETURN (u.format1.apply (c));
  257. default:return TRACE_RETURN (false);
  258. }
  259. }
  260. inline bool sanitize (hb_sanitize_context_t *c) {
  261. TRACE_SANITIZE ();
  262. if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  263. switch (u.format) {
  264. case 1: return TRACE_RETURN (u.format1.sanitize (c));
  265. default:return TRACE_RETURN (true);
  266. }
  267. }
  268. private:
  269. union {
  270. USHORT format; /* Format identifier */
  271. MultipleSubstFormat1 format1;
  272. } u;
  273. };
  274. typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
  275. * arbitrary order */
  276. struct AlternateSubstFormat1
  277. {
  278. friend struct AlternateSubst;
  279. private:
  280. inline void closure (hb_closure_context_t *c) const
  281. {
  282. TRACE_CLOSURE ();
  283. Coverage::Iter iter;
  284. for (iter.init (this+coverage); iter.more (); iter.next ()) {
  285. if (c->glyphs->has (iter.get_glyph ())) {
  286. const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
  287. unsigned int count = alt_set.len;
  288. for (unsigned int i = 0; i < count; i++)
  289. c->glyphs->add (alt_set[i]);
  290. }
  291. }
  292. }
  293. inline bool would_apply (hb_codepoint_t glyph_id) const
  294. {
  295. return (this+coverage) (glyph_id) != NOT_COVERED;
  296. }
  297. inline bool apply (hb_apply_context_t *c) const
  298. {
  299. TRACE_APPLY ();
  300. hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
  301. unsigned int index = (this+coverage) (glyph_id);
  302. if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
  303. const AlternateSet &alt_set = this+alternateSet[index];
  304. if (unlikely (!alt_set.len)) return TRACE_RETURN (false);
  305. hb_mask_t glyph_mask = c->buffer->cur().mask;
  306. hb_mask_t lookup_mask = c->lookup_mask;
  307. /* Note: This breaks badly if two features enabled this lookup together. */
  308. unsigned int shift = _hb_ctz (lookup_mask);
  309. unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
  310. if (unlikely (alt_index > alt_set.len || alt_index == 0)) return TRACE_RETURN (false);
  311. glyph_id = alt_set[alt_index - 1];
  312. c->replace_glyph (glyph_id);
  313. return TRACE_RETURN (true);
  314. }
  315. inline bool sanitize (hb_sanitize_context_t *c) {
  316. TRACE_SANITIZE ();
  317. return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
  318. }
  319. private:
  320. USHORT format; /* Format identifier--format = 1 */
  321. OffsetTo<Coverage>
  322. coverage; /* Offset to Coverage table--from
  323. * beginning of Substitution table */
  324. OffsetArrayOf<AlternateSet>
  325. alternateSet; /* Array of AlternateSet tables
  326. * ordered by Coverage Index */
  327. public:
  328. DEFINE_SIZE_ARRAY (6, alternateSet);
  329. };
  330. struct AlternateSubst
  331. {
  332. friend struct SubstLookupSubTable;
  333. private:
  334. inline void closure (hb_closure_context_t *c) const
  335. {
  336. TRACE_CLOSURE ();
  337. switch (u.format) {
  338. case 1: u.format1.closure (c); break;
  339. default: break;
  340. }
  341. }
  342. inline bool would_apply (hb_codepoint_t glyph_id) const
  343. {
  344. switch (u.format) {
  345. case 1: return u.format1.would_apply (glyph_id);
  346. default:return false;
  347. }
  348. }
  349. inline bool apply (hb_apply_context_t *c) const
  350. {
  351. TRACE_APPLY ();
  352. switch (u.format) {
  353. case 1: return TRACE_RETURN (u.format1.apply (c));
  354. default:return TRACE_RETURN (false);
  355. }
  356. }
  357. inline bool sanitize (hb_sanitize_context_t *c) {
  358. TRACE_SANITIZE ();
  359. if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  360. switch (u.format) {
  361. case 1: return TRACE_RETURN (u.format1.sanitize (c));
  362. default:return TRACE_RETURN (true);
  363. }
  364. }
  365. private:
  366. union {
  367. USHORT format; /* Format identifier */
  368. AlternateSubstFormat1 format1;
  369. } u;
  370. };
  371. struct Ligature
  372. {
  373. friend struct LigatureSet;
  374. private:
  375. inline void closure (hb_closure_context_t *c) const
  376. {
  377. TRACE_CLOSURE ();
  378. unsigned int count = component.len;
  379. for (unsigned int i = 1; i < count; i++)
  380. if (!c->glyphs->has (component[i]))
  381. return;
  382. c->glyphs->add (ligGlyph);
  383. }
  384. inline bool would_apply (hb_codepoint_t second) const
  385. {
  386. return component.len == 2 && component[1] == second;
  387. }
  388. inline bool apply (hb_apply_context_t *c) const
  389. {
  390. TRACE_APPLY ();
  391. unsigned int count = component.len;
  392. if (unlikely (count < 2)) return TRACE_RETURN (false);
  393. hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
  394. if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
  395. bool first_was_mark = (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
  396. bool found_non_mark = false;
  397. for (unsigned int i = 1; i < count; i++)
  398. {
  399. unsigned int property;
  400. if (!skippy_iter.next (&property)) return TRACE_RETURN (false);
  401. found_non_mark |= !(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
  402. if (likely (c->buffer->info[skippy_iter.idx].codepoint != component[i])) return TRACE_RETURN (false);
  403. }
  404. unsigned int klass = first_was_mark && found_non_mark ? HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE : 0;
  405. /* Allocate new ligature id */
  406. unsigned int lig_id = allocate_lig_id (c->buffer);
  407. set_lig_props (c->buffer->cur(), lig_id, 0);
  408. if (skippy_iter.idx < c->buffer->idx + count) /* No input glyphs skipped */
  409. {
  410. c->replace_glyphs_be16 (count, 1, (const uint16_t *) &ligGlyph, klass);
  411. }
  412. else
  413. {
  414. c->replace_glyph (ligGlyph);
  415. /* Now we must do a second loop to copy the skipped glyphs to
  416. `out' and assign component values to it. We start with the
  417. glyph after the first component. Glyphs between component
  418. i and i+1 belong to component i. Together with the lig_id
  419. value it is later possible to check whether a specific
  420. component value really belongs to a given ligature. */
  421. for (unsigned int i = 1; i < count; i++)
  422. {
  423. while (c->should_mark_skip_current_glyph ())
  424. {
  425. set_lig_props (c->buffer->cur(), lig_id, i);
  426. c->replace_glyph (c->buffer->cur().codepoint);
  427. }
  428. /* Skip the base glyph */
  429. c->buffer->idx++;
  430. }
  431. }
  432. return TRACE_RETURN (true);
  433. }
  434. public:
  435. inline bool sanitize (hb_sanitize_context_t *c) {
  436. TRACE_SANITIZE ();
  437. return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
  438. }
  439. private:
  440. GlyphID ligGlyph; /* GlyphID of ligature to substitute */
  441. HeadlessArrayOf<GlyphID>
  442. component; /* Array of component GlyphIDs--start
  443. * with the second component--ordered
  444. * in writing direction */
  445. public:
  446. DEFINE_SIZE_ARRAY (4, component);
  447. };
  448. struct LigatureSet
  449. {
  450. friend struct LigatureSubstFormat1;
  451. private:
  452. inline void closure (hb_closure_context_t *c) const
  453. {
  454. TRACE_CLOSURE ();
  455. unsigned int num_ligs = ligature.len;
  456. for (unsigned int i = 0; i < num_ligs; i++)
  457. (this+ligature[i]).closure (c);
  458. }
  459. inline bool would_apply (hb_codepoint_t second) const
  460. {
  461. unsigned int num_ligs = ligature.len;
  462. for (unsigned int i = 0; i < num_ligs; i++)
  463. {
  464. const Ligature &lig = this+ligature[i];
  465. if (lig.would_apply (second))
  466. return true;
  467. }
  468. return false;
  469. }
  470. inline bool apply (hb_apply_context_t *c) const
  471. {
  472. TRACE_APPLY ();
  473. unsigned int num_ligs = ligature.len;
  474. for (unsigned int i = 0; i < num_ligs; i++)
  475. {
  476. const Ligature &lig = this+ligature[i];
  477. if (lig.apply (c)) return TRACE_RETURN (true);
  478. }
  479. return TRACE_RETURN (false);
  480. }
  481. public:
  482. inline bool sanitize (hb_sanitize_context_t *c) {
  483. TRACE_SANITIZE ();
  484. return TRACE_RETURN (ligature.sanitize (c, this));
  485. }
  486. private:
  487. OffsetArrayOf<Ligature>
  488. ligature; /* Array LigatureSet tables
  489. * ordered by preference */
  490. public:
  491. DEFINE_SIZE_ARRAY (2, ligature);
  492. };
  493. struct LigatureSubstFormat1
  494. {
  495. friend struct LigatureSubst;
  496. private:
  497. inline void closure (hb_closure_context_t *c) const
  498. {
  499. TRACE_CLOSURE ();
  500. Coverage::Iter iter;
  501. for (iter.init (this+coverage); iter.more (); iter.next ()) {
  502. if (c->glyphs->has (iter.get_glyph ()))
  503. (this+ligatureSet[iter.get_coverage ()]).closure (c);
  504. }
  505. }
  506. inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const
  507. {
  508. unsigned int index;
  509. return (index = (this+coverage) (first)) != NOT_COVERED &&
  510. (this+ligatureSet[index]).would_apply (second);
  511. }
  512. inline bool apply (hb_apply_context_t *c) const
  513. {
  514. TRACE_APPLY ();
  515. hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
  516. unsigned int index = (this+coverage) (glyph_id);
  517. if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
  518. const LigatureSet &lig_set = this+ligatureSet[index];
  519. return TRACE_RETURN (lig_set.apply (c));
  520. }
  521. inline bool sanitize (hb_sanitize_context_t *c) {
  522. TRACE_SANITIZE ();
  523. return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
  524. }
  525. private:
  526. USHORT format; /* Format identifier--format = 1 */
  527. OffsetTo<Coverage>
  528. coverage; /* Offset to Coverage table--from
  529. * beginning of Substitution table */
  530. OffsetArrayOf<LigatureSet>
  531. ligatureSet; /* Array LigatureSet tables
  532. * ordered by Coverage Index */
  533. public:
  534. DEFINE_SIZE_ARRAY (6, ligatureSet);
  535. };
  536. struct LigatureSubst
  537. {
  538. friend struct SubstLookupSubTable;
  539. private:
  540. inline void closure (hb_closure_context_t *c) const
  541. {
  542. TRACE_CLOSURE ();
  543. switch (u.format) {
  544. case 1: u.format1.closure (c); break;
  545. default: break;
  546. }
  547. }
  548. inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const
  549. {
  550. switch (u.format) {
  551. case 1: return u.format1.would_apply (first, second);
  552. default:return false;
  553. }
  554. }
  555. inline bool apply (hb_apply_context_t *c) const
  556. {
  557. TRACE_APPLY ();
  558. switch (u.format) {
  559. case 1: return TRACE_RETURN (u.format1.apply (c));
  560. default:return TRACE_RETURN (false);
  561. }
  562. }
  563. inline bool sanitize (hb_sanitize_context_t *c) {
  564. TRACE_SANITIZE ();
  565. if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  566. switch (u.format) {
  567. case 1: return TRACE_RETURN (u.format1.sanitize (c));
  568. default:return TRACE_RETURN (true);
  569. }
  570. }
  571. private:
  572. union {
  573. USHORT format; /* Format identifier */
  574. LigatureSubstFormat1 format1;
  575. } u;
  576. };
  577. static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
  578. static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index);
  579. struct ContextSubst : Context
  580. {
  581. friend struct SubstLookupSubTable;
  582. private:
  583. inline void closure (hb_closure_context_t *c) const
  584. {
  585. TRACE_CLOSURE ();
  586. return Context::closure (c, closure_lookup);
  587. }
  588. inline bool apply (hb_apply_context_t *c) const
  589. {
  590. TRACE_APPLY ();
  591. return TRACE_RETURN (Context::apply (c, substitute_lookup));
  592. }
  593. };
  594. struct ChainContextSubst : ChainContext
  595. {
  596. friend struct SubstLookupSubTable;
  597. private:
  598. inline void closure (hb_closure_context_t *c) const
  599. {
  600. TRACE_CLOSURE ();
  601. return ChainContext::closure (c, closure_lookup);
  602. }
  603. inline bool apply (hb_apply_context_t *c) const
  604. {
  605. TRACE_APPLY ();
  606. return TRACE_RETURN (ChainContext::apply (c, substitute_lookup));
  607. }
  608. };
  609. struct ExtensionSubst : Extension
  610. {
  611. friend struct SubstLookupSubTable;
  612. friend struct SubstLookup;
  613. private:
  614. inline const struct SubstLookupSubTable& get_subtable (void) const
  615. {
  616. unsigned int offset = get_offset ();
  617. if (unlikely (!offset)) return Null(SubstLookupSubTable);
  618. return StructAtOffset<SubstLookupSubTable> (this, offset);
  619. }
  620. inline void closure (hb_closure_context_t *c) const;
  621. inline bool would_apply (hb_codepoint_t glyph_id) const;
  622. inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const;
  623. inline bool apply (hb_apply_context_t *c) const;
  624. inline bool sanitize (hb_sanitize_context_t *c);
  625. inline bool is_reverse (void) const;
  626. };
  627. struct ReverseChainSingleSubstFormat1
  628. {
  629. friend struct ReverseChainSingleSubst;
  630. private:
  631. inline void closure (hb_closure_context_t *c) const
  632. {
  633. TRACE_CLOSURE ();
  634. const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  635. unsigned int count;
  636. count = backtrack.len;
  637. for (unsigned int i = 0; i < count; i++)
  638. if (!(this+backtrack[i]).intersects (c->glyphs))
  639. return;
  640. count = lookahead.len;
  641. for (unsigned int i = 0; i < count; i++)
  642. if (!(this+lookahead[i]).intersects (c->glyphs))
  643. return;
  644. const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
  645. Coverage::Iter iter;
  646. for (iter.init (this+coverage); iter.more (); iter.next ()) {
  647. if (c->glyphs->has (iter.get_glyph ()))
  648. c->glyphs->add (substitute[iter.get_coverage ()]);
  649. }
  650. }
  651. inline bool apply (hb_apply_context_t *c) const
  652. {
  653. TRACE_APPLY ();
  654. if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
  655. return TRACE_RETURN (false); /* No chaining to this type */
  656. unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
  657. if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
  658. const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  659. const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
  660. if (match_backtrack (c,
  661. backtrack.len, (USHORT *) backtrack.array,
  662. match_coverage, this) &&
  663. match_lookahead (c,
  664. lookahead.len, (USHORT *) lookahead.array,
  665. match_coverage, this,
  666. 1))
  667. {
  668. c->buffer->cur().codepoint = substitute[index];
  669. c->buffer->idx--; /* Reverse! */
  670. return TRACE_RETURN (true);
  671. }
  672. return TRACE_RETURN (false);
  673. }
  674. inline bool sanitize (hb_sanitize_context_t *c) {
  675. TRACE_SANITIZE ();
  676. if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
  677. return TRACE_RETURN (false);
  678. OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  679. if (!lookahead.sanitize (c, this))
  680. return TRACE_RETURN (false);
  681. ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
  682. return TRACE_RETURN (substitute.sanitize (c));
  683. }
  684. private:
  685. USHORT format; /* Format identifier--format = 1 */
  686. OffsetTo<Coverage>
  687. coverage; /* Offset to Coverage table--from
  688. * beginning of table */
  689. OffsetArrayOf<Coverage>
  690. backtrack; /* Array of coverage tables
  691. * in backtracking sequence, in glyph
  692. * sequence order */
  693. OffsetArrayOf<Coverage>
  694. lookaheadX; /* Array of coverage tables
  695. * in lookahead sequence, in glyph
  696. * sequence order */
  697. ArrayOf<GlyphID>
  698. substituteX; /* Array of substitute
  699. * GlyphIDs--ordered by Coverage Index */
  700. public:
  701. DEFINE_SIZE_MIN (10);
  702. };
  703. struct ReverseChainSingleSubst
  704. {
  705. friend struct SubstLookupSubTable;
  706. private:
  707. inline void closure (hb_closure_context_t *c) const
  708. {
  709. TRACE_CLOSURE ();
  710. switch (u.format) {
  711. case 1: u.format1.closure (c); break;
  712. default: break;
  713. }
  714. }
  715. inline bool apply (hb_apply_context_t *c) const
  716. {
  717. TRACE_APPLY ();
  718. switch (u.format) {
  719. case 1: return TRACE_RETURN (u.format1.apply (c));
  720. default:return TRACE_RETURN (false);
  721. }
  722. }
  723. inline bool sanitize (hb_sanitize_context_t *c) {
  724. TRACE_SANITIZE ();
  725. if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  726. switch (u.format) {
  727. case 1: return TRACE_RETURN (u.format1.sanitize (c));
  728. default:return TRACE_RETURN (true);
  729. }
  730. }
  731. private:
  732. union {
  733. USHORT format; /* Format identifier */
  734. ReverseChainSingleSubstFormat1 format1;
  735. } u;
  736. };
  737. /*
  738. * SubstLookup
  739. */
  740. struct SubstLookupSubTable
  741. {
  742. friend struct SubstLookup;
  743. enum Type {
  744. Single = 1,
  745. Multiple = 2,
  746. Alternate = 3,
  747. Ligature = 4,
  748. Context = 5,
  749. ChainContext = 6,
  750. Extension = 7,
  751. ReverseChainSingle = 8
  752. };
  753. inline void closure (hb_closure_context_t *c,
  754. unsigned int lookup_type) const
  755. {
  756. TRACE_CLOSURE ();
  757. switch (lookup_type) {
  758. case Single: u.single.closure (c); break;
  759. case Multiple: u.multiple.closure (c); break;
  760. case Alternate: u.alternate.closure (c); break;
  761. case Ligature: u.ligature.closure (c); break;
  762. case Context: u.c.closure (c); break;
  763. case ChainContext: u.chainContext.closure (c); break;
  764. case Extension: u.extension.closure (c); break;
  765. case ReverseChainSingle: u.reverseChainContextSingle.closure (c); break;
  766. default: break;
  767. }
  768. }
  769. inline bool would_apply (hb_codepoint_t glyph_id,
  770. unsigned int lookup_type) const
  771. {
  772. switch (lookup_type) {
  773. case Single: return u.single.would_apply (glyph_id);
  774. case Multiple: return u.multiple.would_apply (glyph_id);
  775. case Alternate: return u.alternate.would_apply (glyph_id);
  776. case Extension: return u.extension.would_apply (glyph_id);
  777. default: return false;
  778. }
  779. }
  780. inline bool would_apply (hb_codepoint_t first,
  781. hb_codepoint_t second,
  782. unsigned int lookup_type) const
  783. {
  784. switch (lookup_type) {
  785. case Ligature: return u.ligature.would_apply (first, second);
  786. case Extension: return u.extension.would_apply (first, second);
  787. default: return false;
  788. }
  789. }
  790. inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
  791. {
  792. TRACE_APPLY ();
  793. switch (lookup_type) {
  794. case Single: return TRACE_RETURN (u.single.apply (c));
  795. case Multiple: return TRACE_RETURN (u.multiple.apply (c));
  796. case Alternate: return TRACE_RETURN (u.alternate.apply (c));
  797. case Ligature: return TRACE_RETURN (u.ligature.apply (c));
  798. case Context: return TRACE_RETURN (u.c.apply (c));
  799. case ChainContext: return TRACE_RETURN (u.chainContext.apply (c));
  800. case Extension: return TRACE_RETURN (u.extension.apply (c));
  801. case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.apply (c));
  802. default: return TRACE_RETURN (false);
  803. }
  804. }
  805. inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
  806. TRACE_SANITIZE ();
  807. switch (lookup_type) {
  808. case Single: return TRACE_RETURN (u.single.sanitize (c));
  809. case Multiple: return TRACE_RETURN (u.multiple.sanitize (c));
  810. case Alternate: return TRACE_RETURN (u.alternate.sanitize (c));
  811. case Ligature: return TRACE_RETURN (u.ligature.sanitize (c));
  812. case Context: return TRACE_RETURN (u.c.sanitize (c));
  813. case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c));
  814. case Extension: return TRACE_RETURN (u.extension.sanitize (c));
  815. case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c));
  816. default: return TRACE_RETURN (true);
  817. }
  818. }
  819. private:
  820. union {
  821. USHORT sub_format;
  822. SingleSubst single;
  823. MultipleSubst multiple;
  824. AlternateSubst alternate;
  825. LigatureSubst ligature;
  826. ContextSubst c;
  827. ChainContextSubst chainContext;
  828. ExtensionSubst extension;
  829. ReverseChainSingleSubst reverseChainContextSingle;
  830. } u;
  831. public:
  832. DEFINE_SIZE_UNION (2, sub_format);
  833. };
  834. struct SubstLookup : Lookup
  835. {
  836. inline const SubstLookupSubTable& get_subtable (unsigned int i) const
  837. { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
  838. inline static bool lookup_type_is_reverse (unsigned int lookup_type)
  839. { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
  840. inline bool is_reverse (void) const
  841. {
  842. unsigned int type = get_type ();
  843. if (unlikely (type == SubstLookupSubTable::Extension))
  844. return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
  845. return lookup_type_is_reverse (type);
  846. }
  847. inline void closure (hb_closure_context_t *c) const
  848. {
  849. unsigned int lookup_type = get_type ();
  850. unsigned int count = get_subtable_count ();
  851. for (unsigned int i = 0; i < count; i++)
  852. get_subtable (i).closure (c, lookup_type);
  853. }
  854. inline bool would_apply (hb_codepoint_t glyph_id) const
  855. {
  856. unsigned int lookup_type = get_type ();
  857. unsigned int count = get_subtable_count ();
  858. for (unsigned int i = 0; i < count; i++)
  859. if (get_subtable (i).would_apply (glyph_id, lookup_type))
  860. return true;
  861. return false;
  862. }
  863. inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const
  864. {
  865. unsigned int lookup_type = get_type ();
  866. unsigned int count = get_subtable_count ();
  867. for (unsigned int i = 0; i < count; i++)
  868. if (get_subtable (i).would_apply (first, second, lookup_type))
  869. return true;
  870. return false;
  871. }
  872. inline bool apply_once (hb_apply_context_t *c) const
  873. {
  874. unsigned int lookup_type = get_type ();
  875. if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->cur(), c->lookup_props, &c->property))
  876. return false;
  877. if (unlikely (lookup_type == SubstLookupSubTable::Extension))
  878. {
  879. /* The spec says all subtables should have the same type.
  880. * This is specially important if one has a reverse type!
  881. *
  882. * This is rather slow to do this here for every glyph,
  883. * but it's easiest, and who uses extension lookups anyway?!*/
  884. unsigned int type = get_subtable(0).u.extension.get_type ();
  885. unsigned int count = get_subtable_count ();
  886. for (unsigned int i = 1; i < count; i++)
  887. if (get_subtable(i).u.extension.get_type () != type)
  888. return false;
  889. }
  890. unsigned int count = get_subtable_count ();
  891. for (unsigned int i = 0; i < count; i++)
  892. if (get_subtable (i).apply (c, lookup_type))
  893. return true;
  894. return false;
  895. }
  896. inline bool apply_string (hb_apply_context_t *c) const
  897. {
  898. bool ret = false;
  899. if (unlikely (!c->buffer->len))
  900. return false;
  901. c->set_lookup (*this);
  902. if (likely (!is_reverse ()))
  903. {
  904. /* in/out forward substitution */
  905. c->buffer->clear_output ();
  906. c->buffer->idx = 0;
  907. while (c->buffer->idx < c->buffer->len)
  908. {
  909. if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c))
  910. ret = true;
  911. else
  912. c->buffer->next_glyph ();
  913. }
  914. if (ret)
  915. c->buffer->swap_buffers ();
  916. }
  917. else
  918. {
  919. /* in-place backward substitution */
  920. c->buffer->idx = c->buffer->len - 1;
  921. do
  922. {
  923. if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c))
  924. ret = true;
  925. else
  926. c->buffer->idx--;
  927. }
  928. while ((int) c->buffer->idx >= 0);
  929. }
  930. return ret;
  931. }
  932. inline bool sanitize (hb_sanitize_context_t *c) {
  933. TRACE_SANITIZE ();
  934. if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
  935. OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
  936. return TRACE_RETURN (list.sanitize (c, this, get_type ()));
  937. }
  938. };
  939. typedef OffsetListOf<SubstLookup> SubstLookupList;
  940. /*
  941. * GSUB -- The Glyph Substitution Table
  942. */
  943. struct GSUB : GSUBGPOS
  944. {
  945. static const hb_tag_t Tag = HB_OT_TAG_GSUB;
  946. inline const SubstLookup& get_lookup (unsigned int i) const
  947. { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
  948. inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index) const
  949. { return get_lookup (lookup_index).apply_string (c); }
  950. static inline void substitute_start (hb_buffer_t *buffer);
  951. static inline void substitute_finish (hb_buffer_t *buffer);
  952. inline void closure_lookup (hb_closure_context_t *c,
  953. unsigned int lookup_index) const
  954. { return get_lookup (lookup_index).closure (c); }
  955. inline bool sanitize (hb_sanitize_context_t *c) {
  956. TRACE_SANITIZE ();
  957. if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
  958. OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
  959. return TRACE_RETURN (list.sanitize (c, this));
  960. }
  961. public:
  962. DEFINE_SIZE_STATIC (10);
  963. };
  964. void
  965. GSUB::substitute_start (hb_buffer_t *buffer)
  966. {
  967. HB_BUFFER_ALLOCATE_VAR (buffer, props_cache);
  968. HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
  969. HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
  970. unsigned int count = buffer->len;
  971. for (unsigned int i = 0; i < count; i++)
  972. buffer->info[i].props_cache() = buffer->info[i].lig_props() = buffer->info[i].syllable() = 0;
  973. }
  974. void
  975. GSUB::substitute_finish (hb_buffer_t *buffer HB_UNUSED)
  976. {
  977. }
  978. /* Out-of-class implementation for methods recursing */
  979. inline void ExtensionSubst::closure (hb_closure_context_t *c) const
  980. {
  981. get_subtable ().closure (c, get_type ());
  982. }
  983. inline bool ExtensionSubst::would_apply (hb_codepoint_t glyph_id) const
  984. {
  985. return get_subtable ().would_apply (glyph_id, get_type ());
  986. }
  987. inline bool ExtensionSubst::would_apply (hb_codepoint_t first, hb_codepoint_t second) const
  988. {
  989. return get_subtable ().would_apply (first, second, get_type ());
  990. }
  991. inline bool ExtensionSubst::apply (hb_apply_context_t *c) const
  992. {
  993. TRACE_APPLY ();
  994. return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
  995. }
  996. inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
  997. {
  998. TRACE_SANITIZE ();
  999. if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
  1000. unsigned int offset = get_offset ();
  1001. if (unlikely (!offset)) return TRACE_RETURN (true);
  1002. return TRACE_RETURN (StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ()));
  1003. }
  1004. inline bool ExtensionSubst::is_reverse (void) const
  1005. {
  1006. unsigned int type = get_type ();
  1007. if (unlikely (type == SubstLookupSubTable::Extension))
  1008. return CastR<ExtensionSubst> (get_subtable()).is_reverse ();
  1009. return SubstLookup::lookup_type_is_reverse (type);
  1010. }
  1011. static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index)
  1012. {
  1013. const GSUB &gsub = *(c->face->ot_layout->gsub);
  1014. const SubstLookup &l = gsub.get_lookup (lookup_index);
  1015. if (unlikely (c->nesting_level_left == 0))
  1016. return;
  1017. c->nesting_level_left--;
  1018. l.closure (c);
  1019. c->nesting_level_left++;
  1020. }
  1021. static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
  1022. {
  1023. const GSUB &gsub = *(c->face->ot_layout->gsub);
  1024. const SubstLookup &l = gsub.get_lookup (lookup_index);
  1025. if (unlikely (c->nesting_level_left == 0))
  1026. return false;
  1027. hb_apply_context_t new_c (*c);
  1028. new_c.nesting_level_left--;
  1029. new_c.set_lookup (l);
  1030. return l.apply_once (&new_c);
  1031. }
  1032. #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */