Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright  2017  Google, Inc.
      3  *
      4  *  This is part of HarfBuzz, a text shaping library.
      5  *
      6  * Permission is hereby granted, without written agreement and without
      7  * license or royalty fees, to use, copy, modify, and distribute this
      8  * software and its documentation for any purpose, provided that the
      9  * above copyright notice and the following two paragraphs appear in
     10  * all copies of this software.
     11  *
     12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     16  * DAMAGE.
     17  *
     18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     23  *
     24  * Google Author(s): Behdad Esfahbod
     25  */
     26 
     27 #ifndef HB_OT_KERN_TABLE_HH
     28 #define HB_OT_KERN_TABLE_HH
     29 
     30 #include "hb-open-type-private.hh"
     31 
     32 namespace OT {
     33 
     34 
     35 /*
     36  * kern -- Kerning
     37  */
     38 
     39 #define HB_OT_TAG_kern HB_TAG('k','e','r','n')
     40 
     41 struct hb_glyph_pair_t
     42 {
     43   hb_codepoint_t left;
     44   hb_codepoint_t right;
     45 };
     46 
     47 struct KernPair
     48 {
     49   inline int get_kerning (void) const
     50   { return value; }
     51 
     52   inline int cmp (const hb_glyph_pair_t &o) const
     53   {
     54     int ret = left.cmp (o.left);
     55     if (ret) return ret;
     56     return right.cmp (o.right);
     57   }
     58 
     59   inline bool sanitize (hb_sanitize_context_t *c) const
     60   {
     61     TRACE_SANITIZE (this);
     62     return_trace (c->check_struct (this));
     63   }
     64 
     65   protected:
     66   GlyphID	left;
     67   GlyphID	right;
     68   FWORD		value;
     69   public:
     70   DEFINE_SIZE_STATIC (6);
     71 };
     72 
     73 struct KernSubTableFormat0
     74 {
     75   inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
     76   {
     77     hb_glyph_pair_t pair = {left, right};
     78     int i = pairs.bsearch (pair);
     79     if (i == -1)
     80       return 0;
     81     return pairs[i].get_kerning ();
     82   }
     83 
     84   inline bool sanitize (hb_sanitize_context_t *c) const
     85   {
     86     TRACE_SANITIZE (this);
     87     return_trace (pairs.sanitize (c));
     88   }
     89 
     90   protected:
     91   BinSearchArrayOf<KernPair> pairs;	/* Array of kerning pairs. */
     92   public:
     93   DEFINE_SIZE_ARRAY (8, pairs);
     94 };
     95 
     96 struct KernClassTable
     97 {
     98   inline unsigned int get_class (hb_codepoint_t g) const { return classes[g - firstGlyph]; }
     99 
    100   inline bool sanitize (hb_sanitize_context_t *c) const
    101   {
    102     TRACE_SANITIZE (this);
    103     return_trace (firstGlyph.sanitize (c) && classes.sanitize (c));
    104   }
    105 
    106   protected:
    107   UINT16		firstGlyph;	/* First glyph in class range. */
    108   ArrayOf<UINT16>	classes;	/* Glyph classes. */
    109   public:
    110   DEFINE_SIZE_ARRAY (4, classes);
    111 };
    112 
    113 struct KernSubTableFormat2
    114 {
    115   inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
    116   {
    117     unsigned int l = (this+leftClassTable).get_class (left);
    118     unsigned int r = (this+leftClassTable).get_class (left);
    119     unsigned int offset = l * rowWidth + r * sizeof (FWORD);
    120     const FWORD *arr = &(this+array);
    121     if (unlikely ((const void *) arr < (const void *) this || (const void *) arr >= (const void *) end))
    122       return 0;
    123     const FWORD *v = &StructAtOffset<FWORD> (arr, offset);
    124     if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end))
    125       return 0;
    126     return *v;
    127   }
    128 
    129   inline bool sanitize (hb_sanitize_context_t *c) const
    130   {
    131     TRACE_SANITIZE (this);
    132     return_trace (rowWidth.sanitize (c) &&
    133 		  leftClassTable.sanitize (c, this) &&
    134 		  rightClassTable.sanitize (c, this) &&
    135 		  array.sanitize (c, this));
    136   }
    137 
    138   protected:
    139   UINT16	rowWidth;	/* The width, in bytes, of a row in the table. */
    140   OffsetTo<KernClassTable>
    141 		leftClassTable;	/* Offset from beginning of this subtable to
    142 				 * left-hand class table. */
    143   OffsetTo<KernClassTable>
    144 		rightClassTable;/* Offset from beginning of this subtable to
    145 				 * right-hand class table. */
    146   OffsetTo<FWORD>
    147 		array;		/* Offset from beginning of this subtable to
    148 				 * the start of the kerning array. */
    149   public:
    150   DEFINE_SIZE_MIN (8);
    151 };
    152 
    153 struct KernSubTable
    154 {
    155   inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end, unsigned int format) const
    156   {
    157     switch (format) {
    158     case 0: return u.format0.get_kerning (left, right);
    159     case 2: return u.format2.get_kerning (left, right, end);
    160     default:return 0;
    161     }
    162   }
    163 
    164   inline bool sanitize (hb_sanitize_context_t *c, unsigned int format) const
    165   {
    166     TRACE_SANITIZE (this);
    167     switch (format) {
    168     case 0: return_trace (u.format0.sanitize (c));
    169     case 2: return_trace (u.format2.sanitize (c));
    170     default:return_trace (true);
    171     }
    172   }
    173 
    174   protected:
    175   union {
    176   KernSubTableFormat0	format0;
    177   KernSubTableFormat2	format2;
    178   } u;
    179   public:
    180   DEFINE_SIZE_MIN (0);
    181 };
    182 
    183 
    184 template <typename T>
    185 struct KernSubTableWrapper
    186 {
    187   /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
    188   inline const T* thiz (void) const { return static_cast<const T *> (this); }
    189 
    190   inline bool is_horizontal (void) const
    191   { return (thiz()->coverage & T::COVERAGE_CHECK_FLAGS) == T::COVERAGE_CHECK_HORIZONTAL; }
    192 
    193   inline bool is_override (void) const
    194   { return bool (thiz()->coverage & T::COVERAGE_OVERRIDE_FLAG); }
    195 
    196   inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
    197   { return thiz()->subtable.get_kerning (left, right, end, thiz()->format); }
    198 
    199   inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
    200   { return is_horizontal () ? get_kerning (left, right, end) : 0; }
    201 
    202   inline unsigned int get_size (void) const { return thiz()->length; }
    203 
    204   inline bool sanitize (hb_sanitize_context_t *c) const
    205   {
    206     TRACE_SANITIZE (this);
    207     return_trace (c->check_struct (thiz()) &&
    208 		  thiz()->length >= thiz()->min_size &&
    209 		  c->check_array (thiz(), 1, thiz()->length) &&
    210 		  thiz()->subtable.sanitize (c, thiz()->format));
    211   }
    212 };
    213 
    214 template <typename T>
    215 struct KernTable
    216 {
    217   /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
    218   inline const T* thiz (void) const { return static_cast<const T *> (this); }
    219 
    220   inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int table_length) const
    221   {
    222     int v = 0;
    223     const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (thiz()->data);
    224     unsigned int count = thiz()->nTables;
    225     for (unsigned int i = 0; i < count; i++)
    226     {
    227       if (st->is_override ())
    228         v = 0;
    229       v += st->get_h_kerning (left, right, table_length + (const char *) this);
    230       st = &StructAfter<typename T::SubTableWrapper> (*st);
    231     }
    232     return v;
    233   }
    234 
    235   inline bool sanitize (hb_sanitize_context_t *c) const
    236   {
    237     TRACE_SANITIZE (this);
    238     if (unlikely (!c->check_struct (thiz()) ||
    239 		  thiz()->version != T::VERSION))
    240       return_trace (false);
    241 
    242     const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (thiz()->data);
    243     unsigned int count = thiz()->nTables;
    244     for (unsigned int i = 0; i < count; i++)
    245     {
    246       if (unlikely (!st->sanitize (c)))
    247 	return_trace (false);
    248       st = &StructAfter<typename T::SubTableWrapper> (*st);
    249     }
    250 
    251     return_trace (true);
    252   }
    253 };
    254 
    255 struct KernOT : KernTable<KernOT>
    256 {
    257   friend struct KernTable<KernOT>;
    258 
    259   static const uint16_t VERSION = 0x0000u;
    260 
    261   struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper>
    262   {
    263     friend struct KernSubTableWrapper<SubTableWrapper>;
    264 
    265     enum coverage_flags_t {
    266       COVERAGE_DIRECTION_FLAG	= 0x01u,
    267       COVERAGE_MINIMUM_FLAG	= 0x02u,
    268       COVERAGE_CROSSSTREAM_FLAG	= 0x04u,
    269       COVERAGE_OVERRIDE_FLAG	= 0x08u,
    270 
    271       COVERAGE_VARIATION_FLAG	= 0x00u, /* Not supported. */
    272 
    273       COVERAGE_CHECK_FLAGS	= 0x07u,
    274       COVERAGE_CHECK_HORIZONTAL	= 0x01u
    275     };
    276 
    277     protected:
    278     UINT16	versionZ;	/* Unused. */
    279     UINT16	length;		/* Length of the subtable (including this header). */
    280     UINT8	format;		/* Subtable format. */
    281     UINT8	coverage;	/* Coverage bits. */
    282     KernSubTable subtable;	/* Subtable data. */
    283     public:
    284     DEFINE_SIZE_MIN (6);
    285   };
    286 
    287   protected:
    288   UINT16	version;	/* Version--0x0000u */
    289   UINT16	nTables;	/* Number of subtables in the kerning table. */
    290   UINT8		data[VAR];
    291   public:
    292   DEFINE_SIZE_ARRAY (4, data);
    293 };
    294 
    295 struct KernAAT : KernTable<KernAAT>
    296 {
    297   friend struct KernTable<KernAAT>;
    298 
    299   static const uint32_t VERSION = 0x00010000u;
    300 
    301   struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper>
    302   {
    303     friend struct KernSubTableWrapper<SubTableWrapper>;
    304 
    305     enum coverage_flags_t {
    306       COVERAGE_DIRECTION_FLAG	= 0x80u,
    307       COVERAGE_CROSSSTREAM_FLAG	= 0x40u,
    308       COVERAGE_VARIATION_FLAG	= 0x20u,
    309 
    310       COVERAGE_OVERRIDE_FLAG	= 0x00u, /* Not supported. */
    311 
    312       COVERAGE_CHECK_FLAGS	= 0xE0u,
    313       COVERAGE_CHECK_HORIZONTAL	= 0x00u
    314     };
    315 
    316     protected:
    317     UINT32	length;		/* Length of the subtable (including this header). */
    318     UINT8	coverage;	/* Coverage bits. */
    319     UINT8	format;		/* Subtable format. */
    320     UINT16	tupleIndex;	/* The tuple index (used for variations fonts).
    321 				 * This value specifies which tuple this subtable covers. */
    322     KernSubTable subtable;	/* Subtable data. */
    323     public:
    324     DEFINE_SIZE_MIN (8);
    325   };
    326 
    327   protected:
    328   UINT32		version;	/* Version--0x00010000u */
    329   UINT32		nTables;	/* Number of subtables in the kerning table. */
    330   UINT8		data[VAR];
    331   public:
    332   DEFINE_SIZE_ARRAY (8, data);
    333 };
    334 
    335 struct kern
    336 {
    337   static const hb_tag_t tableTag = HB_OT_TAG_kern;
    338 
    339   inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int table_length) const
    340   {
    341     switch (u.major) {
    342     case 0: return u.ot.get_h_kerning (left, right, table_length);
    343     case 1: return u.aat.get_h_kerning (left, right, table_length);
    344     default:return 0;
    345     }
    346   }
    347 
    348   inline bool sanitize (hb_sanitize_context_t *c) const
    349   {
    350     TRACE_SANITIZE (this);
    351     if (!u.major.sanitize (c)) return_trace (false);
    352     switch (u.major) {
    353     case 0: return_trace (u.ot.sanitize (c));
    354     case 1: return_trace (u.aat.sanitize (c));
    355     default:return_trace (true);
    356     }
    357   }
    358 
    359   struct accelerator_t
    360   {
    361     inline void init (hb_face_t *face)
    362     {
    363       blob = Sanitizer<kern>::sanitize (face->reference_table (HB_OT_TAG_kern));
    364       table = Sanitizer<kern>::lock_instance (blob);
    365       table_length = hb_blob_get_length (blob);
    366     }
    367     inline void fini (void)
    368     {
    369       hb_blob_destroy (blob);
    370     }
    371 
    372     inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
    373     { return table->get_h_kerning (left, right, table_length); }
    374 
    375     private:
    376     hb_blob_t *blob;
    377     const kern *table;
    378     unsigned int table_length;
    379   };
    380 
    381   protected:
    382   union {
    383   UINT16		major;
    384   KernOT		ot;
    385   KernAAT		aat;
    386   } u;
    387   public:
    388   DEFINE_SIZE_UNION (2, major);
    389 };
    390 
    391 } /* namespace OT */
    392 
    393 
    394 #endif /* HB_OT_KERN_TABLE_HH */
    395