LCOV - code coverage report
Current view: directory - gfx/harfbuzz/src - hb-ot-layout-gsub-table.hh (source / functions) Found Hit Coverage
Test: app.info Lines: 345 0 0.0 %
Date: 2012-06-02 Functions: 48 0 0.0 %

       1                 : /*
       2                 :  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
       3                 :  * Copyright © 2010  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                 : 
      36                 : struct SingleSubstFormat1
      37                 : {
      38                 :   friend struct SingleSubst;
      39                 : 
      40                 :   private:
      41                 : 
      42               0 :   inline bool apply (hb_apply_context_t *c) const
      43                 :   {
      44               0 :     TRACE_APPLY ();
      45               0 :     hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint;
      46               0 :     unsigned int index = (this+coverage) (glyph_id);
      47               0 :     if (likely (index == NOT_COVERED))
      48               0 :       return false;
      49                 : 
      50                 :     /* According to the Adobe Annotated OpenType Suite, result is always
      51                 :      * limited to 16bit. */
      52               0 :     glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF;
      53               0 :     c->replace_glyph (glyph_id);
      54                 : 
      55               0 :     return true;
      56                 :   }
      57                 : 
      58               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
      59               0 :     TRACE_SANITIZE ();
      60               0 :     return coverage.sanitize (c, this)
      61               0 :         && deltaGlyphID.sanitize (c);
      62                 :   }
      63                 : 
      64                 :   private:
      65                 :   USHORT        format;                 /* Format identifier--format = 1 */
      66                 :   OffsetTo<Coverage>
      67                 :                 coverage;               /* Offset to Coverage table--from
      68                 :                                          * beginning of Substitution table */
      69                 :   SHORT         deltaGlyphID;           /* Add to original GlyphID to get
      70                 :                                          * substitute GlyphID */
      71                 :   public:
      72                 :   DEFINE_SIZE_STATIC (6);
      73                 : };
      74                 : 
      75                 : struct SingleSubstFormat2
      76                 : {
      77                 :   friend struct SingleSubst;
      78                 : 
      79                 :   private:
      80                 : 
      81               0 :   inline bool apply (hb_apply_context_t *c) const
      82                 :   {
      83               0 :     TRACE_APPLY ();
      84               0 :     hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint;
      85               0 :     unsigned int index = (this+coverage) (glyph_id);
      86               0 :     if (likely (index == NOT_COVERED))
      87               0 :       return false;
      88                 : 
      89               0 :     if (unlikely (index >= substitute.len))
      90               0 :       return false;
      91                 : 
      92               0 :     glyph_id = substitute[index];
      93               0 :     c->replace_glyph (glyph_id);
      94                 : 
      95               0 :     return true;
      96                 :   }
      97                 : 
      98               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
      99               0 :     TRACE_SANITIZE ();
     100               0 :     return coverage.sanitize (c, this)
     101               0 :         && substitute.sanitize (c);
     102                 :   }
     103                 : 
     104                 :   private:
     105                 :   USHORT        format;                 /* Format identifier--format = 2 */
     106                 :   OffsetTo<Coverage>
     107                 :                 coverage;               /* Offset to Coverage table--from
     108                 :                                          * beginning of Substitution table */
     109                 :   ArrayOf<GlyphID>
     110                 :                 substitute;             /* Array of substitute
     111                 :                                          * GlyphIDs--ordered by Coverage Index */
     112                 :   public:
     113                 :   DEFINE_SIZE_ARRAY (6, substitute);
     114                 : };
     115                 : 
     116                 : struct SingleSubst
     117                 : {
     118                 :   friend struct SubstLookupSubTable;
     119                 : 
     120                 :   private:
     121                 : 
     122               0 :   inline bool apply (hb_apply_context_t *c) const
     123                 :   {
     124               0 :     TRACE_APPLY ();
     125               0 :     switch (u.format) {
     126               0 :     case 1: return u.format1.apply (c);
     127               0 :     case 2: return u.format2.apply (c);
     128               0 :     default:return false;
     129                 :     }
     130                 :   }
     131                 : 
     132               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
     133               0 :     TRACE_SANITIZE ();
     134               0 :     if (!u.format.sanitize (c)) return false;
     135               0 :     switch (u.format) {
     136               0 :     case 1: return u.format1.sanitize (c);
     137               0 :     case 2: return u.format2.sanitize (c);
     138               0 :     default:return true;
     139                 :     }
     140                 :   }
     141                 : 
     142                 :   private:
     143                 :   union {
     144                 :   USHORT                format;         /* Format identifier */
     145                 :   SingleSubstFormat1    format1;
     146                 :   SingleSubstFormat2    format2;
     147                 :   } u;
     148                 : };
     149                 : 
     150                 : 
     151                 : struct Sequence
     152                 : {
     153                 :   friend struct MultipleSubstFormat1;
     154                 : 
     155                 :   private:
     156               0 :   inline bool apply (hb_apply_context_t *c) const
     157                 :   {
     158               0 :     TRACE_APPLY ();
     159               0 :     if (unlikely (!substitute.len))
     160               0 :       return false;
     161                 : 
     162               0 :     if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)
     163               0 :       c->guess_glyph_class (HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH);
     164               0 :     c->replace_glyphs_be16 (1, substitute.len, (const uint16_t *) substitute.array);
     165                 : 
     166               0 :     return true;
     167                 :   }
     168                 : 
     169                 :   public:
     170               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
     171               0 :     TRACE_SANITIZE ();
     172               0 :     return substitute.sanitize (c);
     173                 :   }
     174                 : 
     175                 :   private:
     176                 :   ArrayOf<GlyphID>
     177                 :                 substitute;             /* String of GlyphIDs to substitute */
     178                 :   public:
     179                 :   DEFINE_SIZE_ARRAY (2, substitute);
     180                 : };
     181                 : 
     182                 : struct MultipleSubstFormat1
     183                 : {
     184                 :   friend struct MultipleSubst;
     185                 : 
     186                 :   private:
     187                 : 
     188               0 :   inline bool apply (hb_apply_context_t *c) const
     189                 :   {
     190               0 :     TRACE_APPLY ();
     191                 : 
     192               0 :     unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
     193               0 :     if (likely (index == NOT_COVERED))
     194               0 :       return false;
     195                 : 
     196               0 :     return (this+sequence[index]).apply (c);
     197                 :   }
     198                 : 
     199               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
     200               0 :     TRACE_SANITIZE ();
     201               0 :     return coverage.sanitize (c, this)
     202               0 :         && sequence.sanitize (c, this);
     203                 :   }
     204                 : 
     205                 :   private:
     206                 :   USHORT        format;                 /* Format identifier--format = 1 */
     207                 :   OffsetTo<Coverage>
     208                 :                 coverage;               /* Offset to Coverage table--from
     209                 :                                          * beginning of Substitution table */
     210                 :   OffsetArrayOf<Sequence>
     211                 :                 sequence;               /* Array of Sequence tables
     212                 :                                          * ordered by Coverage Index */
     213                 :   public:
     214                 :   DEFINE_SIZE_ARRAY (6, sequence);
     215                 : };
     216                 : 
     217                 : struct MultipleSubst
     218                 : {
     219                 :   friend struct SubstLookupSubTable;
     220                 : 
     221                 :   private:
     222                 : 
     223               0 :   inline bool apply (hb_apply_context_t *c) const
     224                 :   {
     225               0 :     TRACE_APPLY ();
     226               0 :     switch (u.format) {
     227               0 :     case 1: return u.format1.apply (c);
     228               0 :     default:return false;
     229                 :     }
     230                 :   }
     231                 : 
     232               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
     233               0 :     TRACE_SANITIZE ();
     234               0 :     if (!u.format.sanitize (c)) return false;
     235               0 :     switch (u.format) {
     236               0 :     case 1: return u.format1.sanitize (c);
     237               0 :     default:return true;
     238                 :     }
     239                 :   }
     240                 : 
     241                 :   private:
     242                 :   union {
     243                 :   USHORT                format;         /* Format identifier */
     244                 :   MultipleSubstFormat1  format1;
     245                 :   } u;
     246                 : };
     247                 : 
     248                 : 
     249                 : typedef ArrayOf<GlyphID> AlternateSet;    /* Array of alternate GlyphIDs--in
     250                 :                                          * arbitrary order */
     251                 : 
     252                 : struct AlternateSubstFormat1
     253                 : {
     254                 :   friend struct AlternateSubst;
     255                 : 
     256                 :   private:
     257                 : 
     258               0 :   inline bool apply (hb_apply_context_t *c) const
     259                 :   {
     260               0 :     TRACE_APPLY ();
     261               0 :     hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint;
     262               0 :     hb_mask_t glyph_mask = c->buffer->info[c->buffer->idx].mask;
     263               0 :     hb_mask_t lookup_mask = c->lookup_mask;
     264                 : 
     265               0 :     unsigned int index = (this+coverage) (glyph_id);
     266               0 :     if (likely (index == NOT_COVERED))
     267               0 :       return false;
     268                 : 
     269               0 :     const AlternateSet &alt_set = this+alternateSet[index];
     270                 : 
     271               0 :     if (unlikely (!alt_set.len))
     272               0 :       return false;
     273                 : 
     274                 :     /* Note: This breaks badly if two features enabled this lookup together. */
     275               0 :     unsigned int shift = _hb_ctz (lookup_mask);
     276               0 :     unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
     277                 : 
     278               0 :     if (unlikely (alt_index > alt_set.len || alt_index == 0))
     279               0 :       return false;
     280                 : 
     281               0 :     glyph_id = alt_set[alt_index - 1];
     282                 : 
     283               0 :     c->replace_glyph (glyph_id);
     284                 : 
     285               0 :     return true;
     286                 :   }
     287                 : 
     288               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
     289               0 :     TRACE_SANITIZE ();
     290               0 :     return coverage.sanitize (c, this)
     291               0 :         && alternateSet.sanitize (c, this);
     292                 :   }
     293                 : 
     294                 :   private:
     295                 :   USHORT        format;                 /* Format identifier--format = 1 */
     296                 :   OffsetTo<Coverage>
     297                 :                 coverage;               /* Offset to Coverage table--from
     298                 :                                          * beginning of Substitution table */
     299                 :   OffsetArrayOf<AlternateSet>
     300                 :                 alternateSet;           /* Array of AlternateSet tables
     301                 :                                          * ordered by Coverage Index */
     302                 :   public:
     303                 :   DEFINE_SIZE_ARRAY (6, alternateSet);
     304                 : };
     305                 : 
     306                 : struct AlternateSubst
     307                 : {
     308                 :   friend struct SubstLookupSubTable;
     309                 : 
     310                 :   private:
     311                 : 
     312               0 :   inline bool apply (hb_apply_context_t *c) const
     313                 :   {
     314               0 :     TRACE_APPLY ();
     315               0 :     switch (u.format) {
     316               0 :     case 1: return u.format1.apply (c);
     317               0 :     default:return false;
     318                 :     }
     319                 :   }
     320                 : 
     321               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
     322               0 :     TRACE_SANITIZE ();
     323               0 :     if (!u.format.sanitize (c)) return false;
     324               0 :     switch (u.format) {
     325               0 :     case 1: return u.format1.sanitize (c);
     326               0 :     default:return true;
     327                 :     }
     328                 :   }
     329                 : 
     330                 :   private:
     331                 :   union {
     332                 :   USHORT                format;         /* Format identifier */
     333                 :   AlternateSubstFormat1 format1;
     334                 :   } u;
     335                 : };
     336                 : 
     337                 : 
     338                 : struct Ligature
     339                 : {
     340                 :   friend struct LigatureSet;
     341                 : 
     342                 :   private:
     343               0 :   inline bool apply (hb_apply_context_t *c) const
     344                 :   {
     345               0 :     TRACE_APPLY ();
     346               0 :     unsigned int count = component.len;
     347               0 :     if (unlikely (count < 2))
     348               0 :       return false;
     349                 : 
     350               0 :     hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
     351               0 :     if (skippy_iter.has_no_chance ())
     352               0 :       return false;
     353                 : 
     354               0 :     bool first_was_mark = (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
     355               0 :     bool found_non_mark = false;
     356                 : 
     357               0 :     for (unsigned int i = 1; i < count; i++)
     358                 :     {
     359                 :       unsigned int property;
     360                 : 
     361               0 :       if (!skippy_iter.next (&property))
     362               0 :         return false;
     363                 : 
     364               0 :       found_non_mark |= !(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
     365                 : 
     366               0 :       if (likely (c->buffer->info[skippy_iter.idx].codepoint != component[i]))
     367               0 :         return false;
     368                 :     }
     369                 : 
     370               0 :     if (first_was_mark && found_non_mark)
     371               0 :       c->guess_glyph_class (HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE);
     372                 : 
     373                 :     /* Allocate new ligature id */
     374               0 :     unsigned int lig_id = allocate_lig_id (c->buffer);
     375               0 :     c->buffer->info[c->buffer->idx].lig_comp() = 0;
     376               0 :     c->buffer->info[c->buffer->idx].lig_id() = lig_id;
     377                 : 
     378               0 :     if (skippy_iter.idx < c->buffer->idx + count) /* No input glyphs skipped */
     379                 :     {
     380               0 :       c->replace_glyphs_be16 (count, 1, (const uint16_t *) &ligGlyph);
     381                 :     }
     382                 :     else
     383                 :     {
     384               0 :       c->replace_glyph (ligGlyph);
     385                 : 
     386                 :       /* Now we must do a second loop to copy the skipped glyphs to
     387                 :          `out' and assign component values to it.  We start with the
     388                 :          glyph after the first component.  Glyphs between component
     389                 :          i and i+1 belong to component i.  Together with the lig_id
     390                 :          value it is later possible to check whether a specific
     391                 :          component value really belongs to a given ligature. */
     392                 : 
     393               0 :       for (unsigned int i = 1; i < count; i++)
     394                 :       {
     395               0 :         while (c->should_mark_skip_current_glyph ())
     396                 :         {
     397               0 :           c->buffer->info[c->buffer->idx].lig_comp() = i;
     398               0 :           c->buffer->info[c->buffer->idx].lig_id() = lig_id;
     399               0 :           c->replace_glyph (c->buffer->info[c->buffer->idx].codepoint);
     400                 :         }
     401                 : 
     402                 :         /* Skip the base glyph */
     403               0 :         c->buffer->idx++;
     404                 :       }
     405                 :     }
     406                 : 
     407               0 :     return true;
     408                 :   }
     409                 : 
     410                 :   public:
     411               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
     412               0 :     TRACE_SANITIZE ();
     413               0 :     return ligGlyph.sanitize (c)
     414               0 :         && component.sanitize (c);
     415                 :   }
     416                 : 
     417                 :   private:
     418                 :   GlyphID       ligGlyph;               /* GlyphID of ligature to substitute */
     419                 :   HeadlessArrayOf<GlyphID>
     420                 :                 component;              /* Array of component GlyphIDs--start
     421                 :                                          * with the second  component--ordered
     422                 :                                          * in writing direction */
     423                 :   public:
     424                 :   DEFINE_SIZE_ARRAY (4, component);
     425                 : };
     426                 : 
     427                 : struct LigatureSet
     428                 : {
     429                 :   friend struct LigatureSubstFormat1;
     430                 : 
     431                 :   private:
     432               0 :   inline bool apply (hb_apply_context_t *c) const
     433                 :   {
     434               0 :     TRACE_APPLY ();
     435               0 :     unsigned int num_ligs = ligature.len;
     436               0 :     for (unsigned int i = 0; i < num_ligs; i++)
     437                 :     {
     438               0 :       const Ligature &lig = this+ligature[i];
     439               0 :       if (lig.apply (c))
     440               0 :         return true;
     441                 :     }
     442                 : 
     443               0 :     return false;
     444                 :   }
     445                 : 
     446                 :   public:
     447               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
     448               0 :     TRACE_SANITIZE ();
     449               0 :     return ligature.sanitize (c, this);
     450                 :   }
     451                 : 
     452                 :   private:
     453                 :   OffsetArrayOf<Ligature>
     454                 :                 ligature;               /* Array LigatureSet tables
     455                 :                                          * ordered by preference */
     456                 :   public:
     457                 :   DEFINE_SIZE_ARRAY (2, ligature);
     458                 : };
     459                 : 
     460                 : struct LigatureSubstFormat1
     461                 : {
     462                 :   friend struct LigatureSubst;
     463                 : 
     464                 :   private:
     465               0 :   inline bool apply (hb_apply_context_t *c) const
     466                 :   {
     467               0 :     TRACE_APPLY ();
     468               0 :     hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint;
     469                 : 
     470               0 :     unsigned int index = (this+coverage) (glyph_id);
     471               0 :     if (likely (index == NOT_COVERED))
     472               0 :       return false;
     473                 : 
     474               0 :     const LigatureSet &lig_set = this+ligatureSet[index];
     475               0 :     return lig_set.apply (c);
     476                 :   }
     477                 : 
     478               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
     479               0 :     TRACE_SANITIZE ();
     480               0 :     return coverage.sanitize (c, this)
     481               0 :         && ligatureSet.sanitize (c, this);
     482                 :   }
     483                 : 
     484                 :   private:
     485                 :   USHORT        format;                 /* Format identifier--format = 1 */
     486                 :   OffsetTo<Coverage>
     487                 :                 coverage;               /* Offset to Coverage table--from
     488                 :                                          * beginning of Substitution table */
     489                 :   OffsetArrayOf<LigatureSet>
     490                 :                 ligatureSet;            /* Array LigatureSet tables
     491                 :                                          * ordered by Coverage Index */
     492                 :   public:
     493                 :   DEFINE_SIZE_ARRAY (6, ligatureSet);
     494                 : };
     495                 : 
     496                 : struct LigatureSubst
     497                 : {
     498                 :   friend struct SubstLookupSubTable;
     499                 : 
     500                 :   private:
     501               0 :   inline bool apply (hb_apply_context_t *c) const
     502                 :   {
     503               0 :     TRACE_APPLY ();
     504               0 :     switch (u.format) {
     505               0 :     case 1: return u.format1.apply (c);
     506               0 :     default:return false;
     507                 :     }
     508                 :   }
     509                 : 
     510               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
     511               0 :     TRACE_SANITIZE ();
     512               0 :     if (!u.format.sanitize (c)) return false;
     513               0 :     switch (u.format) {
     514               0 :     case 1: return u.format1.sanitize (c);
     515               0 :     default:return true;
     516                 :     }
     517                 :   }
     518                 : 
     519                 :   private:
     520                 :   union {
     521                 :   USHORT                format;         /* Format identifier */
     522                 :   LigatureSubstFormat1  format1;
     523                 :   } u;
     524                 : };
     525                 : 
     526                 : 
     527                 : static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
     528                 : 
     529                 : struct ContextSubst : Context
     530                 : {
     531                 :   friend struct SubstLookupSubTable;
     532                 : 
     533                 :   private:
     534               0 :   inline bool apply (hb_apply_context_t *c) const
     535                 :   {
     536               0 :     TRACE_APPLY ();
     537               0 :     return Context::apply (c, substitute_lookup);
     538                 :   }
     539                 : };
     540                 : 
     541                 : struct ChainContextSubst : ChainContext
     542                 : {
     543                 :   friend struct SubstLookupSubTable;
     544                 : 
     545                 :   private:
     546               0 :   inline bool apply (hb_apply_context_t *c) const
     547                 :   {
     548               0 :     TRACE_APPLY ();
     549               0 :     return ChainContext::apply (c, substitute_lookup);
     550                 :   }
     551                 : };
     552                 : 
     553                 : 
     554                 : struct ExtensionSubst : Extension
     555                 : {
     556                 :   friend struct SubstLookupSubTable;
     557                 :   friend struct SubstLookup;
     558                 : 
     559                 :   private:
     560               0 :   inline const struct SubstLookupSubTable& get_subtable (void) const
     561                 :   {
     562               0 :     unsigned int offset = get_offset ();
     563               0 :     if (unlikely (!offset)) return Null(SubstLookupSubTable);
     564               0 :     return StructAtOffset<SubstLookupSubTable> (this, offset);
     565                 :   }
     566                 : 
     567                 :   inline bool apply (hb_apply_context_t *c) const;
     568                 : 
     569                 :   inline bool sanitize (hb_sanitize_context_t *c);
     570                 : 
     571                 :   inline bool is_reverse (void) const;
     572                 : };
     573                 : 
     574                 : 
     575                 : struct ReverseChainSingleSubstFormat1
     576                 : {
     577                 :   friend struct ReverseChainSingleSubst;
     578                 : 
     579                 :   private:
     580               0 :   inline bool apply (hb_apply_context_t *c) const
     581                 :   {
     582               0 :     TRACE_APPLY ();
     583               0 :     if (unlikely (c->context_length != NO_CONTEXT))
     584               0 :       return false; /* No chaining to this type */
     585                 : 
     586               0 :     unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
     587               0 :     if (likely (index == NOT_COVERED))
     588               0 :       return false;
     589                 : 
     590               0 :     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     591               0 :     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
     592                 : 
     593               0 :     if (match_backtrack (c,
     594                 :                          backtrack.len, (USHORT *) backtrack.array,
     595               0 :                          match_coverage, this) &&
     596                 :         match_lookahead (c,
     597                 :                          lookahead.len, (USHORT *) lookahead.array,
     598                 :                          match_coverage, this,
     599               0 :                          1))
     600                 :     {
     601               0 :       c->buffer->info[c->buffer->idx].codepoint = substitute[index];
     602               0 :       c->buffer->idx--; /* Reverse! */
     603               0 :       return true;
     604                 :     }
     605                 : 
     606               0 :     return false;
     607                 :   }
     608                 : 
     609               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
     610               0 :     TRACE_SANITIZE ();
     611               0 :     if (!(coverage.sanitize (c, this)
     612               0 :        && backtrack.sanitize (c, this)))
     613               0 :       return false;
     614               0 :     OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     615               0 :     if (!lookahead.sanitize (c, this))
     616               0 :       return false;
     617               0 :     ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
     618               0 :     return substitute.sanitize (c);
     619                 :   }
     620                 : 
     621                 :   private:
     622                 :   USHORT        format;                 /* Format identifier--format = 1 */
     623                 :   OffsetTo<Coverage>
     624                 :                 coverage;               /* Offset to Coverage table--from
     625                 :                                          * beginning of table */
     626                 :   OffsetArrayOf<Coverage>
     627                 :                 backtrack;              /* Array of coverage tables
     628                 :                                          * in backtracking sequence, in  glyph
     629                 :                                          * sequence order */
     630                 :   OffsetArrayOf<Coverage>
     631                 :                 lookaheadX;             /* Array of coverage tables
     632                 :                                          * in lookahead sequence, in glyph
     633                 :                                          * sequence order */
     634                 :   ArrayOf<GlyphID>
     635                 :                 substituteX;            /* Array of substitute
     636                 :                                          * GlyphIDs--ordered by Coverage Index */
     637                 :   public:
     638                 :   DEFINE_SIZE_MIN (10);
     639                 : };
     640                 : 
     641                 : struct ReverseChainSingleSubst
     642                 : {
     643                 :   friend struct SubstLookupSubTable;
     644                 : 
     645                 :   private:
     646               0 :   inline bool apply (hb_apply_context_t *c) const
     647                 :   {
     648               0 :     TRACE_APPLY ();
     649               0 :     switch (u.format) {
     650               0 :     case 1: return u.format1.apply (c);
     651               0 :     default:return false;
     652                 :     }
     653                 :   }
     654                 : 
     655               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
     656               0 :     TRACE_SANITIZE ();
     657               0 :     if (!u.format.sanitize (c)) return false;
     658               0 :     switch (u.format) {
     659               0 :     case 1: return u.format1.sanitize (c);
     660               0 :     default:return true;
     661                 :     }
     662                 :   }
     663                 : 
     664                 :   private:
     665                 :   union {
     666                 :   USHORT                                format;         /* Format identifier */
     667                 :   ReverseChainSingleSubstFormat1        format1;
     668                 :   } u;
     669                 : };
     670                 : 
     671                 : 
     672                 : 
     673                 : /*
     674                 :  * SubstLookup
     675                 :  */
     676                 : 
     677                 : struct SubstLookupSubTable
     678                 : {
     679                 :   friend struct SubstLookup;
     680                 : 
     681                 :   enum {
     682                 :     Single              = 1,
     683                 :     Multiple            = 2,
     684                 :     Alternate           = 3,
     685                 :     Ligature            = 4,
     686                 :     Context             = 5,
     687                 :     ChainContext        = 6,
     688                 :     Extension           = 7,
     689                 :     ReverseChainSingle  = 8
     690                 :   };
     691                 : 
     692               0 :   inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
     693                 :   {
     694               0 :     TRACE_APPLY ();
     695               0 :     switch (lookup_type) {
     696               0 :     case Single:                return u.single.apply (c);
     697               0 :     case Multiple:              return u.multiple.apply (c);
     698               0 :     case Alternate:             return u.alternate.apply (c);
     699               0 :     case Ligature:              return u.ligature.apply (c);
     700               0 :     case Context:               return u.c.apply (c);
     701               0 :     case ChainContext:          return u.chainContext.apply (c);
     702               0 :     case Extension:             return u.extension.apply (c);
     703               0 :     case ReverseChainSingle:    return u.reverseChainContextSingle.apply (c);
     704               0 :     default:return false;
     705                 :     }
     706                 :   }
     707                 : 
     708               0 :   inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
     709               0 :     TRACE_SANITIZE ();
     710               0 :     switch (lookup_type) {
     711               0 :     case Single:                return u.single.sanitize (c);
     712               0 :     case Multiple:              return u.multiple.sanitize (c);
     713               0 :     case Alternate:             return u.alternate.sanitize (c);
     714               0 :     case Ligature:              return u.ligature.sanitize (c);
     715               0 :     case Context:               return u.c.sanitize (c);
     716               0 :     case ChainContext:          return u.chainContext.sanitize (c);
     717               0 :     case Extension:             return u.extension.sanitize (c);
     718               0 :     case ReverseChainSingle:    return u.reverseChainContextSingle.sanitize (c);
     719               0 :     default:return true;
     720                 :     }
     721                 :   }
     722                 : 
     723                 :   private:
     724                 :   union {
     725                 :   USHORT                        sub_format;
     726                 :   SingleSubst                   single;
     727                 :   MultipleSubst                 multiple;
     728                 :   AlternateSubst                alternate;
     729                 :   LigatureSubst                 ligature;
     730                 :   ContextSubst                  c;
     731                 :   ChainContextSubst             chainContext;
     732                 :   ExtensionSubst                extension;
     733                 :   ReverseChainSingleSubst       reverseChainContextSingle;
     734                 :   } u;
     735                 :   public:
     736                 :   DEFINE_SIZE_UNION (2, sub_format);
     737                 : };
     738                 : 
     739                 : 
     740                 : struct SubstLookup : Lookup
     741                 : {
     742               0 :   inline const SubstLookupSubTable& get_subtable (unsigned int i) const
     743               0 :   { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
     744                 : 
     745               0 :   inline static bool lookup_type_is_reverse (unsigned int lookup_type)
     746               0 :   { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
     747                 : 
     748               0 :   inline bool is_reverse (void) const
     749                 :   {
     750               0 :     unsigned int type = get_type ();
     751               0 :     if (unlikely (type == SubstLookupSubTable::Extension))
     752               0 :       return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
     753               0 :     return lookup_type_is_reverse (type);
     754                 :   }
     755                 : 
     756                 : 
     757               0 :   inline bool apply_once (hb_face_t *face,
     758                 :                           hb_buffer_t *buffer,
     759                 :                           hb_mask_t lookup_mask,
     760                 :                           unsigned int context_length,
     761                 :                           unsigned int nesting_level_left) const
     762                 :   {
     763               0 :     unsigned int lookup_type = get_type ();
     764               0 :     hb_apply_context_t c[1] = {{0}};
     765                 : 
     766               0 :     c->face = face;
     767               0 :     c->buffer = buffer;
     768               0 :     c->direction = buffer->props.direction;
     769               0 :     c->lookup_mask = lookup_mask;
     770               0 :     c->context_length = context_length;
     771               0 :     c->nesting_level_left = nesting_level_left;
     772               0 :     c->lookup_props = get_props ();
     773                 : 
     774               0 :     if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, &c->property))
     775               0 :       return false;
     776                 : 
     777               0 :     if (unlikely (lookup_type == SubstLookupSubTable::Extension))
     778                 :     {
     779                 :       /* The spec says all subtables should have the same type.
     780                 :        * This is specially important if one has a reverse type!
     781                 :        *
     782                 :        * This is rather slow to do this here for every glyph,
     783                 :        * but it's easiest, and who uses extension lookups anyway?!*/
     784               0 :       unsigned int count = get_subtable_count ();
     785               0 :       unsigned int type = get_subtable(0).u.extension.get_type ();
     786               0 :       for (unsigned int i = 1; i < count; i++)
     787               0 :         if (get_subtable(i).u.extension.get_type () != type)
     788               0 :           return false;
     789                 :     }
     790                 : 
     791               0 :     unsigned int count = get_subtable_count ();
     792               0 :     for (unsigned int i = 0; i < count; i++)
     793               0 :       if (get_subtable (i).apply (c, lookup_type))
     794               0 :         return true;
     795                 : 
     796               0 :     return false;
     797                 :   }
     798                 : 
     799               0 :   inline bool apply_string (hb_face_t   *face,
     800                 :                             hb_buffer_t *buffer,
     801                 :                             hb_mask_t    mask) const
     802                 :   {
     803               0 :     bool ret = false;
     804                 : 
     805               0 :     if (unlikely (!buffer->len))
     806               0 :       return false;
     807                 : 
     808               0 :     if (likely (!is_reverse ()))
     809                 :     {
     810                 :         /* in/out forward substitution */
     811               0 :         buffer->clear_output ();
     812               0 :         buffer->idx = 0;
     813               0 :         while (buffer->idx < buffer->len)
     814                 :         {
     815               0 :           if ((buffer->info[buffer->idx].mask & mask) &&
     816               0 :               apply_once (face, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
     817               0 :             ret = true;
     818                 :           else
     819               0 :             buffer->next_glyph ();
     820                 : 
     821                 :         }
     822               0 :         if (ret)
     823               0 :           buffer->swap_buffers ();
     824                 :     }
     825                 :     else
     826                 :     {
     827                 :         /* in-place backward substitution */
     828               0 :         buffer->idx = buffer->len - 1;
     829               0 :         do
     830                 :         {
     831               0 :           if ((buffer->info[buffer->idx].mask & mask) &&
     832               0 :               apply_once (face, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
     833               0 :             ret = true;
     834                 :           else
     835               0 :             buffer->idx--;
     836                 : 
     837                 :         }
     838                 :         while ((int) buffer->idx >= 0);
     839                 :     }
     840                 : 
     841               0 :     return ret;
     842                 :   }
     843                 : 
     844               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
     845               0 :     TRACE_SANITIZE ();
     846               0 :     if (unlikely (!Lookup::sanitize (c))) return false;
     847               0 :     OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
     848               0 :     return list.sanitize (c, this, get_type ());
     849                 :   }
     850                 : };
     851                 : 
     852                 : typedef OffsetListOf<SubstLookup> SubstLookupList;
     853                 : 
     854                 : /*
     855                 :  * GSUB -- The Glyph Substitution Table
     856                 :  */
     857                 : 
     858                 : struct GSUB : GSUBGPOS
     859                 : {
     860                 :   static const hb_tag_t Tag     = HB_OT_TAG_GSUB;
     861                 : 
     862               0 :   inline const SubstLookup& get_lookup (unsigned int i) const
     863               0 :   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
     864                 : 
     865               0 :   inline bool substitute_lookup (hb_face_t    *face,
     866                 :                                  hb_buffer_t  *buffer,
     867                 :                                  unsigned int  lookup_index,
     868                 :                                  hb_mask_t     mask) const
     869               0 :   { return get_lookup (lookup_index).apply_string (face, buffer, mask); }
     870                 : 
     871                 :   static inline void substitute_start (hb_buffer_t *buffer);
     872                 :   static inline void substitute_finish (hb_buffer_t *buffer);
     873                 : 
     874               0 :   inline bool sanitize (hb_sanitize_context_t *c) {
     875               0 :     TRACE_SANITIZE ();
     876               0 :     if (unlikely (!GSUBGPOS::sanitize (c))) return false;
     877               0 :     OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
     878               0 :     return list.sanitize (c, this);
     879                 :   }
     880                 :   public:
     881                 :   DEFINE_SIZE_STATIC (10);
     882                 : };
     883                 : 
     884                 : 
     885                 : void
     886               0 : GSUB::substitute_start (hb_buffer_t *buffer)
     887                 : {
     888               0 :   HB_BUFFER_ALLOCATE_VAR (buffer, props_cache);
     889               0 :   HB_BUFFER_ALLOCATE_VAR (buffer, lig_id);
     890               0 :   HB_BUFFER_ALLOCATE_VAR (buffer, lig_comp);
     891                 : 
     892               0 :   unsigned int count = buffer->len;
     893               0 :   for (unsigned int i = 0; i < count; i++)
     894               0 :     buffer->info[i].props_cache() = buffer->info[i].lig_id() = buffer->info[i].lig_comp() = 0;
     895               0 : }
     896                 : 
     897                 : void
     898               0 : GSUB::substitute_finish (hb_buffer_t *buffer)
     899                 : {
     900               0 : }
     901                 : 
     902                 : 
     903                 : /* Out-of-class implementation for methods recursing */
     904                 : 
     905               0 : inline bool ExtensionSubst::apply (hb_apply_context_t *c) const
     906                 : {
     907               0 :   TRACE_APPLY ();
     908               0 :   return get_subtable ().apply (c, get_type ());
     909                 : }
     910                 : 
     911               0 : inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
     912                 : {
     913               0 :   TRACE_SANITIZE ();
     914               0 :   if (unlikely (!Extension::sanitize (c))) return false;
     915               0 :   unsigned int offset = get_offset ();
     916               0 :   if (unlikely (!offset)) return true;
     917               0 :   return StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ());
     918                 : }
     919                 : 
     920               0 : inline bool ExtensionSubst::is_reverse (void) const
     921                 : {
     922               0 :   unsigned int type = get_type ();
     923               0 :   if (unlikely (type == SubstLookupSubTable::Extension))
     924               0 :     return CastR<ExtensionSubst> (get_subtable()).is_reverse ();
     925               0 :   return SubstLookup::lookup_type_is_reverse (type);
     926                 : }
     927                 : 
     928               0 : static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
     929                 : {
     930               0 :   const GSUB &gsub = *(c->face->ot_layout->gsub);
     931               0 :   const SubstLookup &l = gsub.get_lookup (lookup_index);
     932                 : 
     933               0 :   if (unlikely (c->nesting_level_left == 0))
     934               0 :     return false;
     935                 : 
     936               0 :   if (unlikely (c->context_length < 1))
     937               0 :     return false;
     938                 : 
     939               0 :   return l.apply_once (c->face, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1);
     940                 : }
     941                 : 
     942                 : 
     943                 : 
     944                 : #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */

Generated by: LCOV version 1.7