Home | History | Annotate | Download | only in src
      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 = -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   LOffsetTo<IndexSubtableArray, false>
    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   enum { 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   enum { 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 */
    536