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