1 /* 2 * Copyright © 2015 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_GLYF_TABLE_HH 28 #define HB_OT_GLYF_TABLE_HH 29 30 #include "hb-open-type-private.hh" 31 #include "hb-ot-head-table.hh" 32 #include "hb-subset-glyf.hh" 33 #include "hb-subset-plan.hh" 34 #include "hb-subset-private.hh" 35 36 namespace OT { 37 38 39 /* 40 * loca -- Index to Location 41 * https://docs.microsoft.com/en-us/typography/opentype/spec/loca 42 */ 43 #define HB_OT_TAG_loca HB_TAG('l','o','c','a') 44 45 46 struct loca 47 { 48 friend struct glyf; 49 50 static const hb_tag_t tableTag = HB_OT_TAG_loca; 51 52 inline bool sanitize (hb_sanitize_context_t *c) const 53 { 54 TRACE_SANITIZE (this); 55 return_trace (true); 56 } 57 58 protected: 59 HBUINT8 dataZ[VAR]; /* Location data. */ 60 DEFINE_SIZE_ARRAY (0, dataZ); 61 }; 62 63 64 /* 65 * glyf -- TrueType Glyph Data 66 * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf 67 */ 68 #define HB_OT_TAG_glyf HB_TAG('g','l','y','f') 69 70 71 struct glyf 72 { 73 static const hb_tag_t tableTag = HB_OT_TAG_glyf; 74 75 inline bool sanitize (hb_sanitize_context_t *c) const 76 { 77 TRACE_SANITIZE (this); 78 /* We don't check for anything specific here. The users of the 79 * struct do all the hard work... */ 80 return_trace (true); 81 } 82 83 inline bool subset (hb_subset_plan_t *plan) const 84 { 85 hb_blob_t *glyf_prime = nullptr; 86 hb_blob_t *loca_prime = nullptr; 87 88 bool success = true; 89 bool use_short_loca = false; 90 if (hb_subset_glyf_and_loca (plan, &use_short_loca, &glyf_prime, &loca_prime)) { 91 success = success && plan->add_table (HB_OT_TAG_glyf, glyf_prime); 92 success = success && plan->add_table (HB_OT_TAG_loca, loca_prime); 93 success = success && _add_head_and_set_loca_version (plan, use_short_loca); 94 } else { 95 success = false; 96 } 97 hb_blob_destroy (loca_prime); 98 hb_blob_destroy (glyf_prime); 99 100 return success; 101 } 102 103 static bool 104 _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) 105 { 106 hb_blob_t *head_blob = OT::Sanitizer<OT::head>().sanitize (hb_face_reference_table (plan->source, HB_OT_TAG_head)); 107 hb_blob_t *head_prime_blob = hb_blob_copy_writable_or_fail (head_blob); 108 hb_blob_destroy (head_blob); 109 110 if (unlikely (!head_prime_blob)) 111 return false; 112 113 OT::head *head_prime = (OT::head *) hb_blob_get_data_writable (head_prime_blob, nullptr); 114 head_prime->indexToLocFormat.set (use_short_loca ? 0 : 1); 115 bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob); 116 117 hb_blob_destroy (head_prime_blob); 118 return success; 119 } 120 121 struct GlyphHeader 122 { 123 HBINT16 numberOfContours; /* If the number of contours is 124 * greater than or equal to zero, 125 * this is a simple glyph; if negative, 126 * this is a composite glyph. */ 127 FWORD xMin; /* Minimum x for coordinate data. */ 128 FWORD yMin; /* Minimum y for coordinate data. */ 129 FWORD xMax; /* Maximum x for coordinate data. */ 130 FWORD yMax; /* Maximum y for coordinate data. */ 131 132 DEFINE_SIZE_STATIC (10); 133 }; 134 135 struct CompositeGlyphHeader 136 { 137 enum composite_glyph_flag_t { 138 ARG_1_AND_2_ARE_WORDS = 0x0001, 139 ARGS_ARE_XY_VALUES = 0x0002, 140 ROUND_XY_TO_GRID = 0x0004, 141 WE_HAVE_A_SCALE = 0x0008, 142 MORE_COMPONENTS = 0x0020, 143 WE_HAVE_AN_X_AND_Y_SCALE = 0x0040, 144 WE_HAVE_A_TWO_BY_TWO = 0x0080, 145 WE_HAVE_INSTRUCTIONS = 0x0100, 146 USE_MY_METRICS = 0x0200, 147 OVERLAP_COMPOUND = 0x0400, 148 SCALED_COMPONENT_OFFSET = 0x0800, 149 UNSCALED_COMPONENT_OFFSET = 0x1000 150 }; 151 152 HBUINT16 flags; 153 HBUINT16 glyphIndex; 154 155 inline unsigned int get_size (void) const 156 { 157 unsigned int size = min_size; 158 if (flags & ARG_1_AND_2_ARE_WORDS) { 159 // arg1 and 2 are int16 160 size += 4; 161 } else { 162 // arg1 and 2 are int8 163 size += 2; 164 } 165 if (flags & WE_HAVE_A_SCALE) { 166 // One x 16 bit (scale) 167 size += 2; 168 } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { 169 // Two x 16 bit (xscale, yscale) 170 size += 4; 171 } else if (flags & WE_HAVE_A_TWO_BY_TWO) { 172 // Four x 16 bit (xscale, scale01, scale10, yscale) 173 size += 8; 174 } 175 return size; 176 } 177 178 struct Iterator 179 { 180 const char *glyph_start; 181 const char *glyph_end; 182 const CompositeGlyphHeader *current; 183 184 inline bool move_to_next () 185 { 186 if (current->flags & CompositeGlyphHeader::MORE_COMPONENTS) 187 { 188 const CompositeGlyphHeader *possible = 189 &StructAfter<CompositeGlyphHeader, CompositeGlyphHeader> (*current); 190 if (!in_range (possible)) 191 return false; 192 current = possible; 193 return true; 194 } 195 return false; 196 } 197 198 inline bool in_range (const CompositeGlyphHeader *composite) const 199 { 200 return (const char *) composite >= glyph_start 201 && ((const char *) composite + CompositeGlyphHeader::min_size) <= glyph_end 202 && ((const char *) composite + composite->get_size()) <= glyph_end; 203 } 204 }; 205 206 static inline bool get_iterator (const char * glyph_data, 207 unsigned int length, 208 CompositeGlyphHeader::Iterator *iterator /* OUT */) 209 { 210 if (length < GlyphHeader::static_size) 211 return false; /* Empty glyph; zero extents. */ 212 213 const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph_data, 0); 214 if (glyph_header.numberOfContours < 0) 215 { 216 const CompositeGlyphHeader *possible = 217 &StructAfter<CompositeGlyphHeader, GlyphHeader> (glyph_header); 218 219 iterator->glyph_start = glyph_data; 220 iterator->glyph_end = (const char *) glyph_data + length; 221 if (!iterator->in_range (possible)) 222 return false; 223 iterator->current = possible; 224 return true; 225 } 226 227 return false; 228 } 229 230 DEFINE_SIZE_MIN (4); 231 }; 232 233 struct accelerator_t 234 { 235 inline void init (hb_face_t *face) 236 { 237 memset (this, 0, sizeof (accelerator_t)); 238 239 hb_blob_t *head_blob = Sanitizer<head>().sanitize (face->reference_table (HB_OT_TAG_head)); 240 const head *head_table = head_blob->as<head> (); 241 if (head_table == &Null(head) || (unsigned int) head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0) 242 { 243 /* head table is not present, or in an unknown format. Leave num_glyphs=0, that takes care of disabling us. */ 244 hb_blob_destroy (head_blob); 245 return; 246 } 247 short_offset = 0 == head_table->indexToLocFormat; 248 hb_blob_destroy (head_blob); 249 250 loca_blob = Sanitizer<loca>().sanitize (face->reference_table (HB_OT_TAG_loca)); 251 loca_table = loca_blob->as<loca> (); 252 glyf_blob = Sanitizer<glyf>().sanitize (face->reference_table (HB_OT_TAG_glyf)); 253 glyf_table = glyf_blob->as<glyf> (); 254 255 num_glyphs = MAX (1u, hb_blob_get_length (loca_blob) / (short_offset ? 2 : 4)) - 1; 256 glyf_len = hb_blob_get_length (glyf_blob); 257 } 258 259 inline void fini (void) 260 { 261 hb_blob_destroy (loca_blob); 262 hb_blob_destroy (glyf_blob); 263 } 264 265 /* 266 * Returns true if the referenced glyph is a valid glyph and a composite glyph. 267 * If true is returned a pointer to the composite glyph will be written into 268 * composite. 269 */ 270 inline bool get_composite (hb_codepoint_t glyph, 271 CompositeGlyphHeader::Iterator *composite /* OUT */) const 272 { 273 if (this->glyf_table == &Null(glyf) || !num_glyphs) 274 return false; 275 276 unsigned int start_offset, end_offset; 277 if (!get_offsets (glyph, &start_offset, &end_offset)) 278 return false; /* glyph not found */ 279 280 return CompositeGlyphHeader::get_iterator ((const char*) this->glyf_table + start_offset, 281 end_offset - start_offset, 282 composite); 283 } 284 285 enum simple_glyph_flag_t { 286 FLAG_X_SHORT = 0x02, 287 FLAG_Y_SHORT = 0x04, 288 FLAG_REPEAT = 0x08, 289 FLAG_X_SAME = 0x10, 290 FLAG_Y_SAME = 0x20 291 }; 292 293 /* based on FontTools _g_l_y_f.py::trim */ 294 inline bool remove_padding(unsigned int start_offset, 295 unsigned int *end_offset) const 296 { 297 if (*end_offset - start_offset < GlyphHeader::static_size) 298 return true; 299 300 const char *glyph = ((const char *) glyf_table) + start_offset; 301 const char * const glyph_end = glyph + (*end_offset - start_offset); 302 const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph, 0); 303 int16_t num_contours = (int16_t) glyph_header.numberOfContours; 304 305 if (num_contours < 0) 306 /* Trimming for composites not implemented. 307 * If removing hints it falls out of that. */ 308 return true; 309 else if (num_contours > 0) 310 { 311 /* simple glyph w/contours, possibly trimmable */ 312 glyph += GlyphHeader::static_size + 2 * num_contours; 313 314 if (unlikely (glyph + 2 >= glyph_end)) return false; 315 uint16_t nCoordinates = (uint16_t) StructAtOffset<HBUINT16>(glyph - 2, 0) + 1; 316 uint16_t nInstructions = (uint16_t) StructAtOffset<HBUINT16>(glyph, 0); 317 318 glyph += 2 + nInstructions; 319 if (unlikely (glyph + 2 >= glyph_end)) return false; 320 321 unsigned int coordBytes = 0; 322 unsigned int coordsWithFlags = 0; 323 while (glyph < glyph_end) 324 { 325 uint8_t flag = (uint8_t) *glyph; 326 glyph++; 327 328 unsigned int repeat = 1; 329 if (flag & FLAG_REPEAT) 330 { 331 if (glyph >= glyph_end) 332 { 333 DEBUG_MSG(SUBSET, nullptr, "Bad flag"); 334 return false; 335 } 336 repeat = ((uint8_t) *glyph) + 1; 337 glyph++; 338 } 339 340 unsigned int xBytes, yBytes; 341 xBytes = yBytes = 0; 342 if (flag & FLAG_X_SHORT) 343 xBytes = 1; 344 else if ((flag & FLAG_X_SAME) == 0) 345 xBytes = 2; 346 347 if (flag & FLAG_Y_SHORT) 348 yBytes = 1; 349 else if ((flag & FLAG_Y_SAME) == 0) 350 yBytes = 2; 351 352 coordBytes += (xBytes + yBytes) * repeat; 353 coordsWithFlags += repeat; 354 if (coordsWithFlags >= nCoordinates) 355 break; 356 } 357 358 if (coordsWithFlags != nCoordinates) 359 { 360 DEBUG_MSG(SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d", nCoordinates, coordsWithFlags); 361 return false; 362 } 363 glyph += coordBytes; 364 365 if (glyph < glyph_end) 366 *end_offset -= glyph_end - glyph; 367 } 368 return true; 369 } 370 371 inline bool get_offsets (hb_codepoint_t glyph, 372 unsigned int *start_offset /* OUT */, 373 unsigned int *end_offset /* OUT */) const 374 { 375 if (unlikely (glyph >= num_glyphs)) 376 return false; 377 378 if (short_offset) 379 { 380 const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ; 381 *start_offset = 2 * offsets[glyph]; 382 *end_offset = 2 * offsets[glyph + 1]; 383 } 384 else 385 { 386 const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ; 387 388 *start_offset = offsets[glyph]; 389 *end_offset = offsets[glyph + 1]; 390 } 391 392 if (*start_offset > *end_offset || *end_offset > glyf_len) 393 return false; 394 395 return true; 396 } 397 398 inline bool get_instruction_offsets(unsigned int start_offset, 399 unsigned int end_offset, 400 unsigned int *instruction_start /* OUT */, 401 unsigned int *instruction_end /* OUT */) const 402 { 403 if (end_offset - start_offset < GlyphHeader::static_size) 404 { 405 *instruction_start = 0; 406 *instruction_end = 0; 407 return true; /* Empty glyph; no instructions. */ 408 } 409 const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset); 410 int16_t num_contours = (int16_t) glyph_header.numberOfContours; 411 if (num_contours < 0) 412 { 413 CompositeGlyphHeader::Iterator composite_it; 414 if (unlikely (!CompositeGlyphHeader::get_iterator ( 415 (const char*) this->glyf_table + start_offset, 416 end_offset - start_offset, &composite_it))) return false; 417 const CompositeGlyphHeader *last; 418 do { 419 last = composite_it.current; 420 } while (composite_it.move_to_next()); 421 422 if ( (uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS) 423 *instruction_start = ((char *) last - (char *) glyf_table->dataZ) + last->get_size(); 424 else 425 *instruction_start = end_offset; 426 *instruction_end = end_offset; 427 if (unlikely (*instruction_start > *instruction_end)) 428 { 429 DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside [%d, %d]", *instruction_start, start_offset, end_offset); 430 return false; 431 } 432 } 433 else 434 { 435 unsigned int instruction_length_offset = start_offset + GlyphHeader::static_size + 2 * num_contours; 436 if (unlikely (instruction_length_offset + 2 > end_offset)) 437 { 438 DEBUG_MSG(SUBSET, nullptr, "Glyph size is too short, missing field instructionLength."); 439 return false; 440 } 441 442 const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (glyf_table, instruction_length_offset); 443 unsigned int start = instruction_length_offset + 2; 444 unsigned int end = start + (uint16_t) instruction_length; 445 if (unlikely (end > end_offset)) // Out of bounds of the current glyph 446 { 447 DEBUG_MSG(SUBSET, nullptr, "The instructions array overruns the glyph's boundaries."); 448 return false; 449 } 450 451 *instruction_start = start; 452 *instruction_end = end; 453 } 454 return true; 455 } 456 457 inline bool get_extents (hb_codepoint_t glyph, 458 hb_glyph_extents_t *extents) const 459 { 460 unsigned int start_offset, end_offset; 461 if (!get_offsets (glyph, &start_offset, &end_offset)) 462 return false; 463 464 if (end_offset - start_offset < GlyphHeader::static_size) 465 return true; /* Empty glyph; zero extents. */ 466 467 const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset); 468 469 extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax); 470 extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax); 471 extents->width = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing; 472 extents->height = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing; 473 474 return true; 475 } 476 477 private: 478 bool short_offset; 479 unsigned int num_glyphs; 480 const loca *loca_table; 481 const glyf *glyf_table; 482 hb_blob_t *loca_blob; 483 hb_blob_t *glyf_blob; 484 unsigned int glyf_len; 485 }; 486 487 protected: 488 HBUINT8 dataZ[VAR]; /* Glyphs data. */ 489 490 DEFINE_SIZE_ARRAY (0, dataZ); 491 }; 492 493 } /* namespace OT */ 494 495 496 #endif /* HB_OT_GLYF_TABLE_HH */