PageRenderTime 60ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/pango-1.30.0/pango/opentype/hb-ot-layout-gsub-private.hh

#
C++ Header | 909 lines | 665 code | 167 blank | 77 comment | 89 complexity | 1d9d25bce77a774018e301339b68a4fe MD5 | raw file
Possible License(s): LGPL-2.0
  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[VAR];
  120. SingleSubstFormat2 format2[VAR];
  121. } u;
  122. };
  123. struct Sequence
  124. {
  125. friend struct MultipleSubstFormat1;
  126. private:
  127. inline bool apply (APPLY_ARG_DEF) const
  128. {
  129. TRACE_APPLY ();
  130. if (HB_UNLIKELY (!substitute.len))
  131. return false;
  132. _hb_buffer_add_output_glyphs (buffer, 1,
  133. substitute.len, (const uint16_t *) substitute.const_array(),
  134. 0xFFFF, 0xFFFF);
  135. /* This is a guess only ... */
  136. if (_hb_ot_layout_has_new_glyph_classes (context->face))
  137. {
  138. if (property == HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)
  139. property = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
  140. unsigned int count = substitute.len;
  141. for (unsigned int n = 0; n < count; n++)
  142. _hb_ot_layout_set_glyph_property (context->face, substitute[n], property);
  143. }
  144. return true;
  145. }
  146. public:
  147. inline bool sanitize (SANITIZE_ARG_DEF) {
  148. TRACE_SANITIZE ();
  149. return SANITIZE (substitute);
  150. }
  151. private:
  152. ArrayOf<GlyphID>
  153. substitute; /* String of GlyphIDs to substitute */
  154. };
  155. ASSERT_SIZE (Sequence, 2);
  156. struct MultipleSubstFormat1
  157. {
  158. friend struct MultipleSubst;
  159. private:
  160. inline bool apply (APPLY_ARG_DEF) const
  161. {
  162. TRACE_APPLY ();
  163. unsigned int index = (this+coverage) (IN_CURGLYPH ());
  164. if (HB_LIKELY (index == NOT_COVERED))
  165. return false;
  166. return (this+sequence[index]).apply (APPLY_ARG);
  167. }
  168. inline bool sanitize (SANITIZE_ARG_DEF) {
  169. TRACE_SANITIZE ();
  170. return SANITIZE_THIS2 (coverage, sequence);
  171. }
  172. private:
  173. USHORT format; /* Format identifier--format = 1 */
  174. OffsetTo<Coverage>
  175. coverage; /* Offset to Coverage table--from
  176. * beginning of Substitution table */
  177. OffsetArrayOf<Sequence>
  178. sequence; /* Array of Sequence tables
  179. * ordered by Coverage Index */
  180. };
  181. ASSERT_SIZE (MultipleSubstFormat1, 6);
  182. struct MultipleSubst
  183. {
  184. friend struct SubstLookupSubTable;
  185. private:
  186. inline bool apply (APPLY_ARG_DEF) const
  187. {
  188. TRACE_APPLY ();
  189. switch (u.format) {
  190. case 1: return u.format1->apply (APPLY_ARG);
  191. default:return false;
  192. }
  193. }
  194. inline bool sanitize (SANITIZE_ARG_DEF) {
  195. TRACE_SANITIZE ();
  196. if (!SANITIZE (u.format)) return false;
  197. switch (u.format) {
  198. case 1: return u.format1->sanitize (SANITIZE_ARG);
  199. default:return true;
  200. }
  201. }
  202. private:
  203. union {
  204. USHORT format; /* Format identifier */
  205. MultipleSubstFormat1 format1[VAR];
  206. } u;
  207. };
  208. typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
  209. * arbitrary order */
  210. ASSERT_SIZE (AlternateSet, 2);
  211. struct AlternateSubstFormat1
  212. {
  213. friend struct AlternateSubst;
  214. private:
  215. inline bool apply (APPLY_ARG_DEF) const
  216. {
  217. TRACE_APPLY ();
  218. hb_codepoint_t glyph_id = IN_CURGLYPH ();
  219. unsigned int index = (this+coverage) (glyph_id);
  220. if (HB_LIKELY (index == NOT_COVERED))
  221. return false;
  222. const AlternateSet &alt_set = this+alternateSet[index];
  223. if (HB_UNLIKELY (!alt_set.len))
  224. return false;
  225. unsigned int alt_index = 0;
  226. /* XXX callback to user to choose alternate
  227. if (context->face->altfunc)
  228. alt_index = (context->face->altfunc)(context->layout, buffer,
  229. buffer->out_pos, glyph_id,
  230. alt_set.len, alt_set.array);
  231. */
  232. if (HB_UNLIKELY (alt_index >= alt_set.len))
  233. return false;
  234. glyph_id = alt_set[alt_index];
  235. _hb_buffer_replace_glyph (buffer, glyph_id);
  236. /* We inherit the old glyph class to the substituted glyph */
  237. if (_hb_ot_layout_has_new_glyph_classes (context->face))
  238. _hb_ot_layout_set_glyph_property (context->face, glyph_id, property);
  239. return true;
  240. }
  241. inline bool sanitize (SANITIZE_ARG_DEF) {
  242. TRACE_SANITIZE ();
  243. return SANITIZE_THIS2 (coverage, alternateSet);
  244. }
  245. private:
  246. USHORT format; /* Format identifier--format = 1 */
  247. OffsetTo<Coverage>
  248. coverage; /* Offset to Coverage table--from
  249. * beginning of Substitution table */
  250. OffsetArrayOf<AlternateSet>
  251. alternateSet; /* Array of AlternateSet tables
  252. * ordered by Coverage Index */
  253. };
  254. ASSERT_SIZE (AlternateSubstFormat1, 6);
  255. struct AlternateSubst
  256. {
  257. friend struct SubstLookupSubTable;
  258. private:
  259. inline bool apply (APPLY_ARG_DEF) const
  260. {
  261. TRACE_APPLY ();
  262. switch (u.format) {
  263. case 1: return u.format1->apply (APPLY_ARG);
  264. default:return false;
  265. }
  266. }
  267. inline bool sanitize (SANITIZE_ARG_DEF) {
  268. TRACE_SANITIZE ();
  269. if (!SANITIZE (u.format)) return false;
  270. switch (u.format) {
  271. case 1: return u.format1->sanitize (SANITIZE_ARG);
  272. default:return true;
  273. }
  274. }
  275. private:
  276. union {
  277. USHORT format; /* Format identifier */
  278. AlternateSubstFormat1 format1[VAR];
  279. } u;
  280. };
  281. struct Ligature
  282. {
  283. friend struct LigatureSet;
  284. private:
  285. inline bool apply (APPLY_ARG_DEF, bool is_mark) const
  286. {
  287. TRACE_APPLY ();
  288. unsigned int i, j;
  289. unsigned int count = component.len;
  290. unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length);
  291. if (HB_UNLIKELY (buffer->in_pos + count > end))
  292. return false;
  293. for (i = 1, j = buffer->in_pos + 1; i < count; i++, j++)
  294. {
  295. while (_hb_ot_layout_skip_mark (context->face, IN_INFO (j), lookup_flag, &property))
  296. {
  297. if (HB_UNLIKELY (j + count - i == end))
  298. return false;
  299. j++;
  300. }
  301. if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
  302. is_mark = FALSE;
  303. if (HB_LIKELY (IN_GLYPH (j) != component[i]))
  304. return false;
  305. }
  306. /* This is just a guess ... */
  307. if (_hb_ot_layout_has_new_glyph_classes (context->face))
  308. _hb_ot_layout_set_glyph_class (context->face, ligGlyph,
  309. is_mark ? HB_OT_LAYOUT_GLYPH_CLASS_MARK
  310. : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE);
  311. if (j == buffer->in_pos + i) /* No input glyphs skipped */
  312. /* We don't use a new ligature ID if there are no skipped
  313. glyphs and the ligature already has an ID. */
  314. _hb_buffer_add_output_glyphs (buffer, i,
  315. 1, (const uint16_t *) &ligGlyph,
  316. 0,
  317. IN_LIGID (buffer->in_pos) && !IN_COMPONENT (buffer->in_pos) ?
  318. 0xFFFF : _hb_buffer_allocate_lig_id (buffer));
  319. else
  320. {
  321. unsigned int lig_id = _hb_buffer_allocate_lig_id (buffer);
  322. _hb_buffer_add_output_glyph (buffer, ligGlyph, 0xFFFF, lig_id);
  323. /* Now we must do a second loop to copy the skipped glyphs to
  324. `out' and assign component values to it. We start with the
  325. glyph after the first component. Glyphs between component
  326. i and i+1 belong to component i. Together with the lig_id
  327. value it is later possible to check whether a specific
  328. component value really belongs to a given ligature. */
  329. for ( i = 1; i < count; i++ )
  330. {
  331. while (_hb_ot_layout_skip_mark (context->face, IN_CURINFO (), lookup_flag, NULL))
  332. _hb_buffer_add_output_glyph (buffer, IN_CURGLYPH (), i, lig_id);
  333. (buffer->in_pos)++;
  334. }
  335. }
  336. return true;
  337. }
  338. public:
  339. inline bool sanitize (SANITIZE_ARG_DEF) {
  340. TRACE_SANITIZE ();
  341. return SANITIZE2 (ligGlyph, component);
  342. }
  343. private:
  344. GlyphID ligGlyph; /* GlyphID of ligature to substitute */
  345. HeadlessArrayOf<GlyphID>
  346. component; /* Array of component GlyphIDs--start
  347. * with the second component--ordered
  348. * in writing direction */
  349. };
  350. ASSERT_SIZE (Ligature, 4);
  351. struct LigatureSet
  352. {
  353. friend struct LigatureSubstFormat1;
  354. private:
  355. inline bool apply (APPLY_ARG_DEF, bool is_mark) const
  356. {
  357. TRACE_APPLY ();
  358. unsigned int num_ligs = ligature.len;
  359. for (unsigned int i = 0; i < num_ligs; i++)
  360. {
  361. const Ligature &lig = this+ligature[i];
  362. if (lig.apply (APPLY_ARG, is_mark))
  363. return true;
  364. }
  365. return false;
  366. }
  367. public:
  368. inline bool sanitize (SANITIZE_ARG_DEF) {
  369. TRACE_SANITIZE ();
  370. return SANITIZE_THIS (ligature);
  371. }
  372. private:
  373. OffsetArrayOf<Ligature>
  374. ligature; /* Array LigatureSet tables
  375. * ordered by preference */
  376. };
  377. ASSERT_SIZE (LigatureSet, 2);
  378. struct LigatureSubstFormat1
  379. {
  380. friend struct LigatureSubst;
  381. private:
  382. inline bool apply (APPLY_ARG_DEF) const
  383. {
  384. TRACE_APPLY ();
  385. hb_codepoint_t glyph_id = IN_CURGLYPH ();
  386. bool first_is_mark = !!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
  387. unsigned int index = (this+coverage) (glyph_id);
  388. if (HB_LIKELY (index == NOT_COVERED))
  389. return false;
  390. const LigatureSet &lig_set = this+ligatureSet[index];
  391. return lig_set.apply (APPLY_ARG, first_is_mark);
  392. }
  393. inline bool sanitize (SANITIZE_ARG_DEF) {
  394. TRACE_SANITIZE ();
  395. return SANITIZE_THIS2 (coverage, ligatureSet);
  396. }
  397. private:
  398. USHORT format; /* Format identifier--format = 1 */
  399. OffsetTo<Coverage>
  400. coverage; /* Offset to Coverage table--from
  401. * beginning of Substitution table */
  402. OffsetArrayOf<LigatureSet>
  403. ligatureSet; /* Array LigatureSet tables
  404. * ordered by Coverage Index */
  405. };
  406. ASSERT_SIZE (LigatureSubstFormat1, 6);
  407. struct LigatureSubst
  408. {
  409. friend struct SubstLookupSubTable;
  410. private:
  411. inline bool apply (APPLY_ARG_DEF) const
  412. {
  413. TRACE_APPLY ();
  414. switch (u.format) {
  415. case 1: return u.format1->apply (APPLY_ARG);
  416. default:return false;
  417. }
  418. }
  419. inline bool sanitize (SANITIZE_ARG_DEF) {
  420. TRACE_SANITIZE ();
  421. if (!SANITIZE (u.format)) return false;
  422. switch (u.format) {
  423. case 1: return u.format1->sanitize (SANITIZE_ARG);
  424. default:return true;
  425. }
  426. }
  427. private:
  428. union {
  429. USHORT format; /* Format identifier */
  430. LigatureSubstFormat1 format1[VAR];
  431. } u;
  432. };
  433. static inline bool substitute_lookup (APPLY_ARG_DEF, unsigned int lookup_index);
  434. struct ContextSubst : Context
  435. {
  436. friend struct SubstLookupSubTable;
  437. private:
  438. inline bool apply (APPLY_ARG_DEF) const
  439. {
  440. TRACE_APPLY ();
  441. return Context::apply (APPLY_ARG, substitute_lookup);
  442. }
  443. };
  444. struct ChainContextSubst : ChainContext
  445. {
  446. friend struct SubstLookupSubTable;
  447. private:
  448. inline bool apply (APPLY_ARG_DEF) const
  449. {
  450. TRACE_APPLY ();
  451. return ChainContext::apply (APPLY_ARG, substitute_lookup);
  452. }
  453. };
  454. struct ExtensionSubst : Extension
  455. {
  456. friend struct SubstLookupSubTable;
  457. private:
  458. inline const struct SubstLookupSubTable& get_subtable (void) const
  459. { return CONST_CAST (SubstLookupSubTable, Extension::get_subtable (), 0); }
  460. inline bool apply (APPLY_ARG_DEF) const;
  461. inline bool sanitize (SANITIZE_ARG_DEF);
  462. };
  463. struct ReverseChainSingleSubstFormat1
  464. {
  465. friend struct ReverseChainSingleSubst;
  466. private:
  467. inline bool apply (APPLY_ARG_DEF) const
  468. {
  469. TRACE_APPLY ();
  470. if (HB_UNLIKELY (context_length != NO_CONTEXT))
  471. return false; /* No chaining to this type */
  472. unsigned int index = (this+coverage) (IN_CURGLYPH ());
  473. if (HB_LIKELY (index == NOT_COVERED))
  474. return false;
  475. const OffsetArrayOf<Coverage> &lookahead = CONST_NEXT (OffsetArrayOf<Coverage>, backtrack);
  476. const ArrayOf<GlyphID> &substitute = CONST_NEXT (ArrayOf<GlyphID>, lookahead);
  477. if (match_backtrack (APPLY_ARG,
  478. backtrack.len, (USHORT *) backtrack.const_array(),
  479. match_coverage, DECONST_CHARP(this)) &&
  480. match_lookahead (APPLY_ARG,
  481. lookahead.len, (USHORT *) lookahead.const_array(),
  482. match_coverage, DECONST_CHARP(this),
  483. 1))
  484. {
  485. IN_CURGLYPH () = substitute[index];
  486. buffer->in_pos--; /* Reverse! */
  487. return true;
  488. }
  489. return false;
  490. }
  491. inline bool sanitize (SANITIZE_ARG_DEF) {
  492. TRACE_SANITIZE ();
  493. if (!SANITIZE_THIS2 (coverage, backtrack))
  494. return false;
  495. OffsetArrayOf<Coverage> &lookahead = NEXT (OffsetArrayOf<Coverage>, backtrack);
  496. if (!SANITIZE_THIS (lookahead))
  497. return false;
  498. ArrayOf<GlyphID> &substitute = NEXT (ArrayOf<GlyphID>, lookahead);
  499. return SANITIZE (substitute);
  500. }
  501. private:
  502. USHORT format; /* Format identifier--format = 1 */
  503. OffsetTo<Coverage>
  504. coverage; /* Offset to Coverage table--from
  505. * beginning of table */
  506. OffsetArrayOf<Coverage>
  507. backtrack; /* Array of coverage tables
  508. * in backtracking sequence, in glyph
  509. * sequence order */
  510. OffsetArrayOf<Coverage>
  511. lookaheadX; /* Array of coverage tables
  512. * in lookahead sequence, in glyph
  513. * sequence order */
  514. ArrayOf<GlyphID>
  515. substituteX; /* Array of substitute
  516. * GlyphIDs--ordered by Coverage Index */
  517. };
  518. ASSERT_SIZE (ReverseChainSingleSubstFormat1, 10);
  519. struct ReverseChainSingleSubst
  520. {
  521. friend struct SubstLookupSubTable;
  522. private:
  523. inline bool apply (APPLY_ARG_DEF) const
  524. {
  525. TRACE_APPLY ();
  526. switch (u.format) {
  527. case 1: return u.format1->apply (APPLY_ARG);
  528. default:return false;
  529. }
  530. }
  531. inline bool sanitize (SANITIZE_ARG_DEF) {
  532. TRACE_SANITIZE ();
  533. if (!SANITIZE (u.format)) return false;
  534. switch (u.format) {
  535. case 1: return u.format1->sanitize (SANITIZE_ARG);
  536. default:return true;
  537. }
  538. }
  539. private:
  540. union {
  541. USHORT format; /* Format identifier */
  542. ReverseChainSingleSubstFormat1 format1[VAR];
  543. } u;
  544. };
  545. /*
  546. * SubstLookup
  547. */
  548. struct SubstLookupSubTable
  549. {
  550. friend struct SubstLookup;
  551. enum {
  552. Single = 1,
  553. Multiple = 2,
  554. Alternate = 3,
  555. Ligature = 4,
  556. Context = 5,
  557. ChainContext = 6,
  558. Extension = 7,
  559. ReverseChainSingle = 8
  560. };
  561. inline bool apply (APPLY_ARG_DEF, unsigned int lookup_type) const
  562. {
  563. TRACE_APPLY ();
  564. switch (lookup_type) {
  565. case Single: return u.single->apply (APPLY_ARG);
  566. case Multiple: return u.multiple->apply (APPLY_ARG);
  567. case Alternate: return u.alternate->apply (APPLY_ARG);
  568. case Ligature: return u.ligature->apply (APPLY_ARG);
  569. case Context: return u.context->apply (APPLY_ARG);
  570. case ChainContext: return u.chainContext->apply (APPLY_ARG);
  571. case Extension: return u.extension->apply (APPLY_ARG);
  572. case ReverseChainSingle: return u.reverseChainContextSingle->apply (APPLY_ARG);
  573. default:return false;
  574. }
  575. }
  576. inline bool sanitize (SANITIZE_ARG_DEF, unsigned int lookup_type) {
  577. TRACE_SANITIZE ();
  578. if (!SANITIZE (u.sub_format)) return false;
  579. switch (lookup_type) {
  580. case Single: return u.single->sanitize (SANITIZE_ARG);
  581. case Multiple: return u.multiple->sanitize (SANITIZE_ARG);
  582. case Alternate: return u.alternate->sanitize (SANITIZE_ARG);
  583. case Ligature: return u.ligature->sanitize (SANITIZE_ARG);
  584. case Context: return u.context->sanitize (SANITIZE_ARG);
  585. case ChainContext: return u.chainContext->sanitize (SANITIZE_ARG);
  586. case Extension: return u.extension->sanitize (SANITIZE_ARG);
  587. case ReverseChainSingle: return u.reverseChainContextSingle->sanitize (SANITIZE_ARG);
  588. default:return true;
  589. }
  590. }
  591. private:
  592. union {
  593. USHORT sub_format;
  594. SingleSubst single[VAR];
  595. MultipleSubst multiple[VAR];
  596. AlternateSubst alternate[VAR];
  597. LigatureSubst ligature[VAR];
  598. ContextSubst context[VAR];
  599. ChainContextSubst chainContext[VAR];
  600. ExtensionSubst extension[VAR];
  601. ReverseChainSingleSubst reverseChainContextSingle[VAR];
  602. } u;
  603. };
  604. struct SubstLookup : Lookup
  605. {
  606. inline const SubstLookupSubTable& get_subtable (unsigned int i) const
  607. { return CONST_CAST (SubstLookupSubTable, Lookup::get_subtable (i), 0); }
  608. /* Like get_type(), but looks through extension lookups.
  609. * Never returns Extension */
  610. inline unsigned int get_effective_type (void) const
  611. {
  612. unsigned int type = get_type ();
  613. if (HB_UNLIKELY (type == SubstLookupSubTable::Extension))
  614. {
  615. unsigned int count = get_subtable_count ();
  616. type = get_subtable(0).u.extension->get_type ();
  617. /* The spec says all subtables should have the same type.
  618. * This is specially important if one has a reverse type! */
  619. for (unsigned int i = 1; i < count; i++)
  620. if (get_subtable(i).u.extension->get_type () != type)
  621. return 0;
  622. }
  623. return type;
  624. }
  625. inline bool is_reverse (void) const
  626. { return HB_UNLIKELY (get_effective_type () == SubstLookupSubTable::ReverseChainSingle); }
  627. inline bool apply_once (hb_ot_layout_context_t *context,
  628. hb_buffer_t *buffer,
  629. unsigned int context_length,
  630. unsigned int nesting_level_left) const
  631. {
  632. unsigned int lookup_type = get_type ();
  633. unsigned int lookup_flag = get_flag ();
  634. unsigned int property;
  635. if (!_hb_ot_layout_check_glyph_property (context->face, IN_CURINFO (), lookup_flag, &property))
  636. return false;
  637. unsigned int count = get_subtable_count ();
  638. for (unsigned int i = 0; i < count; i++)
  639. if (get_subtable (i).apply (APPLY_ARG_INIT, lookup_type))
  640. return true;
  641. return false;
  642. }
  643. inline bool apply_string (hb_ot_layout_context_t *context,
  644. hb_buffer_t *buffer,
  645. hb_mask_t mask) const
  646. {
  647. bool ret = false;
  648. if (HB_UNLIKELY (!buffer->in_length))
  649. return false;
  650. if (HB_LIKELY (!is_reverse ()))
  651. {
  652. /* in/out forward substitution */
  653. _hb_buffer_clear_output (buffer);
  654. buffer->in_pos = 0;
  655. while (buffer->in_pos < buffer->in_length)
  656. {
  657. if ((~IN_MASK (buffer->in_pos) & mask) &&
  658. apply_once (context, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
  659. ret = true;
  660. else
  661. _hb_buffer_next_glyph (buffer);
  662. }
  663. if (ret)
  664. _hb_buffer_swap (buffer);
  665. }
  666. else
  667. {
  668. /* in-place backward substitution */
  669. buffer->in_pos = buffer->in_length - 1;
  670. do
  671. {
  672. if ((~IN_MASK (buffer->in_pos) & mask) &&
  673. apply_once (context, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
  674. ret = true;
  675. else
  676. buffer->in_pos--;
  677. }
  678. while ((int) buffer->in_pos >= 0);
  679. }
  680. return ret;
  681. }
  682. inline bool sanitize (SANITIZE_ARG_DEF) {
  683. TRACE_SANITIZE ();
  684. if (!Lookup::sanitize (SANITIZE_ARG)) return false;
  685. OffsetArrayOf<SubstLookupSubTable> &list = (OffsetArrayOf<SubstLookupSubTable> &) subTable;
  686. return list.sanitize (SANITIZE_ARG, this, get_type ());
  687. }
  688. };
  689. typedef OffsetListOf<SubstLookup> SubstLookupList;
  690. ASSERT_SIZE (SubstLookupList, 2);
  691. /*
  692. * GSUB
  693. */
  694. struct GSUB : GSUBGPOS
  695. {
  696. static const hb_tag_t Tag = HB_OT_TAG_GSUB;
  697. static inline const GSUB& get_for_data (const char *data)
  698. { return (const GSUB&) GSUBGPOS::get_for_data (data); }
  699. inline const SubstLookup& get_lookup (unsigned int i) const
  700. { return (const SubstLookup&) GSUBGPOS::get_lookup (i); }
  701. inline bool substitute_lookup (hb_ot_layout_context_t *context,
  702. hb_buffer_t *buffer,
  703. unsigned int lookup_index,
  704. hb_mask_t mask) const
  705. { return get_lookup (lookup_index).apply_string (context, buffer, mask); }
  706. inline bool sanitize (SANITIZE_ARG_DEF) {
  707. TRACE_SANITIZE ();
  708. if (!GSUBGPOS::sanitize (SANITIZE_ARG)) return false;
  709. OffsetTo<SubstLookupList> &list = CAST(OffsetTo<SubstLookupList>, lookupList, 0);
  710. return SANITIZE_THIS (list);
  711. }
  712. };
  713. ASSERT_SIZE (GSUB, 10);
  714. /* Out-of-class implementation for methods recursing */
  715. inline bool ExtensionSubst::apply (APPLY_ARG_DEF) const
  716. {
  717. TRACE_APPLY ();
  718. unsigned int lookup_type = get_type ();
  719. if (HB_UNLIKELY (lookup_type == SubstLookupSubTable::Extension))
  720. return false;
  721. return get_subtable ().apply (APPLY_ARG, lookup_type);
  722. }
  723. inline bool ExtensionSubst::sanitize (SANITIZE_ARG_DEF)
  724. {
  725. TRACE_SANITIZE ();
  726. return Extension::sanitize (SANITIZE_ARG) &&
  727. (&(Extension::get_subtable ()) == &Null(LookupSubTable) ||
  728. get_type () == SubstLookupSubTable::Extension ||
  729. DECONST_CAST (SubstLookupSubTable, get_subtable (), 0).sanitize (SANITIZE_ARG, get_type ()));
  730. }
  731. static inline bool substitute_lookup (APPLY_ARG_DEF, unsigned int lookup_index)
  732. {
  733. const GSUB &gsub = *(context->face->ot_layout.gsub);
  734. const SubstLookup &l = gsub.get_lookup (lookup_index);
  735. if (HB_UNLIKELY (nesting_level_left == 0))
  736. return false;
  737. nesting_level_left--;
  738. if (HB_UNLIKELY (context_length < 1))
  739. return false;
  740. return l.apply_once (context, buffer, context_length, nesting_level_left);
  741. }
  742. #endif /* HB_OT_LAYOUT_GSUB_PRIVATE_HH */