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_COLOR_CBDT_TABLE_HH
  28 #define HB_OT_COLOR_CBDT_TABLE_HH
  29 
  30 #include "hb-open-type.hh"
  31 
  32 /*
  33  * CBLC -- Color Bitmap Location
  34  * https://docs.microsoft.com/en-us/typography/opentype/spec/cblc
  35  * https://docs.microsoft.com/en-us/typography/opentype/spec/eblc
  36  * CBDT -- Color Bitmap Data
  37  * https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt
  38  * https://docs.microsoft.com/en-us/typography/opentype/spec/ebdt
  39  */
  40 #define HB_OT_TAG_CBLC HB_TAG('C','B','L','C')
  41 #define HB_OT_TAG_CBDT HB_TAG('C','B','D','T')
  42 
  43 
  44 namespace OT {
  45 
  46 struct SmallGlyphMetrics
  47 {
  48   bool sanitize (hb_sanitize_context_t *c) const
  49   {
  50     TRACE_SANITIZE (this);
  51     return_trace (c->check_struct (this));
  52   }
  53 
  54   void get_extents (hb_glyph_extents_t *extents) const
  55   {
  56     extents->x_bearing = bearingX;
  57     extents->y_bearing = bearingY;
  58     extents->width = width;
  59     extents->height = - (hb_position_t) height;
  60   }
  61 
  62   HBUINT8       height;
  63   HBUINT8       width;
  64   HBINT8        bearingX;
  65   HBINT8        bearingY;
  66   HBUINT8       advance;
  67   public:
  68   DEFINE_SIZE_STATIC(5);
  69 };
  70 
  71 struct BigGlyphMetrics : SmallGlyphMetrics
  72 {
  73   HBINT8        vertBearingX;
  74   HBINT8        vertBearingY;
  75   HBUINT8       vertAdvance;
  76   public:
  77   DEFINE_SIZE_STATIC(8);
  78 };
  79 
  80 struct SBitLineMetrics
  81 {
  82   bool sanitize (hb_sanitize_context_t *c) const
  83   {
  84     TRACE_SANITIZE (this);
  85     return_trace (c->check_struct (this));
  86   }
  87 
  88   HBINT8        ascender;
  89   HBINT8        decender;
  90   HBUINT8       widthMax;
  91   HBINT8        caretSlopeNumerator;
  92   HBINT8        caretSlopeDenominator;
  93   HBINT8        caretOffset;
  94   HBINT8        minOriginSB;
  95   HBINT8        minAdvanceSB;
  96   HBINT8        maxBeforeBL;
  97   HBINT8        minAfterBL;
  98   HBINT8        padding1;
  99   HBINT8        padding2;
 100   public:
 101   DEFINE_SIZE_STATIC(12);
 102 };
 103 
 104 
 105 /*
 106  * Index Subtables.
 107  */
 108 
 109 struct IndexSubtableHeader
 110 {
 111   bool sanitize (hb_sanitize_context_t *c) const
 112   {
 113     TRACE_SANITIZE (this);
 114     return_trace (c->check_struct (this));
 115   }
 116 
 117   HBUINT16      indexFormat;
 118   HBUINT16      imageFormat;
 119   HBUINT32      imageDataOffset;
 120   public:
 121   DEFINE_SIZE_STATIC(8);
 122 };
 123 
 124 template <typename OffsetType>
 125 struct IndexSubtableFormat1Or3
 126 {
 127   bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
 128   {
 129     TRACE_SANITIZE (this);
 130     return_trace (c->check_struct (this) &&
 131                   offsetArrayZ.sanitize (c, glyph_count + 1));
 132   }
 133 
 134   bool get_image_data (unsigned int idx,
 135                        unsigned int *offset,
 136                        unsigned int *length) const
 137   {
 138     if (unlikely (offsetArrayZ[idx + 1] <= offsetArrayZ[idx]))
 139       return false;
 140 
 141     *offset = header.imageDataOffset + offsetArrayZ[idx];
 142     *length = offsetArrayZ[idx + 1] - offsetArrayZ[idx];
 143     return true;
 144   }
 145 
 146   IndexSubtableHeader   header;
 147   UnsizedArrayOf<Offset<OffsetType> >
 148                         offsetArrayZ;
 149   public:
 150   DEFINE_SIZE_ARRAY(8, offsetArrayZ);
 151 };
 152 
 153 struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<HBUINT32> {};
 154 struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<HBUINT16> {};
 155 
 156 struct IndexSubtable
 157 {
 158   bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
 159   {
 160     TRACE_SANITIZE (this);
 161     if (!u.header.sanitize (c)) return_trace (false);
 162     switch (u.header.indexFormat) {
 163     case 1: return_trace (u.format1.sanitize (c, glyph_count));
 164     case 3: return_trace (u.format3.sanitize (c, glyph_count));
 165     default:return_trace (true);
 166     }
 167   }
 168 
 169   bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const
 170   {
 171     switch (u.header.indexFormat) {
 172     case 2: case 5: /* TODO */
 173     case 1: case 3: case 4: /* Variable-metrics formats do not have metrics here. */
 174     default:return (false);
 175     }
 176   }
 177 
 178   bool get_image_data (unsigned int idx,
 179                        unsigned int *offset,
 180                        unsigned int *length,
 181                        unsigned int *format) const
 182   {
 183     *format = u.header.imageFormat;
 184     switch (u.header.indexFormat) {
 185     case 1: return u.format1.get_image_data (idx, offset, length);
 186     case 3: return u.format3.get_image_data (idx, offset, length);
 187     default: return false;
 188     }
 189   }
 190 
 191   protected:
 192   union {
 193   IndexSubtableHeader   header;
 194   IndexSubtableFormat1  format1;
 195   IndexSubtableFormat3  format3;
 196   /* TODO: Format 2, 4, 5. */
 197   } u;
 198   public:
 199   DEFINE_SIZE_UNION (8, header);
 200 };
 201 
 202 struct IndexSubtableRecord
 203 {
 204   bool sanitize (hb_sanitize_context_t *c, const void *base) const
 205   {
 206     TRACE_SANITIZE (this);
 207     return_trace (c->check_struct (this) &&
 208                   firstGlyphIndex <= lastGlyphIndex &&
 209                   offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1));
 210   }
 211 
 212   bool get_extents (hb_glyph_extents_t *extents,
 213                     const void *base) const
 214   {
 215     return (base+offsetToSubtable).get_extents (extents);
 216   }
 217 
 218   bool get_image_data (unsigned int  gid,
 219                        const void   *base,
 220                        unsigned int *offset,
 221                        unsigned int *length,
 222                        unsigned int *format) const
 223   {
 224     if (gid < firstGlyphIndex || gid > lastGlyphIndex) return false;
 225     return (base+offsetToSubtable).get_image_data (gid - firstGlyphIndex,
 226                                                    offset, length, format);
 227   }
 228 
 229   GlyphID                       firstGlyphIndex;
 230   GlyphID                       lastGlyphIndex;
 231   LOffsetTo<IndexSubtable>      offsetToSubtable;
 232   public:
 233   DEFINE_SIZE_STATIC(8);
 234 };
 235 
 236 struct IndexSubtableArray
 237 {
 238   friend struct CBDT;
 239 
 240   bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
 241   {
 242     TRACE_SANITIZE (this);
 243     return_trace (indexSubtablesZ.sanitize (c, count, this));
 244   }
 245 
 246   public:
 247   const IndexSubtableRecord* find_table (hb_codepoint_t glyph, unsigned int numTables) const
 248   {
 249     for (unsigned int i = 0; i < numTables; ++i)
 250     {
 251       unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex;
 252       unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex;
 253       if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex)
 254         return &indexSubtablesZ[i];
 255     }
 256     return nullptr;
 257   }
 258 
 259   protected:
 260   UnsizedArrayOf<IndexSubtableRecord>   indexSubtablesZ;
 261 };
 262 
 263 struct BitmapSizeTable
 264 {
 265   friend struct CBLC;
 266   friend struct CBDT;
 267 
 268   bool sanitize (hb_sanitize_context_t *c, const void *base) const
 269   {
 270     TRACE_SANITIZE (this);
 271     return_trace (c->check_struct (this) &&
 272                   indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) &&
 273                   horizontal.sanitize (c) &&
 274                   vertical.sanitize (c));
 275   }
 276 
 277   const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
 278                                          const void *base,
 279                                          const void **out_base) const
 280   {
 281     *out_base = &(base+indexSubtableArrayOffset);
 282     return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables);
 283   }
 284 
 285   protected:
 286   LNNOffsetTo<IndexSubtableArray>
 287                         indexSubtableArrayOffset;
 288   HBUINT32              indexTablesSize;
 289   HBUINT32              numberOfIndexSubtables;
 290   HBUINT32              colorRef;
 291   SBitLineMetrics       horizontal;
 292   SBitLineMetrics       vertical;
 293   GlyphID               startGlyphIndex;
 294   GlyphID               endGlyphIndex;
 295   HBUINT8               ppemX;
 296   HBUINT8               ppemY;
 297   HBUINT8               bitDepth;
 298   HBINT8                flags;
 299   public:
 300   DEFINE_SIZE_STATIC(48);
 301 };
 302 
 303 
 304 /*
 305  * Glyph Bitmap Data Formats.
 306  */
 307 
 308 struct GlyphBitmapDataFormat17
 309 {
 310   SmallGlyphMetrics     glyphMetrics;
 311   LArrayOf<HBUINT8>     data;
 312   public:
 313   DEFINE_SIZE_ARRAY(9, data);
 314 };
 315 
 316 struct GlyphBitmapDataFormat18
 317 {
 318   BigGlyphMetrics       glyphMetrics;
 319   LArrayOf<HBUINT8>     data;
 320   public:
 321   DEFINE_SIZE_ARRAY(12, data);
 322 };
 323 
 324 struct GlyphBitmapDataFormat19
 325 {
 326   LArrayOf<HBUINT8>     data;
 327   public:
 328   DEFINE_SIZE_ARRAY(4, data);
 329 };
 330 
 331 struct CBLC
 332 {
 333   friend struct CBDT;
 334 
 335   static constexpr hb_tag_t tableTag = HB_OT_TAG_CBLC;
 336 
 337   bool sanitize (hb_sanitize_context_t *c) const
 338   {
 339     TRACE_SANITIZE (this);
 340     return_trace (c->check_struct (this) &&
 341                   likely (version.major == 2 || version.major == 3) &&
 342                   sizeTables.sanitize (c, this));
 343   }
 344 
 345   protected:
 346   const BitmapSizeTable &choose_strike (hb_font_t *font) const
 347   {
 348     unsigned count = sizeTables.len;
 349     if (unlikely (!count))
 350       return Null(BitmapSizeTable);
 351 
 352     unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem);
 353     if (!requested_ppem)
 354       requested_ppem = 1<<30; /* Choose largest strike. */
 355     unsigned int best_i = 0;
 356     unsigned int best_ppem = MAX (sizeTables[0].ppemX, sizeTables[0].ppemY);
 357 
 358     for (unsigned int i = 1; i < count; i++)
 359     {
 360       unsigned int ppem = MAX (sizeTables[i].ppemX, sizeTables[i].ppemY);
 361       if ((requested_ppem <= ppem && ppem < best_ppem) ||
 362           (requested_ppem > best_ppem && ppem > best_ppem))
 363       {
 364         best_i = i;
 365         best_ppem = ppem;
 366       }
 367     }
 368 
 369     return sizeTables[best_i];
 370   }
 371 
 372   protected:
 373   FixedVersion<>                version;
 374   LArrayOf<BitmapSizeTable>     sizeTables;
 375   public:
 376   DEFINE_SIZE_ARRAY(8, sizeTables);
 377 };
 378 
 379 struct CBDT
 380 {
 381   static constexpr hb_tag_t tableTag = HB_OT_TAG_CBDT;
 382 
 383   struct accelerator_t
 384   {
 385     void init (hb_face_t *face)
 386     {
 387       cblc = hb_sanitize_context_t().reference_table<CBLC> (face);
 388       cbdt = hb_sanitize_context_t().reference_table<CBDT> (face);
 389 
 390       upem = hb_face_get_upem (face);
 391     }
 392 
 393     void fini ()
 394     {
 395       this->cblc.destroy ();
 396       this->cbdt.destroy ();
 397     }
 398 
 399     bool get_extents (hb_font_t *font, hb_codepoint_t glyph,
 400                       hb_glyph_extents_t *extents) const
 401     {
 402       const void *base;
 403       const BitmapSizeTable &strike = this->cblc->choose_strike (font);
 404       const IndexSubtableRecord *subtable_record = strike.find_table (glyph, cblc, &base);
 405       if (!subtable_record || !strike.ppemX || !strike.ppemY)
 406         return false;
 407 
 408       if (subtable_record->get_extents (extents, base))
 409         return true;
 410 
 411       unsigned int image_offset = 0, image_length = 0, image_format = 0;
 412       if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format))
 413         return false;
 414 
 415       {
 416         unsigned int cbdt_len = cbdt.get_length ();
 417         if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
 418           return false;
 419 
 420         switch (image_format)
 421         {
 422           case 17: {
 423             if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
 424               return false;
 425             const GlyphBitmapDataFormat17& glyphFormat17 =
 426                 StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
 427             glyphFormat17.glyphMetrics.get_extents (extents);
 428             break;
 429           }
 430           case 18: {
 431             if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
 432               return false;
 433             const GlyphBitmapDataFormat18& glyphFormat18 =
 434                 StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
 435             glyphFormat18.glyphMetrics.get_extents (extents);
 436             break;
 437           }
 438           default:
 439             // TODO: Support other image formats.
 440             return false;
 441         }
 442       }
 443 
 444       /* Convert to font units. */
 445       double x_scale = upem / (double) strike.ppemX;
 446       double y_scale = upem / (double) strike.ppemY;
 447       extents->x_bearing = round (extents->x_bearing * x_scale);
 448       extents->y_bearing = round (extents->y_bearing * y_scale);
 449       extents->width = round (extents->width * x_scale);
 450       extents->height = round (extents->height * y_scale);
 451 
 452       return true;
 453     }
 454 
 455     hb_blob_t* reference_png (hb_font_t      *font,
 456                                      hb_codepoint_t  glyph) const
 457     {
 458       const void *base;
 459       const BitmapSizeTable &strike = this->cblc->choose_strike (font);
 460       const IndexSubtableRecord *subtable_record = strike.find_table (glyph, cblc, &base);
 461       if (!subtable_record || !strike.ppemX || !strike.ppemY)
 462         return hb_blob_get_empty ();
 463 
 464       unsigned int image_offset = 0, image_length = 0, image_format = 0;
 465       if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format))
 466         return hb_blob_get_empty ();
 467 
 468       {
 469         unsigned int cbdt_len = cbdt.get_length ();
 470         if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
 471           return hb_blob_get_empty ();
 472 
 473         switch (image_format)
 474         {
 475           case 17: {
 476             if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
 477               return hb_blob_get_empty ();
 478             const GlyphBitmapDataFormat17& glyphFormat17 =
 479               StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
 480             return hb_blob_create_sub_blob (cbdt.get_blob (),
 481                                             image_offset + GlyphBitmapDataFormat17::min_size,
 482                                             glyphFormat17.data.len);
 483           }
 484           case 18: {
 485             if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
 486               return hb_blob_get_empty ();
 487             const GlyphBitmapDataFormat18& glyphFormat18 =
 488               StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
 489             return hb_blob_create_sub_blob (cbdt.get_blob (),
 490                                             image_offset + GlyphBitmapDataFormat18::min_size,
 491                                             glyphFormat18.data.len);
 492           }
 493           case 19: {
 494             if (unlikely (image_length < GlyphBitmapDataFormat19::min_size))
 495               return hb_blob_get_empty ();
 496             const GlyphBitmapDataFormat19& glyphFormat19 =
 497               StructAtOffset<GlyphBitmapDataFormat19> (this->cbdt, image_offset);
 498             return hb_blob_create_sub_blob (cbdt.get_blob (),
 499                                             image_offset + GlyphBitmapDataFormat19::min_size,
 500                                             glyphFormat19.data.len);
 501           }
 502         }
 503       }
 504 
 505       return hb_blob_get_empty ();
 506     }
 507 
 508     bool has_data () const { return cbdt.get_length (); }
 509 
 510     private:
 511     hb_blob_ptr_t<CBLC> cblc;
 512     hb_blob_ptr_t<CBDT> cbdt;
 513 
 514     unsigned int upem;
 515   };
 516 
 517   bool sanitize (hb_sanitize_context_t *c) const
 518   {
 519     TRACE_SANITIZE (this);
 520     return_trace (c->check_struct (this) &&
 521                   likely (version.major == 2 || version.major == 3));
 522   }
 523 
 524   protected:
 525   FixedVersion<>                version;
 526   UnsizedArrayOf<HBUINT8>       dataZ;
 527   public:
 528   DEFINE_SIZE_ARRAY(4, dataZ);
 529 };
 530 
 531 struct CBDT_accelerator_t : CBDT::accelerator_t {};
 532 
 533 } /* namespace OT */
 534 
 535 #endif /* HB_OT_COLOR_CBDT_TABLE_HH */