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   USHORT                firstGlyph;     /* First glyph in class range. */
 108   ArrayOf<USHORT>       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   USHORT        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     USHORT      versionZ;       /* Unused. */
 279     USHORT      length;         /* Length of the subtable (including this header). */
 280     BYTE        format;         /* Subtable format. */
 281     BYTE        coverage;       /* Coverage bits. */
 282     KernSubTable subtable;      /* Subtable data. */
 283     public:
 284     DEFINE_SIZE_MIN (6);
 285   };
 286 
 287   protected:
 288   USHORT        version;        /* Version--0x0000u */
 289   USHORT        nTables;        /* Number of subtables in the kerning table. */
 290   BYTE          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     ULONG       length;         /* Length of the subtable (including this header). */
 318     BYTE        coverage;       /* Coverage bits. */
 319     BYTE        format;         /* Subtable format. */
 320     USHORT      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   ULONG         version;        /* Version--0x00010000u */
 329   ULONG         nTables;        /* Number of subtables in the kerning table. */
 330   BYTE          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 (const kern *table_, unsigned int table_length_)
 362     {
 363       table = table_;
 364       table_length = table_length_;
 365     }
 366     inline void fini (void) {}
 367 
 368     inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
 369     { return table->get_h_kerning (left, right, table_length); }
 370 
 371     private:
 372     const kern *table;
 373     unsigned int table_length;
 374   };
 375 
 376   protected:
 377   union {
 378   USHORT                major;
 379   KernOT                ot;
 380   KernAAT               aat;
 381   } u;
 382   public:
 383   DEFINE_SIZE_UNION (2, major);
 384 };
 385 
 386 } /* namespace OT */
 387 
 388 
 389 #endif /* HB_OT_KERN_TABLE_HH */