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

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