PageRenderTime 69ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/pango1.0/pango/opentype/hb-ot-layout-gsub-private.hh

https://review.tizen.org/git/
C++ Header | 923 lines | 675 code | 168 blank | 80 comment | 88 complexity | 6c1ca8bcc9f98d5ba99d2f621a7cecd9 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 (C) 2007,2008,2009 Red Hat, Inc.
  3. *
  4. * This is part of HarfBuzz, an OpenType Layout engine library.
  5. *
  6. * Permission is hereby granted, without written agreement and without
  7. * license or royalty fees, to use, copy, modify, and distribute this
  8. * software and its documentation for any purpose, provided that the
  9. * above copyright notice and the following two paragraphs appear in
  10. * all copies of this software.
  11. *
  12. * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  13. * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  14. * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
  15. * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  16. * DAMAGE.
  17. *
  18. * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  19. * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  20. * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
  21. * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  22. * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  23. *
  24. * Red Hat Author(s): Behdad Esfahbod
  25. */
  26. #ifndef HB_OT_LAYOUT_GSUB_PRIVATE_HH
  27. #define HB_OT_LAYOUT_GSUB_PRIVATE_HH
  28. #include "hb-ot-layout-gsubgpos-private.hh"
  29. struct SingleSubstFormat1
  30. {
  31. friend struct SingleSubst;
  32. private:
  33. inline bool apply (APPLY_ARG_DEF) const
  34. {
  35. TRACE_APPLY ();
  36. hb_codepoint_t glyph_id = IN_CURGLYPH ();
  37. unsigned int index = (this+coverage) (glyph_id);
  38. if (HB_LIKELY (index == NOT_COVERED))
  39. return false;
  40. glyph_id += deltaGlyphID;
  41. _hb_buffer_replace_glyph (buffer, glyph_id);
  42. /* We inherit the old glyph class to the substituted glyph */
  43. if (_hb_ot_layout_has_new_glyph_classes (context->face))
  44. _hb_ot_layout_set_glyph_property (context->face, glyph_id, property);
  45. return true;
  46. }
  47. inline bool sanitize (SANITIZE_ARG_DEF) {
  48. TRACE_SANITIZE ();
  49. return SANITIZE_THIS (coverage) && SANITIZE (deltaGlyphID);
  50. }
  51. private:
  52. USHORT format; /* Format identifier--format = 1 */
  53. OffsetTo<Coverage>
  54. coverage; /* Offset to Coverage table--from
  55. * beginning of Substitution table */
  56. SHORT deltaGlyphID; /* Add to original GlyphID to get
  57. * substitute GlyphID */
  58. };
  59. ASSERT_SIZE (SingleSubstFormat1, 6);
  60. struct SingleSubstFormat2
  61. {
  62. friend struct SingleSubst;
  63. private:
  64. inline bool apply (APPLY_ARG_DEF) const
  65. {
  66. TRACE_APPLY ();
  67. hb_codepoint_t glyph_id = IN_CURGLYPH ();
  68. unsigned int index = (this+coverage) (glyph_id);
  69. if (HB_LIKELY (index == NOT_COVERED))
  70. return false;
  71. if (HB_UNLIKELY (index >= substitute.len))
  72. return false;
  73. glyph_id = substitute[index];
  74. _hb_buffer_replace_glyph (buffer, glyph_id);
  75. /* We inherit the old glyph class to the substituted glyph */
  76. if (_hb_ot_layout_has_new_glyph_classes (context->face))
  77. _hb_ot_layout_set_glyph_property (context->face, glyph_id, property);
  78. return true;
  79. }
  80. inline bool sanitize (SANITIZE_ARG_DEF) {
  81. TRACE_SANITIZE ();
  82. return SANITIZE_THIS (coverage) && SANITIZE (substitute);
  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. };
  93. ASSERT_SIZE (SingleSubstFormat2, 6);
  94. struct SingleSubst
  95. {
  96. friend struct SubstLookupSubTable;
  97. private:
  98. inline bool apply (APPLY_ARG_DEF) const
  99. {
  100. TRACE_APPLY ();
  101. switch (u.format) {
  102. case 1: return u.format1->apply (APPLY_ARG);
  103. case 2: return u.format2->apply (APPLY_ARG);
  104. default:return false;
  105. }
  106. }
  107. inline bool sanitize (SANITIZE_ARG_DEF) {
  108. TRACE_SANITIZE ();
  109. if (!SANITIZE (u.format)) return false;
  110. switch (u.format) {
  111. case 1: return u.format1->sanitize (SANITIZE_ARG);
  112. case 2: return u.format2->sanitize (SANITIZE_ARG);
  113. default:return true;
  114. }
  115. }
  116. private:
  117. union {
  118. USHORT format; /* Format identifier */
  119. SingleSubstFormat1 format1[];
  120. SingleSubstFormat2 format2[];
  121. } u;
  122. };
  123. ASSERT_SIZE (SingleSubst, 2);
  124. struct Sequence
  125. {
  126. friend struct MultipleSubstFormat1;
  127. private:
  128. inline bool apply (APPLY_ARG_DEF) const
  129. {
  130. TRACE_APPLY ();
  131. if (HB_UNLIKELY (!substitute.len))
  132. return false;
  133. _hb_buffer_add_output_glyphs (buffer, 1,
  134. substitute.len, (const uint16_t *) substitute.array,
  135. 0xFFFF, 0xFFFF);
  136. /* This is a guess only ... */
  137. if (_hb_ot_layout_has_new_glyph_classes (context->face))
  138. {
  139. if (property == HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)
  140. property = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
  141. unsigned int count = substitute.len;
  142. for (unsigned int n = 0; n < count; n++)
  143. _hb_ot_layout_set_glyph_property (context->face, substitute[n], property);
  144. }
  145. return true;
  146. }
  147. public:
  148. inline bool sanitize (SANITIZE_ARG_DEF) {
  149. TRACE_SANITIZE ();
  150. return SANITIZE (substitute);
  151. }
  152. private:
  153. ArrayOf<GlyphID>
  154. substitute; /* String of GlyphIDs to substitute */
  155. };
  156. ASSERT_SIZE (Sequence, 2);
  157. struct MultipleSubstFormat1
  158. {
  159. friend struct MultipleSubst;
  160. private:
  161. inline bool apply (APPLY_ARG_DEF) const
  162. {
  163. TRACE_APPLY ();
  164. unsigned int index = (this+coverage) (IN_CURGLYPH ());
  165. if (HB_LIKELY (index == NOT_COVERED))
  166. return false;
  167. return (this+sequence[index]).apply (APPLY_ARG);
  168. }
  169. inline bool sanitize (SANITIZE_ARG_DEF) {
  170. TRACE_SANITIZE ();
  171. return SANITIZE_THIS2 (coverage, sequence);
  172. }
  173. private:
  174. USHORT format; /* Format identifier--format = 1 */
  175. OffsetTo<Coverage>
  176. coverage; /* Offset to Coverage table--from
  177. * beginning of Substitution table */
  178. OffsetArrayOf<Sequence>
  179. sequence; /* Array of Sequence tables
  180. * ordered by Coverage Index */
  181. };
  182. ASSERT_SIZE (MultipleSubstFormat1, 6);
  183. struct MultipleSubst
  184. {
  185. friend struct SubstLookupSubTable;
  186. private:
  187. inline bool apply (APPLY_ARG_DEF) const
  188. {
  189. TRACE_APPLY ();
  190. switch (u.format) {
  191. case 1: return u.format1->apply (APPLY_ARG);
  192. default:return false;
  193. }
  194. }
  195. inline bool sanitize (SANITIZE_ARG_DEF) {
  196. TRACE_SANITIZE ();
  197. if (!SANITIZE (u.format)) return false;
  198. switch (u.format) {
  199. case 1: return u.format1->sanitize (SANITIZE_ARG);
  200. default:return true;
  201. }
  202. }
  203. private:
  204. union {
  205. USHORT format; /* Format identifier */
  206. MultipleSubstFormat1 format1[];
  207. } u;
  208. };
  209. ASSERT_SIZE (MultipleSubst, 2);
  210. typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
  211. * arbitrary order */
  212. ASSERT_SIZE (AlternateSet, 2);
  213. struct AlternateSubstFormat1
  214. {
  215. friend struct AlternateSubst;
  216. private:
  217. inline bool apply (APPLY_ARG_DEF) const
  218. {
  219. TRACE_APPLY ();
  220. hb_codepoint_t glyph_id = IN_CURGLYPH ();
  221. unsigned int index = (this+coverage) (glyph_id);
  222. if (HB_LIKELY (index == NOT_COVERED))
  223. return false;
  224. const AlternateSet &alt_set = this+alternateSet[index];
  225. if (HB_UNLIKELY (!alt_set.len))
  226. return false;
  227. unsigned int alt_index = 0;
  228. /* XXX callback to user to choose alternate
  229. if (context->face->altfunc)
  230. alt_index = (context->face->altfunc)(context->layout, buffer,
  231. buffer->out_pos, glyph_id,
  232. alt_set.len, alt_set.array);
  233. */
  234. if (HB_UNLIKELY (alt_index >= alt_set.len))
  235. return false;
  236. glyph_id = alt_set[alt_index];
  237. _hb_buffer_replace_glyph (buffer, glyph_id);
  238. /* We inherit the old glyph class to the substituted glyph */
  239. if (_hb_ot_layout_has_new_glyph_classes (context->face))
  240. _hb_ot_layout_set_glyph_property (context->face, glyph_id, property);
  241. return true;
  242. }
  243. inline bool sanitize (SANITIZE_ARG_DEF) {
  244. TRACE_SANITIZE ();
  245. return SANITIZE_THIS2 (coverage, alternateSet);
  246. }
  247. private:
  248. USHORT format; /* Format identifier--format = 1 */
  249. OffsetTo<Coverage>
  250. coverage; /* Offset to Coverage table--from
  251. * beginning of Substitution table */
  252. OffsetArrayOf<AlternateSet>
  253. alternateSet; /* Array of AlternateSet tables
  254. * ordered by Coverage Index */
  255. };
  256. ASSERT_SIZE (AlternateSubstFormat1, 6);
  257. struct AlternateSubst
  258. {
  259. friend struct SubstLookupSubTable;
  260. private:
  261. inline bool apply (APPLY_ARG_DEF) const
  262. {
  263. TRACE_APPLY ();
  264. switch (u.format) {
  265. case 1: return u.format1->apply (APPLY_ARG);
  266. default:return false;
  267. }
  268. }
  269. inline bool sanitize (SANITIZE_ARG_DEF) {
  270. TRACE_SANITIZE ();
  271. if (!SANITIZE (u.format)) return false;
  272. switch (u.format) {
  273. case 1: return u.format1->sanitize (SANITIZE_ARG);
  274. default:return true;
  275. }
  276. }
  277. private:
  278. union {
  279. USHORT format; /* Format identifier */
  280. AlternateSubstFormat1 format1[];
  281. } u;
  282. };
  283. ASSERT_SIZE (AlternateSubst, 2);
  284. struct Ligature
  285. {
  286. friend struct LigatureSet;
  287. private:
  288. inline bool apply (APPLY_ARG_DEF, bool is_mark) const
  289. {
  290. TRACE_APPLY ();
  291. unsigned int i, j;
  292. unsigned int count = component.len;
  293. unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length);
  294. if (HB_UNLIKELY (buffer->in_pos + count > end))
  295. return false;
  296. for (i = 1, j = buffer->in_pos + 1; i < count; i++, j++)
  297. {
  298. while (_hb_ot_layout_skip_mark (context->face, IN_INFO (j), lookup_flag, &property))
  299. {
  300. if (HB_UNLIKELY (j + count - i == end))
  301. return false;
  302. j++;
  303. }
  304. if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
  305. is_mark = FALSE;
  306. if (HB_LIKELY (IN_GLYPH (j) != component[i]))
  307. return false;
  308. }
  309. /* This is just a guess ... */
  310. if (_hb_ot_layout_has_new_glyph_classes (context->face))
  311. _hb_ot_layout_set_glyph_class (context->face, ligGlyph,
  312. is_mark ? HB_OT_LAYOUT_GLYPH_CLASS_MARK
  313. : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE);
  314. if (j == buffer->in_pos + i) /* No input glyphs skipped */
  315. /* We don't use a new ligature ID if there are no skipped
  316. glyphs and the ligature already has an ID. */
  317. _hb_buffer_add_output_glyphs (buffer, i,
  318. 1, (const uint16_t *) &ligGlyph,
  319. 0xFFFF,
  320. IN_LIGID (buffer->in_pos) ?
  321. 0xFFFF : _hb_buffer_allocate_lig_id (buffer));
  322. else
  323. {
  324. unsigned int lig_id = _hb_buffer_allocate_lig_id (buffer);
  325. _hb_buffer_add_output_glyph (buffer, ligGlyph, 0xFFFF, lig_id);
  326. /* Now we must do a second loop to copy the skipped glyphs to
  327. `out' and assign component values to it. We start with the
  328. glyph after the first component. Glyphs between component
  329. i and i+1 belong to component i. Together with the lig_id
  330. value it is later possible to check whether a specific
  331. component value really belongs to a given ligature. */
  332. for ( i = 1; i < count; i++ )
  333. {
  334. while (_hb_ot_layout_skip_mark (context->face, IN_CURINFO (), lookup_flag, NULL))
  335. _hb_buffer_add_output_glyph (buffer, IN_CURGLYPH (), i - 1, lig_id);
  336. (buffer->in_pos)++;
  337. }
  338. /* TODO We should possibly reassign lig_id and component for any
  339. * components of a previous ligature that s now being removed as part of
  340. * this ligature. */
  341. }
  342. return true;
  343. }
  344. public:
  345. inline bool sanitize (SANITIZE_ARG_DEF) {
  346. TRACE_SANITIZE ();
  347. return SANITIZE2 (ligGlyph, component);
  348. }
  349. private:
  350. GlyphID ligGlyph; /* GlyphID of ligature to substitute */
  351. HeadlessArrayOf<GlyphID>
  352. component; /* Array of component GlyphIDs--start
  353. * with the second component--ordered
  354. * in writing direction */
  355. };
  356. ASSERT_SIZE (Ligature, 4);
  357. struct LigatureSet
  358. {
  359. friend struct LigatureSubstFormat1;
  360. private:
  361. inline bool apply (APPLY_ARG_DEF, bool is_mark) const
  362. {
  363. TRACE_APPLY ();
  364. unsigned int num_ligs = ligature.len;
  365. for (unsigned int i = 0; i < num_ligs; i++)
  366. {
  367. const Ligature &lig = this+ligature[i];
  368. if (lig.apply (APPLY_ARG, is_mark))
  369. return true;
  370. }
  371. return false;
  372. }
  373. public:
  374. inline bool sanitize (SANITIZE_ARG_DEF) {
  375. TRACE_SANITIZE ();
  376. return SANITIZE_THIS (ligature);
  377. }
  378. private:
  379. OffsetArrayOf<Ligature>
  380. ligature; /* Array LigatureSet tables
  381. * ordered by preference */
  382. };
  383. ASSERT_SIZE (LigatureSet, 2);
  384. struct LigatureSubstFormat1
  385. {
  386. friend struct LigatureSubst;
  387. private:
  388. inline bool apply (APPLY_ARG_DEF) const
  389. {
  390. TRACE_APPLY ();
  391. hb_codepoint_t glyph_id = IN_CURGLYPH ();
  392. bool first_is_mark = !!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
  393. unsigned int index = (this+coverage) (glyph_id);
  394. if (HB_LIKELY (index == NOT_COVERED))
  395. return false;
  396. const LigatureSet &lig_set = this+ligatureSet[index];
  397. return lig_set.apply (APPLY_ARG, first_is_mark);
  398. }
  399. inline bool sanitize (SANITIZE_ARG_DEF) {
  400. TRACE_SANITIZE ();
  401. return SANITIZE_THIS2 (coverage, ligatureSet);
  402. }
  403. private:
  404. USHORT format; /* Format identifier--format = 1 */
  405. OffsetTo<Coverage>
  406. coverage; /* Offset to Coverage table--from
  407. * beginning of Substitution table */
  408. OffsetArrayOf<LigatureSet>
  409. ligatureSet; /* Array LigatureSet tables
  410. * ordered by Coverage Index */
  411. };
  412. ASSERT_SIZE (LigatureSubstFormat1, 6);
  413. struct LigatureSubst
  414. {
  415. friend struct SubstLookupSubTable;
  416. private:
  417. inline bool apply (APPLY_ARG_DEF) const
  418. {
  419. TRACE_APPLY ();
  420. switch (u.format) {
  421. case 1: return u.format1->apply (APPLY_ARG);
  422. default:return false;
  423. }
  424. }
  425. inline bool sanitize (SANITIZE_ARG_DEF) {
  426. TRACE_SANITIZE ();
  427. if (!SANITIZE (u.format)) return false;
  428. switch (u.format) {
  429. case 1: return u.format1->sanitize (SANITIZE_ARG);
  430. default:return true;
  431. }
  432. }
  433. private:
  434. union {
  435. USHORT format; /* Format identifier */
  436. LigatureSubstFormat1 format1[];
  437. } u;
  438. };
  439. ASSERT_SIZE (LigatureSubst, 2);
  440. static inline bool substitute_lookup (APPLY_ARG_DEF, unsigned int lookup_index);
  441. struct ContextSubst : Context
  442. {
  443. friend struct SubstLookupSubTable;
  444. private:
  445. inline bool apply (APPLY_ARG_DEF) const
  446. {
  447. TRACE_APPLY ();
  448. return Context::apply (APPLY_ARG, substitute_lookup);
  449. }
  450. };
  451. ASSERT_SIZE (ContextSubst, 2);
  452. struct ChainContextSubst : ChainContext
  453. {
  454. friend struct SubstLookupSubTable;
  455. private:
  456. inline bool apply (APPLY_ARG_DEF) const
  457. {
  458. TRACE_APPLY ();
  459. return ChainContext::apply (APPLY_ARG, substitute_lookup);
  460. }
  461. };
  462. ASSERT_SIZE (ChainContextSubst, 2);
  463. struct ExtensionSubst : Extension
  464. {
  465. friend struct SubstLookupSubTable;
  466. private:
  467. inline const struct SubstLookupSubTable& get_subtable (void) const
  468. { return CONST_CAST (SubstLookupSubTable, Extension::get_subtable (), 0); }
  469. inline bool apply (APPLY_ARG_DEF) const;
  470. inline bool sanitize (SANITIZE_ARG_DEF);
  471. };
  472. ASSERT_SIZE (ExtensionSubst, 2);
  473. struct ReverseChainSingleSubstFormat1
  474. {
  475. friend struct ReverseChainSingleSubst;
  476. private:
  477. inline bool apply (APPLY_ARG_DEF) const
  478. {
  479. TRACE_APPLY ();
  480. if (HB_UNLIKELY (context_length != NO_CONTEXT))
  481. return false; /* No chaining to this type */
  482. unsigned int index = (this+coverage) (IN_CURGLYPH ());
  483. if (HB_LIKELY (index == NOT_COVERED))
  484. return false;
  485. const OffsetArrayOf<Coverage> &lookahead = CONST_NEXT (OffsetArrayOf<Coverage>, backtrack);
  486. const ArrayOf<GlyphID> &substitute = CONST_NEXT (ArrayOf<GlyphID>, lookahead);
  487. if (match_backtrack (APPLY_ARG,
  488. backtrack.len, (USHORT *) backtrack.array,
  489. match_coverage, DECONST_CHARP(this)) &&
  490. match_lookahead (APPLY_ARG,
  491. lookahead.len, (USHORT *) lookahead.array,
  492. match_coverage, DECONST_CHARP(this),
  493. 1))
  494. {
  495. IN_CURGLYPH () = substitute[index];
  496. buffer->in_pos--; /* Reverse! */
  497. return true;
  498. }
  499. return false;
  500. }
  501. inline bool sanitize (SANITIZE_ARG_DEF) {
  502. TRACE_SANITIZE ();
  503. if (!SANITIZE_THIS2 (coverage, backtrack))
  504. return false;
  505. OffsetArrayOf<Coverage> &lookahead = NEXT (OffsetArrayOf<Coverage>, backtrack);
  506. if (!SANITIZE_THIS (lookahead))
  507. return false;
  508. ArrayOf<GlyphID> &substitute = NEXT (ArrayOf<GlyphID>, lookahead);
  509. return SANITIZE (substitute);
  510. }
  511. private:
  512. USHORT format; /* Format identifier--format = 1 */
  513. OffsetTo<Coverage>
  514. coverage; /* Offset to Coverage table--from
  515. * beginning of table */
  516. OffsetArrayOf<Coverage>
  517. backtrack; /* Array of coverage tables
  518. * in backtracking sequence, in glyph
  519. * sequence order */
  520. OffsetArrayOf<Coverage>
  521. lookaheadX; /* Array of coverage tables
  522. * in lookahead sequence, in glyph
  523. * sequence order */
  524. ArrayOf<GlyphID>
  525. substituteX; /* Array of substitute
  526. * GlyphIDs--ordered by Coverage Index */
  527. };
  528. ASSERT_SIZE (ReverseChainSingleSubstFormat1, 10);
  529. struct ReverseChainSingleSubst
  530. {
  531. friend struct SubstLookupSubTable;
  532. private:
  533. inline bool apply (APPLY_ARG_DEF) const
  534. {
  535. TRACE_APPLY ();
  536. switch (u.format) {
  537. case 1: return u.format1->apply (APPLY_ARG);
  538. default:return false;
  539. }
  540. }
  541. inline bool sanitize (SANITIZE_ARG_DEF) {
  542. TRACE_SANITIZE ();
  543. if (!SANITIZE (u.format)) return false;
  544. switch (u.format) {
  545. case 1: return u.format1->sanitize (SANITIZE_ARG);
  546. default:return true;
  547. }
  548. }
  549. private:
  550. union {
  551. USHORT format; /* Format identifier */
  552. ReverseChainSingleSubstFormat1 format1[];
  553. } u;
  554. };
  555. ASSERT_SIZE (ReverseChainSingleSubst, 2);
  556. /*
  557. * SubstLookup
  558. */
  559. struct SubstLookupSubTable
  560. {
  561. friend struct SubstLookup;
  562. enum {
  563. Single = 1,
  564. Multiple = 2,
  565. Alternate = 3,
  566. Ligature = 4,
  567. Context = 5,
  568. ChainContext = 6,
  569. Extension = 7,
  570. ReverseChainSingle = 8
  571. };
  572. inline bool apply (APPLY_ARG_DEF, unsigned int lookup_type) const
  573. {
  574. TRACE_APPLY ();
  575. switch (lookup_type) {
  576. case Single: return u.single->apply (APPLY_ARG);
  577. case Multiple: return u.multiple->apply (APPLY_ARG);
  578. case Alternate: return u.alternate->apply (APPLY_ARG);
  579. case Ligature: return u.ligature->apply (APPLY_ARG);
  580. case Context: return u.context->apply (APPLY_ARG);
  581. case ChainContext: return u.chainContext->apply (APPLY_ARG);
  582. case Extension: return u.extension->apply (APPLY_ARG);
  583. case ReverseChainSingle: return u.reverseChainContextSingle->apply (APPLY_ARG);
  584. default:return false;
  585. }
  586. }
  587. inline bool sanitize (SANITIZE_ARG_DEF) {
  588. TRACE_SANITIZE ();
  589. if (!SANITIZE (u.format)) return false;
  590. switch (u.format) {
  591. case Single: return u.single->sanitize (SANITIZE_ARG);
  592. case Multiple: return u.multiple->sanitize (SANITIZE_ARG);
  593. case Alternate: return u.alternate->sanitize (SANITIZE_ARG);
  594. case Ligature: return u.ligature->sanitize (SANITIZE_ARG);
  595. case Context: return u.context->sanitize (SANITIZE_ARG);
  596. case ChainContext: return u.chainContext->sanitize (SANITIZE_ARG);
  597. case Extension: return u.extension->sanitize (SANITIZE_ARG);
  598. case ReverseChainSingle: return u.reverseChainContextSingle->sanitize (SANITIZE_ARG);
  599. default:return true;
  600. }
  601. }
  602. private:
  603. union {
  604. USHORT format;
  605. SingleSubst single[];
  606. MultipleSubst multiple[];
  607. AlternateSubst alternate[];
  608. LigatureSubst ligature[];
  609. ContextSubst context[];
  610. ChainContextSubst chainContext[];
  611. ExtensionSubst extension[];
  612. ReverseChainSingleSubst reverseChainContextSingle[];
  613. } u;
  614. };
  615. ASSERT_SIZE (SubstLookupSubTable, 2);
  616. struct SubstLookup : Lookup
  617. {
  618. inline const SubstLookupSubTable& get_subtable (unsigned int i) const
  619. { return CONST_CAST (SubstLookupSubTable, Lookup::get_subtable (i), 0); }
  620. /* Like get_type(), but looks through extension lookups.
  621. * Never returns Extension */
  622. inline unsigned int get_effective_type (void) const
  623. {
  624. unsigned int type = get_type ();
  625. if (HB_UNLIKELY (type == SubstLookupSubTable::Extension))
  626. {
  627. unsigned int count = get_subtable_count ();
  628. type = get_subtable(0).u.extension->get_type ();
  629. /* The spec says all subtables should have the same type.
  630. * This is specially important if one has a reverse type! */
  631. for (unsigned int i = 1; i < count; i++)
  632. if (get_subtable(i).u.extension->get_type () != type)
  633. return 0;
  634. }
  635. return type;
  636. }
  637. inline bool is_reverse (void) const
  638. { return HB_UNLIKELY (get_effective_type () == SubstLookupSubTable::ReverseChainSingle); }
  639. inline bool apply_once (hb_ot_layout_context_t *context,
  640. hb_buffer_t *buffer,
  641. unsigned int context_length,
  642. unsigned int nesting_level_left) const
  643. {
  644. unsigned int lookup_type = get_type ();
  645. unsigned int lookup_flag = get_flag ();
  646. unsigned int property;
  647. if (!_hb_ot_layout_check_glyph_property (context->face, IN_CURINFO (), lookup_flag, &property))
  648. return false;
  649. unsigned int count = get_subtable_count ();
  650. for (unsigned int i = 0; i < count; i++)
  651. if (get_subtable (i).apply (APPLY_ARG_INIT, lookup_type))
  652. return true;
  653. return false;
  654. }
  655. inline bool apply_string (hb_ot_layout_context_t *context,
  656. hb_buffer_t *buffer,
  657. hb_mask_t mask) const
  658. {
  659. bool ret = false;
  660. if (HB_UNLIKELY (!buffer->in_length))
  661. return false;
  662. if (HB_LIKELY (!is_reverse ()))
  663. {
  664. /* in/out forward substitution */
  665. _hb_buffer_clear_output (buffer);
  666. buffer->in_pos = 0;
  667. while (buffer->in_pos < buffer->in_length)
  668. {
  669. if ((~IN_MASK (buffer->in_pos) & mask) &&
  670. apply_once (context, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
  671. ret = true;
  672. else
  673. _hb_buffer_next_glyph (buffer);
  674. }
  675. if (ret)
  676. _hb_buffer_swap (buffer);
  677. }
  678. else
  679. {
  680. /* in-place backward substitution */
  681. buffer->in_pos = buffer->in_length - 1;
  682. do
  683. {
  684. if ((~IN_MASK (buffer->in_pos) & mask) &&
  685. apply_once (context, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
  686. ret = true;
  687. else
  688. buffer->in_pos--;
  689. }
  690. while ((int) buffer->in_pos >= 0);
  691. }
  692. return ret;
  693. }
  694. inline bool sanitize (SANITIZE_ARG_DEF) {
  695. TRACE_SANITIZE ();
  696. if (!Lookup::sanitize (SANITIZE_ARG)) return false;
  697. OffsetArrayOf<SubstLookupSubTable> &list = (OffsetArrayOf<SubstLookupSubTable> &) subTable;
  698. return SANITIZE_THIS (list);
  699. }
  700. };
  701. ASSERT_SIZE (SubstLookup, 6);
  702. typedef OffsetListOf<SubstLookup> SubstLookupList;
  703. ASSERT_SIZE (SubstLookupList, 2);
  704. /*
  705. * GSUB
  706. */
  707. struct GSUB : GSUBGPOS
  708. {
  709. static const hb_tag_t Tag = HB_OT_TAG_GSUB;
  710. static inline const GSUB& get_for_data (const char *data)
  711. { return (const GSUB&) GSUBGPOS::get_for_data (data); }
  712. inline const SubstLookup& get_lookup (unsigned int i) const
  713. { return (const SubstLookup&) GSUBGPOS::get_lookup (i); }
  714. inline bool substitute_lookup (hb_ot_layout_context_t *context,
  715. hb_buffer_t *buffer,
  716. unsigned int lookup_index,
  717. hb_mask_t mask) const
  718. { return get_lookup (lookup_index).apply_string (context, buffer, mask); }
  719. inline bool sanitize (SANITIZE_ARG_DEF) {
  720. TRACE_SANITIZE ();
  721. if (!GSUBGPOS::sanitize (SANITIZE_ARG)) return false;
  722. OffsetTo<SubstLookupList> &list = CAST(OffsetTo<SubstLookupList>, lookupList, 0);
  723. return SANITIZE_THIS (list);
  724. }
  725. };
  726. ASSERT_SIZE (GSUB, 10);
  727. /* Out-of-class implementation for methods recursing */
  728. inline bool ExtensionSubst::apply (APPLY_ARG_DEF) const
  729. {
  730. TRACE_APPLY ();
  731. unsigned int lookup_type = get_type ();
  732. if (HB_UNLIKELY (lookup_type == SubstLookupSubTable::Extension))
  733. return false;
  734. return get_subtable ().apply (APPLY_ARG, lookup_type);
  735. }
  736. inline bool ExtensionSubst::sanitize (SANITIZE_ARG_DEF)
  737. {
  738. TRACE_SANITIZE ();
  739. return Extension::sanitize (SANITIZE_ARG) &&
  740. (&(Extension::get_subtable ()) == &Null(LookupSubTable) ||
  741. get_type () == SubstLookupSubTable::Extension ||
  742. DECONST_CAST (SubstLookupSubTable, get_subtable (), 0).sanitize (SANITIZE_ARG));
  743. }
  744. static inline bool substitute_lookup (APPLY_ARG_DEF, unsigned int lookup_index)
  745. {
  746. const GSUB &gsub = *(context->face->ot_layout.gsub);
  747. const SubstLookup &l = gsub.get_lookup (lookup_index);
  748. if (HB_UNLIKELY (nesting_level_left == 0))
  749. return false;
  750. nesting_level_left--;
  751. if (HB_UNLIKELY (context_length < 1))
  752. return false;
  753. return l.apply_once (context, buffer, context_length, nesting_level_left);
  754. }
  755. #endif /* HB_OT_LAYOUT_GSUB_PRIVATE_HH */