LCOV - code coverage report
Current view: top level - gfx/harfbuzz/src - hb-ot-layout-gsub-table.hh (source / functions) Hit Total Coverage
Test: output.info Lines: 163 542 30.1 %
Date: 2017-07-14 16:53:18 Functions: 46 124 37.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
       3             :  * Copyright © 2010,2012,2013  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             : 
      29             : #ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
      30             : #define HB_OT_LAYOUT_GSUB_TABLE_HH
      31             : 
      32             : #include "hb-ot-layout-gsubgpos-private.hh"
      33             : 
      34             : 
      35             : namespace OT {
      36             : 
      37             : 
      38             : struct SingleSubstFormat1
      39             : {
      40           0 :   inline void closure (hb_closure_context_t *c) const
      41             :   {
      42           0 :     TRACE_CLOSURE (this);
      43           0 :     Coverage::Iter iter;
      44           0 :     for (iter.init (this+coverage); iter.more (); iter.next ())
      45             :     {
      46             :       /* TODO Switch to range-based API to work around malicious fonts.
      47             :        * https://github.com/behdad/harfbuzz/issues/363 */
      48           0 :       hb_codepoint_t glyph_id = iter.get_glyph ();
      49           0 :       if (c->glyphs->has (glyph_id))
      50           0 :         c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
      51             :     }
      52           0 :   }
      53             : 
      54          14 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
      55             :   {
      56          14 :     TRACE_COLLECT_GLYPHS (this);
      57          14 :     Coverage::Iter iter;
      58          82 :     for (iter.init (this+coverage); iter.more (); iter.next ())
      59             :     {
      60             :       /* TODO Switch to range-based API to work around malicious fonts.
      61             :        * https://github.com/behdad/harfbuzz/issues/363 */
      62          68 :       hb_codepoint_t glyph_id = iter.get_glyph ();
      63          68 :       c->input->add (glyph_id);
      64          68 :       c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
      65             :     }
      66          14 :   }
      67             : 
      68          20 :   inline const Coverage &get_coverage (void) const
      69             :   {
      70          20 :     return this+coverage;
      71             :   }
      72             : 
      73           0 :   inline bool would_apply (hb_would_apply_context_t *c) const
      74             :   {
      75           0 :     TRACE_WOULD_APPLY (this);
      76           0 :     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
      77             :   }
      78             : 
      79           0 :   inline bool apply (hb_apply_context_t *c) const
      80             :   {
      81           0 :     TRACE_APPLY (this);
      82           0 :     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
      83           0 :     unsigned int index = (this+coverage).get_coverage (glyph_id);
      84           0 :     if (likely (index == NOT_COVERED)) return_trace (false);
      85             : 
      86             :     /* According to the Adobe Annotated OpenType Suite, result is always
      87             :      * limited to 16bit. */
      88           0 :     glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
      89           0 :     c->replace_glyph (glyph_id);
      90             : 
      91           0 :     return_trace (true);
      92             :   }
      93             : 
      94           0 :   inline bool serialize (hb_serialize_context_t *c,
      95             :                          Supplier<GlyphID> &glyphs,
      96             :                          unsigned int num_glyphs,
      97             :                          int delta)
      98             :   {
      99           0 :     TRACE_SERIALIZE (this);
     100           0 :     if (unlikely (!c->extend_min (*this))) return_trace (false);
     101           0 :     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
     102           0 :     deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
     103           0 :     return_trace (true);
     104             :   }
     105             : 
     106          20 :   inline bool sanitize (hb_sanitize_context_t *c) const
     107             :   {
     108          20 :     TRACE_SANITIZE (this);
     109          20 :     return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
     110             :   }
     111             : 
     112             :   protected:
     113             :   USHORT        format;                 /* Format identifier--format = 1 */
     114             :   OffsetTo<Coverage>
     115             :                 coverage;               /* Offset to Coverage table--from
     116             :                                          * beginning of Substitution table */
     117             :   SHORT         deltaGlyphID;           /* Add to original GlyphID to get
     118             :                                          * substitute GlyphID */
     119             :   public:
     120             :   DEFINE_SIZE_STATIC (6);
     121             : };
     122             : 
     123             : struct SingleSubstFormat2
     124             : {
     125           0 :   inline void closure (hb_closure_context_t *c) const
     126             :   {
     127           0 :     TRACE_CLOSURE (this);
     128           0 :     Coverage::Iter iter;
     129           0 :     unsigned int count = substitute.len;
     130           0 :     for (iter.init (this+coverage); iter.more (); iter.next ())
     131             :     {
     132           0 :       if (unlikely (iter.get_coverage () >= count))
     133           0 :         break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
     134           0 :       if (c->glyphs->has (iter.get_glyph ()))
     135           0 :         c->glyphs->add (substitute[iter.get_coverage ()]);
     136             :     }
     137           0 :   }
     138             : 
     139          36 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
     140             :   {
     141          36 :     TRACE_COLLECT_GLYPHS (this);
     142          36 :     Coverage::Iter iter;
     143          36 :     unsigned int count = substitute.len;
     144        1448 :     for (iter.init (this+coverage); iter.more (); iter.next ())
     145             :     {
     146        1412 :       if (unlikely (iter.get_coverage () >= count))
     147           0 :         break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
     148        1412 :       c->input->add (iter.get_glyph ());
     149        1412 :       c->output->add (substitute[iter.get_coverage ()]);
     150             :     }
     151          36 :   }
     152             : 
     153          34 :   inline const Coverage &get_coverage (void) const
     154             :   {
     155          34 :     return this+coverage;
     156             :   }
     157             : 
     158           0 :   inline bool would_apply (hb_would_apply_context_t *c) const
     159             :   {
     160           0 :     TRACE_WOULD_APPLY (this);
     161           0 :     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
     162             :   }
     163             : 
     164           0 :   inline bool apply (hb_apply_context_t *c) const
     165             :   {
     166           0 :     TRACE_APPLY (this);
     167           0 :     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
     168           0 :     unsigned int index = (this+coverage).get_coverage (glyph_id);
     169           0 :     if (likely (index == NOT_COVERED)) return_trace (false);
     170             : 
     171           0 :     if (unlikely (index >= substitute.len)) return_trace (false);
     172             : 
     173           0 :     glyph_id = substitute[index];
     174           0 :     c->replace_glyph (glyph_id);
     175             : 
     176           0 :     return_trace (true);
     177             :   }
     178             : 
     179           0 :   inline bool serialize (hb_serialize_context_t *c,
     180             :                          Supplier<GlyphID> &glyphs,
     181             :                          Supplier<GlyphID> &substitutes,
     182             :                          unsigned int num_glyphs)
     183             :   {
     184           0 :     TRACE_SERIALIZE (this);
     185           0 :     if (unlikely (!c->extend_min (*this))) return_trace (false);
     186           0 :     if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false);
     187           0 :     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
     188           0 :     return_trace (true);
     189             :   }
     190             : 
     191          34 :   inline bool sanitize (hb_sanitize_context_t *c) const
     192             :   {
     193          34 :     TRACE_SANITIZE (this);
     194          34 :     return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
     195             :   }
     196             : 
     197             :   protected:
     198             :   USHORT        format;                 /* Format identifier--format = 2 */
     199             :   OffsetTo<Coverage>
     200             :                 coverage;               /* Offset to Coverage table--from
     201             :                                          * beginning of Substitution table */
     202             :   ArrayOf<GlyphID>
     203             :                 substitute;             /* Array of substitute
     204             :                                          * GlyphIDs--ordered by Coverage Index */
     205             :   public:
     206             :   DEFINE_SIZE_ARRAY (6, substitute);
     207             : };
     208             : 
     209             : struct SingleSubst
     210             : {
     211           0 :   inline bool serialize (hb_serialize_context_t *c,
     212             :                          Supplier<GlyphID> &glyphs,
     213             :                          Supplier<GlyphID> &substitutes,
     214             :                          unsigned int num_glyphs)
     215             :   {
     216           0 :     TRACE_SERIALIZE (this);
     217           0 :     if (unlikely (!c->extend_min (u.format))) return_trace (false);
     218           0 :     unsigned int format = 2;
     219           0 :     int delta = 0;
     220           0 :     if (num_glyphs) {
     221           0 :       format = 1;
     222             :       /* TODO(serialize) check for wrap-around */
     223           0 :       delta = substitutes[0] - glyphs[0];
     224           0 :       for (unsigned int i = 1; i < num_glyphs; i++)
     225           0 :         if (delta != substitutes[i] - glyphs[i]) {
     226           0 :           format = 2;
     227           0 :           break;
     228             :         }
     229             :     }
     230           0 :     u.format.set (format);
     231           0 :     switch (u.format) {
     232           0 :     case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs, delta));
     233           0 :     case 2: return_trace (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
     234           0 :     default:return_trace (false);
     235             :     }
     236             :   }
     237             : 
     238             :   template <typename context_t>
     239         274 :   inline typename context_t::return_t dispatch (context_t *c) const
     240             :   {
     241         274 :     TRACE_DISPATCH (this, u.format);
     242         274 :     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     243         274 :     switch (u.format) {
     244          54 :     case 1: return_trace (c->dispatch (u.format1));
     245         220 :     case 2: return_trace (c->dispatch (u.format2));
     246           0 :     default:return_trace (c->default_return_value ());
     247             :     }
     248             :   }
     249             : 
     250             :   protected:
     251             :   union {
     252             :   USHORT                format;         /* Format identifier */
     253             :   SingleSubstFormat1    format1;
     254             :   SingleSubstFormat2    format2;
     255             :   } u;
     256             : };
     257             : 
     258             : 
     259             : struct Sequence
     260             : {
     261           0 :   inline void closure (hb_closure_context_t *c) const
     262             :   {
     263           0 :     TRACE_CLOSURE (this);
     264           0 :     unsigned int count = substitute.len;
     265           0 :     for (unsigned int i = 0; i < count; i++)
     266           0 :       c->glyphs->add (substitute[i]);
     267           0 :   }
     268             : 
     269           0 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
     270             :   {
     271           0 :     TRACE_COLLECT_GLYPHS (this);
     272           0 :     unsigned int count = substitute.len;
     273           0 :     for (unsigned int i = 0; i < count; i++)
     274           0 :       c->output->add (substitute[i]);
     275           0 :   }
     276             : 
     277           0 :   inline bool apply (hb_apply_context_t *c) const
     278             :   {
     279           0 :     TRACE_APPLY (this);
     280           0 :     unsigned int count = substitute.len;
     281             : 
     282             :     /* Special-case to make it in-place and not consider this
     283             :      * as a "multiplied" substitution. */
     284           0 :     if (unlikely (count == 1))
     285             :     {
     286           0 :       c->replace_glyph (substitute.array[0]);
     287           0 :       return_trace (true);
     288             :     }
     289             :     /* Spec disallows this, but Uniscribe allows it.
     290             :      * https://github.com/behdad/harfbuzz/issues/253 */
     291           0 :     else if (unlikely (count == 0))
     292             :     {
     293           0 :       c->buffer->delete_glyph ();
     294           0 :       return_trace (true);
     295             :     }
     296             : 
     297           0 :     unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
     298           0 :                          HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
     299             : 
     300           0 :     for (unsigned int i = 0; i < count; i++) {
     301           0 :       _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
     302           0 :       c->output_glyph_for_component (substitute.array[i], klass);
     303             :     }
     304           0 :     c->buffer->skip_glyph ();
     305             : 
     306           0 :     return_trace (true);
     307             :   }
     308             : 
     309             :   inline bool serialize (hb_serialize_context_t *c,
     310             :                          Supplier<GlyphID> &glyphs,
     311             :                          unsigned int num_glyphs)
     312             :   {
     313             :     TRACE_SERIALIZE (this);
     314             :     if (unlikely (!c->extend_min (*this))) return_trace (false);
     315             :     if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
     316             :     return_trace (true);
     317             :   }
     318             : 
     319           0 :   inline bool sanitize (hb_sanitize_context_t *c) const
     320             :   {
     321           0 :     TRACE_SANITIZE (this);
     322           0 :     return_trace (substitute.sanitize (c));
     323             :   }
     324             : 
     325             :   protected:
     326             :   ArrayOf<GlyphID>
     327             :                 substitute;             /* String of GlyphIDs to substitute */
     328             :   public:
     329             :   DEFINE_SIZE_ARRAY (2, substitute);
     330             : };
     331             : 
     332             : struct MultipleSubstFormat1
     333             : {
     334           0 :   inline void closure (hb_closure_context_t *c) const
     335             :   {
     336           0 :     TRACE_CLOSURE (this);
     337           0 :     Coverage::Iter iter;
     338           0 :     unsigned int count = sequence.len;
     339           0 :     for (iter.init (this+coverage); iter.more (); iter.next ())
     340             :     {
     341           0 :       if (unlikely (iter.get_coverage () >= count))
     342           0 :         break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
     343           0 :       if (c->glyphs->has (iter.get_glyph ()))
     344           0 :         (this+sequence[iter.get_coverage ()]).closure (c);
     345             :     }
     346           0 :   }
     347             : 
     348           0 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
     349             :   {
     350           0 :     TRACE_COLLECT_GLYPHS (this);
     351           0 :     (this+coverage).add_coverage (c->input);
     352           0 :     unsigned int count = sequence.len;
     353           0 :     for (unsigned int i = 0; i < count; i++)
     354           0 :         (this+sequence[i]).collect_glyphs (c);
     355           0 :   }
     356             : 
     357           0 :   inline const Coverage &get_coverage (void) const
     358             :   {
     359           0 :     return this+coverage;
     360             :   }
     361             : 
     362           0 :   inline bool would_apply (hb_would_apply_context_t *c) const
     363             :   {
     364           0 :     TRACE_WOULD_APPLY (this);
     365           0 :     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
     366             :   }
     367             : 
     368           0 :   inline bool apply (hb_apply_context_t *c) const
     369             :   {
     370           0 :     TRACE_APPLY (this);
     371             : 
     372           0 :     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     373           0 :     if (likely (index == NOT_COVERED)) return_trace (false);
     374             : 
     375           0 :     return_trace ((this+sequence[index]).apply (c));
     376             :   }
     377             : 
     378             :   inline bool serialize (hb_serialize_context_t *c,
     379             :                          Supplier<GlyphID> &glyphs,
     380             :                          Supplier<unsigned int> &substitute_len_list,
     381             :                          unsigned int num_glyphs,
     382             :                          Supplier<GlyphID> &substitute_glyphs_list)
     383             :   {
     384             :     TRACE_SERIALIZE (this);
     385             :     if (unlikely (!c->extend_min (*this))) return_trace (false);
     386             :     if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
     387             :     for (unsigned int i = 0; i < num_glyphs; i++)
     388             :       if (unlikely (!sequence[i].serialize (c, this).serialize (c,
     389             :                                                                 substitute_glyphs_list,
     390             :                                                                 substitute_len_list[i]))) return_trace (false);
     391             :     substitute_len_list.advance (num_glyphs);
     392             :     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
     393             :     return_trace (true);
     394             :   }
     395             : 
     396           0 :   inline bool sanitize (hb_sanitize_context_t *c) const
     397             :   {
     398           0 :     TRACE_SANITIZE (this);
     399           0 :     return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
     400             :   }
     401             : 
     402             :   protected:
     403             :   USHORT        format;                 /* Format identifier--format = 1 */
     404             :   OffsetTo<Coverage>
     405             :                 coverage;               /* Offset to Coverage table--from
     406             :                                          * beginning of Substitution table */
     407             :   OffsetArrayOf<Sequence>
     408             :                 sequence;               /* Array of Sequence tables
     409             :                                          * ordered by Coverage Index */
     410             :   public:
     411             :   DEFINE_SIZE_ARRAY (6, sequence);
     412             : };
     413             : 
     414             : struct MultipleSubst
     415             : {
     416             :   inline bool serialize (hb_serialize_context_t *c,
     417             :                          Supplier<GlyphID> &glyphs,
     418             :                          Supplier<unsigned int> &substitute_len_list,
     419             :                          unsigned int num_glyphs,
     420             :                          Supplier<GlyphID> &substitute_glyphs_list)
     421             :   {
     422             :     TRACE_SERIALIZE (this);
     423             :     if (unlikely (!c->extend_min (u.format))) return_trace (false);
     424             :     unsigned int format = 1;
     425             :     u.format.set (format);
     426             :     switch (u.format) {
     427             :     case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
     428             :     default:return_trace (false);
     429             :     }
     430             :   }
     431             : 
     432             :   template <typename context_t>
     433           0 :   inline typename context_t::return_t dispatch (context_t *c) const
     434             :   {
     435           0 :     TRACE_DISPATCH (this, u.format);
     436           0 :     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     437           0 :     switch (u.format) {
     438           0 :     case 1: return_trace (c->dispatch (u.format1));
     439           0 :     default:return_trace (c->default_return_value ());
     440             :     }
     441             :   }
     442             : 
     443             :   protected:
     444             :   union {
     445             :   USHORT                format;         /* Format identifier */
     446             :   MultipleSubstFormat1  format1;
     447             :   } u;
     448             : };
     449             : 
     450             : 
     451             : typedef ArrayOf<GlyphID> AlternateSet;    /* Array of alternate GlyphIDs--in
     452             :                                          * arbitrary order */
     453             : 
     454             : struct AlternateSubstFormat1
     455             : {
     456           0 :   inline void closure (hb_closure_context_t *c) const
     457             :   {
     458           0 :     TRACE_CLOSURE (this);
     459           0 :     Coverage::Iter iter;
     460           0 :     unsigned int count = alternateSet.len;
     461           0 :     for (iter.init (this+coverage); iter.more (); iter.next ())
     462             :     {
     463           0 :       if (unlikely (iter.get_coverage () >= count))
     464           0 :         break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
     465           0 :       if (c->glyphs->has (iter.get_glyph ())) {
     466           0 :         const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
     467           0 :         unsigned int count = alt_set.len;
     468           0 :         for (unsigned int i = 0; i < count; i++)
     469           0 :           c->glyphs->add (alt_set[i]);
     470             :       }
     471             :     }
     472           0 :   }
     473             : 
     474           9 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
     475             :   {
     476           9 :     TRACE_COLLECT_GLYPHS (this);
     477           9 :     Coverage::Iter iter;
     478           9 :     unsigned int count = alternateSet.len;
     479          63 :     for (iter.init (this+coverage); iter.more (); iter.next ())
     480             :     {
     481          54 :       if (unlikely (iter.get_coverage () >= count))
     482           0 :         break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
     483          54 :       c->input->add (iter.get_glyph ());
     484          54 :       const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
     485          54 :       unsigned int count = alt_set.len;
     486         118 :       for (unsigned int i = 0; i < count; i++)
     487          64 :         c->output->add (alt_set[i]);
     488             :     }
     489           9 :   }
     490             : 
     491           6 :   inline const Coverage &get_coverage (void) const
     492             :   {
     493           6 :     return this+coverage;
     494             :   }
     495             : 
     496           0 :   inline bool would_apply (hb_would_apply_context_t *c) const
     497             :   {
     498           0 :     TRACE_WOULD_APPLY (this);
     499           0 :     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
     500             :   }
     501             : 
     502           0 :   inline bool apply (hb_apply_context_t *c) const
     503             :   {
     504           0 :     TRACE_APPLY (this);
     505           0 :     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
     506             : 
     507           0 :     unsigned int index = (this+coverage).get_coverage (glyph_id);
     508           0 :     if (likely (index == NOT_COVERED)) return_trace (false);
     509             : 
     510           0 :     const AlternateSet &alt_set = this+alternateSet[index];
     511             : 
     512           0 :     if (unlikely (!alt_set.len)) return_trace (false);
     513             : 
     514           0 :     hb_mask_t glyph_mask = c->buffer->cur().mask;
     515           0 :     hb_mask_t lookup_mask = c->lookup_mask;
     516             : 
     517             :     /* Note: This breaks badly if two features enabled this lookup together. */
     518           0 :     unsigned int shift = _hb_ctz (lookup_mask);
     519           0 :     unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
     520             : 
     521           0 :     if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
     522             : 
     523           0 :     glyph_id = alt_set[alt_index - 1];
     524             : 
     525           0 :     c->replace_glyph (glyph_id);
     526             : 
     527           0 :     return_trace (true);
     528             :   }
     529             : 
     530             :   inline bool serialize (hb_serialize_context_t *c,
     531             :                          Supplier<GlyphID> &glyphs,
     532             :                          Supplier<unsigned int> &alternate_len_list,
     533             :                          unsigned int num_glyphs,
     534             :                          Supplier<GlyphID> &alternate_glyphs_list)
     535             :   {
     536             :     TRACE_SERIALIZE (this);
     537             :     if (unlikely (!c->extend_min (*this))) return_trace (false);
     538             :     if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
     539             :     for (unsigned int i = 0; i < num_glyphs; i++)
     540             :       if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
     541             :                                                                     alternate_glyphs_list,
     542             :                                                                     alternate_len_list[i]))) return_trace (false);
     543             :     alternate_len_list.advance (num_glyphs);
     544             :     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
     545             :     return_trace (true);
     546             :   }
     547             : 
     548           6 :   inline bool sanitize (hb_sanitize_context_t *c) const
     549             :   {
     550           6 :     TRACE_SANITIZE (this);
     551           6 :     return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
     552             :   }
     553             : 
     554             :   protected:
     555             :   USHORT        format;                 /* Format identifier--format = 1 */
     556             :   OffsetTo<Coverage>
     557             :                 coverage;               /* Offset to Coverage table--from
     558             :                                          * beginning of Substitution table */
     559             :   OffsetArrayOf<AlternateSet>
     560             :                 alternateSet;           /* Array of AlternateSet tables
     561             :                                          * ordered by Coverage Index */
     562             :   public:
     563             :   DEFINE_SIZE_ARRAY (6, alternateSet);
     564             : };
     565             : 
     566             : struct AlternateSubst
     567             : {
     568             :   inline bool serialize (hb_serialize_context_t *c,
     569             :                          Supplier<GlyphID> &glyphs,
     570             :                          Supplier<unsigned int> &alternate_len_list,
     571             :                          unsigned int num_glyphs,
     572             :                          Supplier<GlyphID> &alternate_glyphs_list)
     573             :   {
     574             :     TRACE_SERIALIZE (this);
     575             :     if (unlikely (!c->extend_min (u.format))) return_trace (false);
     576             :     unsigned int format = 1;
     577             :     u.format.set (format);
     578             :     switch (u.format) {
     579             :     case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
     580             :     default:return_trace (false);
     581             :     }
     582             :   }
     583             : 
     584             :   template <typename context_t>
     585          21 :   inline typename context_t::return_t dispatch (context_t *c) const
     586             :   {
     587          21 :     TRACE_DISPATCH (this, u.format);
     588          21 :     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     589          21 :     switch (u.format) {
     590          21 :     case 1: return_trace (c->dispatch (u.format1));
     591           0 :     default:return_trace (c->default_return_value ());
     592             :     }
     593             :   }
     594             : 
     595             :   protected:
     596             :   union {
     597             :   USHORT                format;         /* Format identifier */
     598             :   AlternateSubstFormat1 format1;
     599             :   } u;
     600             : };
     601             : 
     602             : 
     603             : struct Ligature
     604             : {
     605           0 :   inline void closure (hb_closure_context_t *c) const
     606             :   {
     607           0 :     TRACE_CLOSURE (this);
     608           0 :     unsigned int count = component.len;
     609           0 :     for (unsigned int i = 1; i < count; i++)
     610           0 :       if (!c->glyphs->has (component[i]))
     611           0 :         return;
     612           0 :     c->glyphs->add (ligGlyph);
     613             :   }
     614             : 
     615        2959 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
     616             :   {
     617        2959 :     TRACE_COLLECT_GLYPHS (this);
     618        2959 :     unsigned int count = component.len;
     619        8848 :     for (unsigned int i = 1; i < count; i++)
     620        5889 :       c->input->add (component[i]);
     621        2959 :     c->output->add (ligGlyph);
     622        2959 :   }
     623             : 
     624           0 :   inline bool would_apply (hb_would_apply_context_t *c) const
     625             :   {
     626           0 :     TRACE_WOULD_APPLY (this);
     627           0 :     if (c->len != component.len)
     628           0 :       return_trace (false);
     629             : 
     630           0 :     for (unsigned int i = 1; i < c->len; i++)
     631           0 :       if (likely (c->glyphs[i] != component[i]))
     632           0 :         return_trace (false);
     633             : 
     634           0 :     return_trace (true);
     635             :   }
     636             : 
     637          10 :   inline bool apply (hb_apply_context_t *c) const
     638             :   {
     639          10 :     TRACE_APPLY (this);
     640          10 :     unsigned int count = component.len;
     641             : 
     642          10 :     if (unlikely (!count)) return_trace (false);
     643             : 
     644             :     /* Special-case to make it in-place and not consider this
     645             :      * as a "ligated" substitution. */
     646          10 :     if (unlikely (count == 1))
     647             :     {
     648           0 :       c->replace_glyph (ligGlyph);
     649           0 :       return_trace (true);
     650             :     }
     651             : 
     652          10 :     bool is_mark_ligature = false;
     653          10 :     unsigned int total_component_count = 0;
     654             : 
     655          10 :     unsigned int match_length = 0;
     656             :     unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
     657             : 
     658          10 :     if (likely (!match_input (c, count,
     659             :                               &component[1],
     660             :                               match_glyph,
     661             :                               NULL,
     662             :                               &match_length,
     663             :                               match_positions,
     664             :                               &is_mark_ligature,
     665             :                               &total_component_count)))
     666          10 :       return_trace (false);
     667             : 
     668           0 :     ligate_input (c,
     669             :                   count,
     670             :                   match_positions,
     671             :                   match_length,
     672             :                   ligGlyph,
     673             :                   is_mark_ligature,
     674           0 :                   total_component_count);
     675             : 
     676           0 :     return_trace (true);
     677             :   }
     678             : 
     679           0 :   inline bool serialize (hb_serialize_context_t *c,
     680             :                          GlyphID ligature,
     681             :                          Supplier<GlyphID> &components, /* Starting from second */
     682             :                          unsigned int num_components /* Including first component */)
     683             :   {
     684           0 :     TRACE_SERIALIZE (this);
     685           0 :     if (unlikely (!c->extend_min (*this))) return_trace (false);
     686           0 :     ligGlyph = ligature;
     687           0 :     if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
     688           0 :     return_trace (true);
     689             :   }
     690             : 
     691             :   public:
     692        1988 :   inline bool sanitize (hb_sanitize_context_t *c) const
     693             :   {
     694        1988 :     TRACE_SANITIZE (this);
     695        1988 :     return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
     696             :   }
     697             : 
     698             :   protected:
     699             :   GlyphID       ligGlyph;               /* GlyphID of ligature to substitute */
     700             :   HeadlessArrayOf<GlyphID>
     701             :                 component;              /* Array of component GlyphIDs--start
     702             :                                          * with the second  component--ordered
     703             :                                          * in writing direction */
     704             :   public:
     705             :   DEFINE_SIZE_ARRAY (4, component);
     706             : };
     707             : 
     708             : struct LigatureSet
     709             : {
     710           0 :   inline void closure (hb_closure_context_t *c) const
     711             :   {
     712           0 :     TRACE_CLOSURE (this);
     713           0 :     unsigned int num_ligs = ligature.len;
     714           0 :     for (unsigned int i = 0; i < num_ligs; i++)
     715           0 :       (this+ligature[i]).closure (c);
     716           0 :   }
     717             : 
     718         163 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
     719             :   {
     720         163 :     TRACE_COLLECT_GLYPHS (this);
     721         163 :     unsigned int num_ligs = ligature.len;
     722        3122 :     for (unsigned int i = 0; i < num_ligs; i++)
     723        2959 :       (this+ligature[i]).collect_glyphs (c);
     724         163 :   }
     725             : 
     726           0 :   inline bool would_apply (hb_would_apply_context_t *c) const
     727             :   {
     728           0 :     TRACE_WOULD_APPLY (this);
     729           0 :     unsigned int num_ligs = ligature.len;
     730           0 :     for (unsigned int i = 0; i < num_ligs; i++)
     731             :     {
     732           0 :       const Ligature &lig = this+ligature[i];
     733           0 :       if (lig.would_apply (c))
     734           0 :         return_trace (true);
     735             :     }
     736           0 :     return_trace (false);
     737             :   }
     738             : 
     739           2 :   inline bool apply (hb_apply_context_t *c) const
     740             :   {
     741           2 :     TRACE_APPLY (this);
     742           2 :     unsigned int num_ligs = ligature.len;
     743          12 :     for (unsigned int i = 0; i < num_ligs; i++)
     744             :     {
     745          10 :       const Ligature &lig = this+ligature[i];
     746          10 :       if (lig.apply (c)) return_trace (true);
     747             :     }
     748             : 
     749           2 :     return_trace (false);
     750             :   }
     751             : 
     752           0 :   inline bool serialize (hb_serialize_context_t *c,
     753             :                          Supplier<GlyphID> &ligatures,
     754             :                          Supplier<unsigned int> &component_count_list,
     755             :                          unsigned int num_ligatures,
     756             :                          Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
     757             :   {
     758           0 :     TRACE_SERIALIZE (this);
     759           0 :     if (unlikely (!c->extend_min (*this))) return_trace (false);
     760           0 :     if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
     761           0 :     for (unsigned int i = 0; i < num_ligatures; i++)
     762           0 :       if (unlikely (!ligature[i].serialize (c, this).serialize (c,
     763             :                                                                 ligatures[i],
     764             :                                                                 component_list,
     765           0 :                                                                 component_count_list[i]))) return_trace (false);
     766           0 :     ligatures.advance (num_ligatures);
     767           0 :     component_count_list.advance (num_ligatures);
     768           0 :     return_trace (true);
     769             :   }
     770             : 
     771         110 :   inline bool sanitize (hb_sanitize_context_t *c) const
     772             :   {
     773         110 :     TRACE_SANITIZE (this);
     774         110 :     return_trace (ligature.sanitize (c, this));
     775             :   }
     776             : 
     777             :   protected:
     778             :   OffsetArrayOf<Ligature>
     779             :                 ligature;               /* Array LigatureSet tables
     780             :                                          * ordered by preference */
     781             :   public:
     782             :   DEFINE_SIZE_ARRAY (2, ligature);
     783             : };
     784             : 
     785             : struct LigatureSubstFormat1
     786             : {
     787           0 :   inline void closure (hb_closure_context_t *c) const
     788             :   {
     789           0 :     TRACE_CLOSURE (this);
     790           0 :     Coverage::Iter iter;
     791           0 :     unsigned int count = ligatureSet.len;
     792           0 :     for (iter.init (this+coverage); iter.more (); iter.next ())
     793             :     {
     794           0 :       if (unlikely (iter.get_coverage () >= count))
     795           0 :         break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
     796           0 :       if (c->glyphs->has (iter.get_glyph ()))
     797           0 :         (this+ligatureSet[iter.get_coverage ()]).closure (c);
     798             :     }
     799           0 :   }
     800             : 
     801          18 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
     802             :   {
     803          18 :     TRACE_COLLECT_GLYPHS (this);
     804          18 :     Coverage::Iter iter;
     805          18 :     unsigned int count = ligatureSet.len;
     806         181 :     for (iter.init (this+coverage); iter.more (); iter.next ())
     807             :     {
     808         163 :       if (unlikely (iter.get_coverage () >= count))
     809           0 :         break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
     810         163 :       c->input->add (iter.get_glyph ());
     811         163 :       (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
     812             :     }
     813          18 :   }
     814             : 
     815          14 :   inline const Coverage &get_coverage (void) const
     816             :   {
     817          14 :     return this+coverage;
     818             :   }
     819             : 
     820           0 :   inline bool would_apply (hb_would_apply_context_t *c) const
     821             :   {
     822           0 :     TRACE_WOULD_APPLY (this);
     823           0 :     unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
     824           0 :     if (likely (index == NOT_COVERED)) return_trace (false);
     825             : 
     826           0 :     const LigatureSet &lig_set = this+ligatureSet[index];
     827           0 :     return_trace (lig_set.would_apply (c));
     828             :   }
     829             : 
     830           2 :   inline bool apply (hb_apply_context_t *c) const
     831             :   {
     832           2 :     TRACE_APPLY (this);
     833           2 :     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
     834             : 
     835           2 :     unsigned int index = (this+coverage).get_coverage (glyph_id);
     836           2 :     if (likely (index == NOT_COVERED)) return_trace (false);
     837             : 
     838           2 :     const LigatureSet &lig_set = this+ligatureSet[index];
     839           2 :     return_trace (lig_set.apply (c));
     840             :   }
     841             : 
     842           0 :   inline bool serialize (hb_serialize_context_t *c,
     843             :                          Supplier<GlyphID> &first_glyphs,
     844             :                          Supplier<unsigned int> &ligature_per_first_glyph_count_list,
     845             :                          unsigned int num_first_glyphs,
     846             :                          Supplier<GlyphID> &ligatures_list,
     847             :                          Supplier<unsigned int> &component_count_list,
     848             :                          Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
     849             :   {
     850           0 :     TRACE_SERIALIZE (this);
     851           0 :     if (unlikely (!c->extend_min (*this))) return_trace (false);
     852           0 :     if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
     853           0 :     for (unsigned int i = 0; i < num_first_glyphs; i++)
     854           0 :       if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
     855             :                                                                    ligatures_list,
     856             :                                                                    component_count_list,
     857             :                                                                    ligature_per_first_glyph_count_list[i],
     858           0 :                                                                    component_list))) return_trace (false);
     859           0 :     ligature_per_first_glyph_count_list.advance (num_first_glyphs);
     860           0 :     if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
     861           0 :     return_trace (true);
     862             :   }
     863             : 
     864          14 :   inline bool sanitize (hb_sanitize_context_t *c) const
     865             :   {
     866          14 :     TRACE_SANITIZE (this);
     867          14 :     return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
     868             :   }
     869             : 
     870             :   protected:
     871             :   USHORT        format;                 /* Format identifier--format = 1 */
     872             :   OffsetTo<Coverage>
     873             :                 coverage;               /* Offset to Coverage table--from
     874             :                                          * beginning of Substitution table */
     875             :   OffsetArrayOf<LigatureSet>
     876             :                 ligatureSet;            /* Array LigatureSet tables
     877             :                                          * ordered by Coverage Index */
     878             :   public:
     879             :   DEFINE_SIZE_ARRAY (6, ligatureSet);
     880             : };
     881             : 
     882             : struct LigatureSubst
     883             : {
     884           0 :   inline bool serialize (hb_serialize_context_t *c,
     885             :                          Supplier<GlyphID> &first_glyphs,
     886             :                          Supplier<unsigned int> &ligature_per_first_glyph_count_list,
     887             :                          unsigned int num_first_glyphs,
     888             :                          Supplier<GlyphID> &ligatures_list,
     889             :                          Supplier<unsigned int> &component_count_list,
     890             :                          Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
     891             :   {
     892           0 :     TRACE_SERIALIZE (this);
     893           0 :     if (unlikely (!c->extend_min (u.format))) return_trace (false);
     894           0 :     unsigned int format = 1;
     895           0 :     u.format.set (format);
     896           0 :     switch (u.format) {
     897           0 :     case 1: return_trace (u.format1.serialize (c,
     898             :                                                first_glyphs,
     899             :                                                ligature_per_first_glyph_count_list,
     900             :                                                num_first_glyphs,
     901             :                                                ligatures_list,
     902             :                                                component_count_list,
     903             :                                                component_list));
     904           0 :     default:return_trace (false);
     905             :     }
     906             :   }
     907             : 
     908             :   template <typename context_t>
     909         114 :   inline typename context_t::return_t dispatch (context_t *c) const
     910             :   {
     911         114 :     TRACE_DISPATCH (this, u.format);
     912         114 :     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     913         114 :     switch (u.format) {
     914         114 :     case 1: return_trace (c->dispatch (u.format1));
     915           0 :     default:return_trace (c->default_return_value ());
     916             :     }
     917             :   }
     918             : 
     919             :   protected:
     920             :   union {
     921             :   USHORT                format;         /* Format identifier */
     922             :   LigatureSubstFormat1  format1;
     923             :   } u;
     924             : };
     925             : 
     926             : 
     927             : struct ContextSubst : Context {};
     928             : 
     929             : struct ChainContextSubst : ChainContext {};
     930             : 
     931             : struct ExtensionSubst : Extension<ExtensionSubst>
     932             : {
     933             :   typedef struct SubstLookupSubTable LookupSubTable;
     934             : 
     935             :   inline bool is_reverse (void) const;
     936             : };
     937             : 
     938             : 
     939             : struct ReverseChainSingleSubstFormat1
     940             : {
     941           0 :   inline void closure (hb_closure_context_t *c) const
     942             :   {
     943           0 :     TRACE_CLOSURE (this);
     944           0 :     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     945             : 
     946             :     unsigned int count;
     947             : 
     948           0 :     count = backtrack.len;
     949           0 :     for (unsigned int i = 0; i < count; i++)
     950           0 :       if (!(this+backtrack[i]).intersects (c->glyphs))
     951           0 :         return;
     952             : 
     953           0 :     count = lookahead.len;
     954           0 :     for (unsigned int i = 0; i < count; i++)
     955           0 :       if (!(this+lookahead[i]).intersects (c->glyphs))
     956           0 :         return;
     957             : 
     958           0 :     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
     959           0 :     Coverage::Iter iter;
     960           0 :     count = substitute.len;
     961           0 :     for (iter.init (this+coverage); iter.more (); iter.next ())
     962             :     {
     963           0 :       if (unlikely (iter.get_coverage () >= count))
     964           0 :         break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
     965           0 :       if (c->glyphs->has (iter.get_glyph ()))
     966           0 :         c->glyphs->add (substitute[iter.get_coverage ()]);
     967             :     }
     968             :   }
     969             : 
     970           0 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
     971             :   {
     972           0 :     TRACE_COLLECT_GLYPHS (this);
     973             : 
     974           0 :     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     975             : 
     976             :     unsigned int count;
     977             : 
     978           0 :     (this+coverage).add_coverage (c->input);
     979             : 
     980           0 :     count = backtrack.len;
     981           0 :     for (unsigned int i = 0; i < count; i++)
     982           0 :       (this+backtrack[i]).add_coverage (c->before);
     983             : 
     984           0 :     count = lookahead.len;
     985           0 :     for (unsigned int i = 0; i < count; i++)
     986           0 :       (this+lookahead[i]).add_coverage (c->after);
     987             : 
     988           0 :     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
     989           0 :     count = substitute.len;
     990           0 :     for (unsigned int i = 0; i < count; i++)
     991           0 :       c->output->add (substitute[i]);
     992           0 :   }
     993             : 
     994           0 :   inline const Coverage &get_coverage (void) const
     995             :   {
     996           0 :     return this+coverage;
     997             :   }
     998             : 
     999           0 :   inline bool would_apply (hb_would_apply_context_t *c) const
    1000             :   {
    1001           0 :     TRACE_WOULD_APPLY (this);
    1002           0 :     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
    1003             :   }
    1004             : 
    1005           0 :   inline bool apply (hb_apply_context_t *c) const
    1006             :   {
    1007           0 :     TRACE_APPLY (this);
    1008           0 :     if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
    1009           0 :       return_trace (false); /* No chaining to this type */
    1010             : 
    1011           0 :     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
    1012           0 :     if (likely (index == NOT_COVERED)) return_trace (false);
    1013             : 
    1014           0 :     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    1015           0 :     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    1016             : 
    1017           0 :     if (match_backtrack (c,
    1018             :                          backtrack.len, (USHORT *) backtrack.array,
    1019           0 :                          match_coverage, this) &&
    1020           0 :         match_lookahead (c,
    1021             :                          lookahead.len, (USHORT *) lookahead.array,
    1022             :                          match_coverage, this,
    1023           0 :                          1))
    1024             :     {
    1025           0 :       c->replace_glyph_inplace (substitute[index]);
    1026             :       /* Note: We DON'T decrease buffer->idx.  The main loop does it
    1027             :        * for us.  This is useful for preventing surprises if someone
    1028             :        * calls us through a Context lookup. */
    1029           0 :       return_trace (true);
    1030             :     }
    1031             : 
    1032           0 :     return_trace (false);
    1033             :   }
    1034             : 
    1035           0 :   inline bool sanitize (hb_sanitize_context_t *c) const
    1036             :   {
    1037           0 :     TRACE_SANITIZE (this);
    1038           0 :     if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
    1039           0 :       return_trace (false);
    1040           0 :     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    1041           0 :     if (!lookahead.sanitize (c, this))
    1042           0 :       return_trace (false);
    1043           0 :     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    1044           0 :     return_trace (substitute.sanitize (c));
    1045             :   }
    1046             : 
    1047             :   protected:
    1048             :   USHORT        format;                 /* Format identifier--format = 1 */
    1049             :   OffsetTo<Coverage>
    1050             :                 coverage;               /* Offset to Coverage table--from
    1051             :                                          * beginning of table */
    1052             :   OffsetArrayOf<Coverage>
    1053             :                 backtrack;              /* Array of coverage tables
    1054             :                                          * in backtracking sequence, in  glyph
    1055             :                                          * sequence order */
    1056             :   OffsetArrayOf<Coverage>
    1057             :                 lookaheadX;             /* Array of coverage tables
    1058             :                                          * in lookahead sequence, in glyph
    1059             :                                          * sequence order */
    1060             :   ArrayOf<GlyphID>
    1061             :                 substituteX;            /* Array of substitute
    1062             :                                          * GlyphIDs--ordered by Coverage Index */
    1063             :   public:
    1064             :   DEFINE_SIZE_MIN (10);
    1065             : };
    1066             : 
    1067             : struct ReverseChainSingleSubst
    1068             : {
    1069             :   template <typename context_t>
    1070           0 :   inline typename context_t::return_t dispatch (context_t *c) const
    1071             :   {
    1072           0 :     TRACE_DISPATCH (this, u.format);
    1073           0 :     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
    1074           0 :     switch (u.format) {
    1075           0 :     case 1: return_trace (c->dispatch (u.format1));
    1076           0 :     default:return_trace (c->default_return_value ());
    1077             :     }
    1078             :   }
    1079             : 
    1080             :   protected:
    1081             :   union {
    1082             :   USHORT                                format;         /* Format identifier */
    1083             :   ReverseChainSingleSubstFormat1        format1;
    1084             :   } u;
    1085             : };
    1086             : 
    1087             : 
    1088             : 
    1089             : /*
    1090             :  * SubstLookup
    1091             :  */
    1092             : 
    1093             : struct SubstLookupSubTable
    1094             : {
    1095             :   friend struct SubstLookup;
    1096             : 
    1097             :   enum Type {
    1098             :     Single              = 1,
    1099             :     Multiple            = 2,
    1100             :     Alternate           = 3,
    1101             :     Ligature            = 4,
    1102             :     Context             = 5,
    1103             :     ChainContext        = 6,
    1104             :     Extension           = 7,
    1105             :     ReverseChainSingle  = 8
    1106             :   };
    1107             : 
    1108             :   template <typename context_t>
    1109         458 :   inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
    1110             :   {
    1111         458 :     TRACE_DISPATCH (this, lookup_type);
    1112         458 :     if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
    1113         458 :     switch (lookup_type) {
    1114         274 :     case Single:                return_trace (u.single.dispatch (c));
    1115           0 :     case Multiple:              return_trace (u.multiple.dispatch (c));
    1116          21 :     case Alternate:             return_trace (u.alternate.dispatch (c));
    1117         114 :     case Ligature:              return_trace (u.ligature.dispatch (c));
    1118           0 :     case Context:               return_trace (u.context.dispatch (c));
    1119          49 :     case ChainContext:          return_trace (u.chainContext.dispatch (c));
    1120           0 :     case Extension:             return_trace (u.extension.dispatch (c));
    1121           0 :     case ReverseChainSingle:    return_trace (u.reverseChainContextSingle.dispatch (c));
    1122           0 :     default:                    return_trace (c->default_return_value ());
    1123             :     }
    1124             :   }
    1125             : 
    1126             :   protected:
    1127             :   union {
    1128             :   USHORT                        sub_format;
    1129             :   SingleSubst                   single;
    1130             :   MultipleSubst                 multiple;
    1131             :   AlternateSubst                alternate;
    1132             :   LigatureSubst                 ligature;
    1133             :   ContextSubst                  context;
    1134             :   ChainContextSubst             chainContext;
    1135             :   ExtensionSubst                extension;
    1136             :   ReverseChainSingleSubst       reverseChainContextSingle;
    1137             :   } u;
    1138             :   public:
    1139             :   DEFINE_SIZE_UNION (2, sub_format);
    1140             : };
    1141             : 
    1142             : 
    1143             : struct SubstLookup : Lookup
    1144             : {
    1145           0 :   inline const SubstLookupSubTable& get_subtable (unsigned int i) const
    1146           0 :   { return Lookup::get_subtable<SubstLookupSubTable> (i); }
    1147             : 
    1148         218 :   inline static bool lookup_type_is_reverse (unsigned int lookup_type)
    1149         218 :   { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
    1150             : 
    1151         218 :   inline bool is_reverse (void) const
    1152             :   {
    1153         218 :     unsigned int type = get_type ();
    1154         218 :     if (unlikely (type == SubstLookupSubTable::Extension))
    1155           0 :       return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
    1156         218 :     return lookup_type_is_reverse (type);
    1157             :   }
    1158             : 
    1159             :   inline bool apply (hb_apply_context_t *c) const
    1160             :   {
    1161             :     TRACE_APPLY (this);
    1162             :     return_trace (dispatch (c));
    1163             :   }
    1164             : 
    1165           0 :   inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
    1166             :   {
    1167           0 :     TRACE_CLOSURE (this);
    1168           0 :     c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
    1169           0 :     return_trace (dispatch (c));
    1170             :   }
    1171             : 
    1172          84 :   inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
    1173             :   {
    1174          84 :     TRACE_COLLECT_GLYPHS (this);
    1175          84 :     c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
    1176          84 :     return_trace (dispatch (c));
    1177             :   }
    1178             : 
    1179             :   template <typename set_t>
    1180          78 :   inline void add_coverage (set_t *glyphs) const
    1181             :   {
    1182          78 :     hb_add_coverage_context_t<set_t> c (glyphs);
    1183          78 :     dispatch (&c);
    1184          78 :   }
    1185             : 
    1186           0 :   inline bool would_apply (hb_would_apply_context_t *c,
    1187             :                            const hb_ot_layout_lookup_accelerator_t *accel) const
    1188             :   {
    1189           0 :     TRACE_WOULD_APPLY (this);
    1190           0 :     if (unlikely (!c->len))  return_trace (false);
    1191           0 :     if (!accel->may_have (c->glyphs[0]))  return_trace (false);
    1192           0 :       return_trace (dispatch (c));
    1193             :   }
    1194             : 
    1195             :   static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
    1196             : 
    1197           0 :   inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
    1198             :                                                   unsigned int i)
    1199           0 :   { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
    1200             : 
    1201           0 :   inline bool serialize_single (hb_serialize_context_t *c,
    1202             :                                 uint32_t lookup_props,
    1203             :                                 Supplier<GlyphID> &glyphs,
    1204             :                                 Supplier<GlyphID> &substitutes,
    1205             :                                 unsigned int num_glyphs)
    1206             :   {
    1207           0 :     TRACE_SERIALIZE (this);
    1208           0 :     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
    1209           0 :     return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
    1210             :   }
    1211             : 
    1212             :   inline bool serialize_multiple (hb_serialize_context_t *c,
    1213             :                                   uint32_t lookup_props,
    1214             :                                   Supplier<GlyphID> &glyphs,
    1215             :                                   Supplier<unsigned int> &substitute_len_list,
    1216             :                                   unsigned int num_glyphs,
    1217             :                                   Supplier<GlyphID> &substitute_glyphs_list)
    1218             :   {
    1219             :     TRACE_SERIALIZE (this);
    1220             :     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
    1221             :     return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
    1222             :                                                                   glyphs,
    1223             :                                                                   substitute_len_list,
    1224             :                                                                   num_glyphs,
    1225             :                                                                   substitute_glyphs_list));
    1226             :   }
    1227             : 
    1228             :   inline bool serialize_alternate (hb_serialize_context_t *c,
    1229             :                                    uint32_t lookup_props,
    1230             :                                    Supplier<GlyphID> &glyphs,
    1231             :                                    Supplier<unsigned int> &alternate_len_list,
    1232             :                                    unsigned int num_glyphs,
    1233             :                                    Supplier<GlyphID> &alternate_glyphs_list)
    1234             :   {
    1235             :     TRACE_SERIALIZE (this);
    1236             :     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
    1237             :     return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
    1238             :                                                                    glyphs,
    1239             :                                                                    alternate_len_list,
    1240             :                                                                    num_glyphs,
    1241             :                                                                    alternate_glyphs_list));
    1242             :   }
    1243             : 
    1244           0 :   inline bool serialize_ligature (hb_serialize_context_t *c,
    1245             :                                   uint32_t lookup_props,
    1246             :                                   Supplier<GlyphID> &first_glyphs,
    1247             :                                   Supplier<unsigned int> &ligature_per_first_glyph_count_list,
    1248             :                                   unsigned int num_first_glyphs,
    1249             :                                   Supplier<GlyphID> &ligatures_list,
    1250             :                                   Supplier<unsigned int> &component_count_list,
    1251             :                                   Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
    1252             :   {
    1253           0 :     TRACE_SERIALIZE (this);
    1254           0 :     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false);
    1255           0 :     return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
    1256             :                                                                   first_glyphs,
    1257             :                                                                   ligature_per_first_glyph_count_list,
    1258             :                                                                   num_first_glyphs,
    1259             :                                                                   ligatures_list,
    1260             :                                                                   component_count_list,
    1261             :                                                                   component_list));
    1262             :   }
    1263             : 
    1264             :   template <typename context_t>
    1265             :   static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
    1266             : 
    1267             :   template <typename context_t>
    1268         458 :   inline typename context_t::return_t dispatch (context_t *c) const
    1269         458 :   { return Lookup::dispatch<SubstLookupSubTable> (c); }
    1270             : 
    1271          78 :   inline bool sanitize (hb_sanitize_context_t *c) const
    1272             :   {
    1273          78 :     TRACE_SANITIZE (this);
    1274          78 :     if (unlikely (!Lookup::sanitize (c))) return_trace (false);
    1275          78 :     if (unlikely (!dispatch (c))) return_trace (false);
    1276             : 
    1277          78 :     if (unlikely (get_type () == SubstLookupSubTable::Extension))
    1278             :     {
    1279             :       /* The spec says all subtables of an Extension lookup should
    1280             :        * have the same type.  This is specially important if one has
    1281             :        * a reverse type! */
    1282           0 :       unsigned int type = get_subtable (0).u.extension.get_type ();
    1283           0 :       unsigned int count = get_subtable_count ();
    1284           0 :       for (unsigned int i = 1; i < count; i++)
    1285           0 :         if (get_subtable (i).u.extension.get_type () != type)
    1286           0 :           return_trace (false);
    1287             :     }
    1288          78 :     return_trace (true);
    1289             :   }
    1290             : };
    1291             : 
    1292             : typedef OffsetListOf<SubstLookup> SubstLookupList;
    1293             : 
    1294             : /*
    1295             :  * GSUB -- The Glyph Substitution Table
    1296             :  */
    1297             : 
    1298             : struct GSUB : GSUBGPOS
    1299             : {
    1300             :   static const hb_tag_t tableTag        = HB_OT_TAG_GSUB;
    1301             : 
    1302         380 :   inline const SubstLookup& get_lookup (unsigned int i) const
    1303         380 :   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
    1304             : 
    1305             :   static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
    1306             : 
    1307           4 :   inline bool sanitize (hb_sanitize_context_t *c) const
    1308             :   {
    1309           4 :     TRACE_SANITIZE (this);
    1310           4 :     if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
    1311           4 :     const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
    1312           4 :     return_trace (list.sanitize (c, this));
    1313             :   }
    1314             : };
    1315             : 
    1316             : 
    1317             : void
    1318          34 : GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
    1319             : {
    1320          34 :   _hb_buffer_assert_gsubgpos_vars (buffer);
    1321             : 
    1322          34 :   const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
    1323          34 :   unsigned int count = buffer->len;
    1324         299 :   for (unsigned int i = 0; i < count; i++)
    1325             :   {
    1326         265 :     _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
    1327         265 :     _hb_glyph_info_clear_lig_props (&buffer->info[i]);
    1328         265 :     buffer->info[i].syllable() = 0;
    1329             :   }
    1330          34 : }
    1331             : 
    1332             : 
    1333             : /* Out-of-class implementation for methods recursing */
    1334             : 
    1335           0 : /*static*/ inline bool ExtensionSubst::is_reverse (void) const
    1336             : {
    1337           0 :   unsigned int type = get_type ();
    1338           0 :   if (unlikely (type == SubstLookupSubTable::Extension))
    1339           0 :     return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
    1340           0 :   return SubstLookup::lookup_type_is_reverse (type);
    1341             : }
    1342             : 
    1343             : template <typename context_t>
    1344           0 : /*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
    1345             : {
    1346           0 :   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
    1347           0 :   const SubstLookup &l = gsub.get_lookup (lookup_index);
    1348           0 :   return l.dispatch (c);
    1349             : }
    1350             : 
    1351           0 : /*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
    1352             : {
    1353           0 :   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
    1354           0 :   const SubstLookup &l = gsub.get_lookup (lookup_index);
    1355           0 :   unsigned int saved_lookup_props = c->lookup_props;
    1356           0 :   unsigned int saved_lookup_index = c->lookup_index;
    1357           0 :   c->set_lookup_index (lookup_index);
    1358           0 :   c->set_lookup_props (l.get_props ());
    1359           0 :   bool ret = l.dispatch (c);
    1360           0 :   c->set_lookup_index (saved_lookup_index);
    1361           0 :   c->set_lookup_props (saved_lookup_props);
    1362           0 :   return ret;
    1363             : }
    1364             : 
    1365             : 
    1366             : } /* namespace OT */
    1367             : 
    1368             : 
    1369             : #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */

Generated by: LCOV version 1.13