1 /*
   2  * Copyright © 2016  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): Seigo Nonaka
  25  */
  26 
  27 #ifndef HB_OT_CBDT_TABLE_HH
  28 #define HB_OT_CBDT_TABLE_HH
  29 
  30 #include "hb-open-type-private.hh"
  31 
  32 namespace OT {
  33 
  34 struct SmallGlyphMetrics
  35 {
  36   inline bool sanitize (hb_sanitize_context_t *c) const
  37   {
  38     TRACE_SANITIZE (this);
  39     return_trace (c->check_struct (this));
  40   }
  41 
  42   inline void get_extents (hb_glyph_extents_t *extents) const
  43   {
  44     extents->x_bearing = bearingX;
  45     extents->y_bearing = bearingY;
  46     extents->width = width;
  47     extents->height = -height;
  48   }
  49 
  50   BYTE height;
  51   BYTE width;
  52   CHAR bearingX;
  53   CHAR bearingY;
  54   BYTE advance;
  55 
  56   DEFINE_SIZE_STATIC(5);
  57 };
  58 
  59 struct BigGlyphMetrics : SmallGlyphMetrics
  60 {
  61   CHAR vertBearingX;
  62   CHAR vertBearingY;
  63   BYTE vertAdvance;
  64 
  65   DEFINE_SIZE_STATIC(8);
  66 };
  67 
  68 struct SBitLineMetrics
  69 {
  70   inline bool sanitize (hb_sanitize_context_t *c) const
  71   {
  72     TRACE_SANITIZE (this);
  73     return_trace (c->check_struct (this));
  74   }
  75 
  76   CHAR ascender;
  77   CHAR decender;
  78   BYTE widthMax;
  79   CHAR caretSlopeNumerator;
  80   CHAR caretSlopeDenominator;
  81   CHAR caretOffset;
  82   CHAR minOriginSB;
  83   CHAR minAdvanceSB;
  84   CHAR maxBeforeBL;
  85   CHAR minAfterBL;
  86   CHAR padding1;
  87   CHAR padding2;
  88 
  89   DEFINE_SIZE_STATIC(12);
  90 };
  91 
  92 
  93 /*
  94  * Index Subtables.
  95  */
  96 
  97 struct IndexSubtableHeader
  98 {
  99   inline bool sanitize (hb_sanitize_context_t *c) const
 100   {
 101     TRACE_SANITIZE (this);
 102     return_trace (c->check_struct (this));
 103   }
 104 
 105   USHORT indexFormat;
 106   USHORT imageFormat;
 107   ULONG imageDataOffset;
 108 
 109   DEFINE_SIZE_STATIC(8);
 110 };
 111 
 112 template <typename OffsetType>
 113 struct IndexSubtableFormat1Or3
 114 {
 115   inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
 116   {
 117     TRACE_SANITIZE (this);
 118     return_trace (c->check_struct (this) &&
 119                   c->check_array (offsetArrayZ, offsetArrayZ[0].static_size, glyph_count + 1));
 120   }
 121 
 122   bool get_image_data (unsigned int idx,
 123                        unsigned int *offset,
 124                        unsigned int *length) const
 125   {
 126     if (unlikely (offsetArrayZ[idx + 1] <= offsetArrayZ[idx]))
 127       return false;
 128 
 129     *offset = header.imageDataOffset + offsetArrayZ[idx];
 130     *length = offsetArrayZ[idx + 1] - offsetArrayZ[idx];
 131     return true;
 132   }
 133 
 134   IndexSubtableHeader header;
 135   Offset<OffsetType> offsetArrayZ[VAR];
 136 
 137   DEFINE_SIZE_ARRAY(8, offsetArrayZ);
 138 };
 139 
 140 struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<ULONG> {};
 141 struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<USHORT> {};
 142 
 143 struct IndexSubtable
 144 {
 145   inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
 146   {
 147     TRACE_SANITIZE (this);
 148     if (!u.header.sanitize (c)) return_trace (false);
 149     switch (u.header.indexFormat) {
 150     case 1: return_trace (u.format1.sanitize (c, glyph_count));
 151     case 3: return_trace (u.format3.sanitize (c, glyph_count));
 152     default:return_trace (true);
 153     }
 154   }
 155 
 156   inline bool get_extents (hb_glyph_extents_t *extents) const
 157   {
 158     switch (u.header.indexFormat) {
 159     case 2: case 5: /* TODO */
 160     case 1: case 3: case 4: /* Variable-metrics formats do not have metrics here. */
 161     default:return (false);
 162     }
 163   }
 164 
 165   bool get_image_data (unsigned int idx,
 166                        unsigned int *offset,
 167                        unsigned int *length,
 168                        unsigned int *format) const
 169   {
 170     *format = u.header.imageFormat;
 171     switch (u.header.indexFormat) {
 172     case 1: return u.format1.get_image_data (idx, offset, length);
 173     case 3: return u.format3.get_image_data (idx, offset, length);
 174     default: return false;
 175     }
 176   }
 177 
 178   protected:
 179   union {
 180   IndexSubtableHeader   header;
 181   IndexSubtableFormat1  format1;
 182   IndexSubtableFormat3  format3;
 183   /* TODO: Format 2, 4, 5. */
 184   } u;
 185   public:
 186   DEFINE_SIZE_UNION (8, header);
 187 };
 188 
 189 struct IndexSubtableRecord
 190 {
 191   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
 192   {
 193     TRACE_SANITIZE (this);
 194     return_trace (c->check_struct (this) &&
 195                   firstGlyphIndex <= lastGlyphIndex &&
 196                   offsetToSubtable.sanitize (c, this, lastGlyphIndex - firstGlyphIndex + 1));
 197   }
 198 
 199   inline bool get_extents (hb_glyph_extents_t *extents) const
 200   {
 201     return (this+offsetToSubtable).get_extents (extents);
 202   }
 203 
 204   bool get_image_data (unsigned int gid,
 205                        unsigned int *offset,
 206                        unsigned int *length,
 207                        unsigned int *format) const
 208   {
 209     if (gid < firstGlyphIndex || gid > lastGlyphIndex)
 210     {
 211       return false;
 212     }
 213     return (this+offsetToSubtable).get_image_data (gid - firstGlyphIndex,
 214                                                    offset, length, format);
 215   }
 216 
 217   USHORT firstGlyphIndex;
 218   USHORT lastGlyphIndex;
 219   LOffsetTo<IndexSubtable> offsetToSubtable;
 220 
 221   DEFINE_SIZE_STATIC(8);
 222 };
 223 
 224 struct IndexSubtableArray
 225 {
 226   inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
 227   {
 228     TRACE_SANITIZE (this);
 229     if (unlikely (!c->check_array (&indexSubtablesZ, indexSubtablesZ[0].static_size, count)))
 230       return_trace (false);
 231     for (unsigned int i = 0; i < count; i++)
 232       if (unlikely (!indexSubtablesZ[i].sanitize (c, this)))
 233         return_trace (false);
 234     return_trace (true);
 235   }
 236 
 237   public:
 238   const IndexSubtableRecord* find_table (hb_codepoint_t glyph, unsigned int numTables) const
 239   {
 240     for (unsigned int i = 0; i < numTables; ++i)
 241     {
 242       unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex;
 243       unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex;
 244       if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex) {
 245         return &indexSubtablesZ[i];
 246       }
 247     }
 248     return nullptr;
 249   }
 250 
 251   protected:
 252   IndexSubtableRecord indexSubtablesZ[VAR];
 253 
 254   public:
 255   DEFINE_SIZE_ARRAY(0, indexSubtablesZ);
 256 };
 257 
 258 struct BitmapSizeTable
 259 {
 260   friend struct CBLC;
 261 
 262   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
 263   {
 264     TRACE_SANITIZE (this);
 265     return_trace (c->check_struct (this) &&
 266                   indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) &&
 267                   c->check_range (&(base+indexSubtableArrayOffset), indexTablesSize) &&
 268                   horizontal.sanitize (c) &&
 269                   vertical.sanitize (c));
 270   }
 271 
 272   const IndexSubtableRecord *find_table (hb_codepoint_t glyph, const void *base) const
 273   {
 274     return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables);
 275   }
 276 
 277   protected:
 278   LOffsetTo<IndexSubtableArray> indexSubtableArrayOffset;
 279   ULONG indexTablesSize;
 280   ULONG numberOfIndexSubtables;
 281   ULONG colorRef;
 282   SBitLineMetrics horizontal;
 283   SBitLineMetrics vertical;
 284   USHORT startGlyphIndex;
 285   USHORT endGlyphIndex;
 286   BYTE ppemX;
 287   BYTE ppemY;
 288   BYTE bitDepth;
 289   CHAR flags;
 290 
 291 public:
 292   DEFINE_SIZE_STATIC(48);
 293 };
 294 
 295 
 296 /*
 297  * Glyph Bitmap Data Formats.
 298  */
 299 
 300 struct GlyphBitmapDataFormat17
 301 {
 302   SmallGlyphMetrics glyphMetrics;
 303   ULONG dataLen;
 304   BYTE dataZ[VAR];
 305 
 306   DEFINE_SIZE_ARRAY(9, dataZ);
 307 };
 308 
 309 
 310 /*
 311  * CBLC -- Color Bitmap Location Table
 312  */
 313 
 314 #define HB_OT_TAG_CBLC HB_TAG('C','B','L','C')
 315 
 316 struct CBLC
 317 {
 318   static const hb_tag_t tableTag = HB_OT_TAG_CBLC;
 319 
 320   inline bool sanitize (hb_sanitize_context_t *c) const
 321   {
 322     TRACE_SANITIZE (this);
 323     return_trace (c->check_struct (this) &&
 324                   likely (version.major == 2 || version.major == 3) &&
 325                   sizeTables.sanitize (c, this));
 326   }
 327 
 328   public:
 329   const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
 330                                          unsigned int *x_ppem, unsigned int *y_ppem) const
 331   {
 332     /* TODO: Make it possible to select strike. */
 333 
 334     unsigned int count = sizeTables.len;
 335     for (uint32_t i = 0; i < count; ++i)
 336     {
 337       unsigned int startGlyphIndex = sizeTables.array[i].startGlyphIndex;
 338       unsigned int endGlyphIndex = sizeTables.array[i].endGlyphIndex;
 339       if (startGlyphIndex <= glyph && glyph <= endGlyphIndex)
 340       {
 341         *x_ppem = sizeTables[i].ppemX;
 342         *y_ppem = sizeTables[i].ppemY;
 343         return sizeTables[i].find_table (glyph, this);
 344       }
 345     }
 346 
 347     return nullptr;
 348   }
 349 
 350   protected:
 351   FixedVersion<>                version;
 352   LArrayOf<BitmapSizeTable>     sizeTables;
 353 
 354   public:
 355   DEFINE_SIZE_ARRAY(8, sizeTables);
 356 };
 357 
 358 /*
 359  * CBDT -- Color Bitmap Data Table
 360  */
 361 #define HB_OT_TAG_CBDT HB_TAG('C','B','D','T')
 362 
 363 struct CBDT
 364 {
 365   static const hb_tag_t tableTag = HB_OT_TAG_CBDT;
 366 
 367   inline bool sanitize (hb_sanitize_context_t *c) const
 368   {
 369     TRACE_SANITIZE (this);
 370     return_trace (c->check_struct (this) &&
 371                   likely (version.major == 2 || version.major == 3));
 372   }
 373 
 374   protected:
 375   FixedVersion<>version;
 376   BYTE dataZ[VAR];
 377 
 378   public:
 379   DEFINE_SIZE_ARRAY(4, dataZ);
 380 };
 381 
 382 } /* namespace OT */
 383 
 384 #endif /* HB_OT_CBDT_TABLE_HH */