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

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

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

mercurial