glyf.hh (17527B)
1 #ifndef OT_GLYF_GLYF_HH 2 #define OT_GLYF_GLYF_HH 3 4 5 #include "../../hb-open-type.hh" 6 #include "../../hb-ot-head-table.hh" 7 #include "../../hb-ot-hmtx-table.hh" 8 #include "../../hb-ot-var-gvar-table.hh" 9 #include "../../hb-draw.hh" 10 #include "../../hb-paint.hh" 11 12 #include "glyf-helpers.hh" 13 #include "Glyph.hh" 14 #include "SubsetGlyph.hh" 15 #include "loca.hh" 16 #include "path-builder.hh" 17 18 19 namespace OT { 20 21 22 /* 23 * glyf -- TrueType Glyph Data 24 * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf 25 */ 26 #define HB_OT_TAG_glyf HB_TAG('g','l','y','f') 27 28 struct glyf 29 { 30 friend struct glyf_accelerator_t; 31 32 static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf; 33 34 static bool has_valid_glyf_format(const hb_face_t* face) 35 { 36 const OT::head &head = *face->table.head; 37 return head.indexToLocFormat <= 1 && head.glyphDataFormat <= 1; 38 } 39 40 bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const 41 { 42 TRACE_SANITIZE (this); 43 /* Runtime checks as eager sanitizing each glyph is costy */ 44 return_trace (true); 45 } 46 47 /* requires source of SubsetGlyph complains the identifier isn't declared */ 48 template <typename Iterator> 49 bool serialize (hb_serialize_context_t *c, 50 Iterator it, 51 bool use_short_loca, 52 const hb_subset_plan_t *plan) 53 { 54 TRACE_SERIALIZE (this); 55 56 unsigned init_len = c->length (); 57 for (auto &_ : it) 58 if (unlikely (!_.serialize (c, use_short_loca, plan))) 59 return false; 60 61 /* As a special case when all glyph in the font are empty, add a zero byte 62 * to the table, so that OTS doesn’t reject it, and to make the table work 63 * on Windows as well. 64 * See https://github.com/khaledhosny/ots/issues/52 */ 65 if (init_len == c->length ()) 66 { 67 HBUINT8 empty_byte; 68 empty_byte = 0; 69 c->copy (empty_byte); 70 } 71 return_trace (true); 72 } 73 74 /* Byte region(s) per glyph to output 75 unpadded, hints removed if so requested 76 If we fail to process a glyph we produce an empty (0-length) glyph */ 77 bool subset (hb_subset_context_t *c) const 78 { 79 TRACE_SUBSET (this); 80 81 if (!has_valid_glyf_format (c->plan->source)) { 82 // glyf format is unknown don't attempt to subset it. 83 DEBUG_MSG (SUBSET, nullptr, 84 "unkown glyf format, dropping from subset."); 85 return_trace (false); 86 } 87 88 hb_font_t *font = nullptr; 89 if (c->plan->normalized_coords) 90 { 91 font = _create_font_for_instancing (c->plan); 92 if (unlikely (!font)) 93 return_trace (false); 94 } 95 96 hb_vector_t<unsigned> padded_offsets; 97 if (unlikely (!padded_offsets.alloc_exact (c->plan->new_to_old_gid_list.length))) 98 return_trace (false); 99 100 hb_vector_t<glyf_impl::SubsetGlyph> glyphs; 101 if (!_populate_subset_glyphs (c->plan, font, glyphs)) 102 { 103 hb_font_destroy (font); 104 return_trace (false); 105 } 106 107 if (font) 108 hb_font_destroy (font); 109 110 unsigned max_offset = 0; 111 for (auto &g : glyphs) 112 { 113 unsigned size = g.padded_size (); 114 padded_offsets.push (size); 115 max_offset += size; 116 } 117 118 bool use_short_loca = false; 119 if (likely (!c->plan->force_long_loca)) 120 use_short_loca = max_offset < 0x1FFFF; 121 122 if (!use_short_loca) 123 { 124 padded_offsets.resize (0); 125 for (auto &g : glyphs) 126 padded_offsets.push (g.length ()); 127 } 128 129 auto *glyf_prime = c->serializer->start_embed <glyf> (); 130 bool result = glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan); 131 if (c->plan->normalized_coords && !c->plan->pinned_at_default) 132 _free_compiled_subset_glyphs (glyphs); 133 134 if (unlikely (!c->serializer->check_success (glyf_impl::_add_loca_and_head (c, 135 padded_offsets.iter (), 136 use_short_loca)))) 137 return_trace (false); 138 139 return result; 140 } 141 142 bool 143 _populate_subset_glyphs (const hb_subset_plan_t *plan, 144 hb_font_t *font, 145 hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const; 146 147 hb_font_t * 148 _create_font_for_instancing (const hb_subset_plan_t *plan) const; 149 150 void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> &glyphs) const 151 { 152 for (auto &g : glyphs) 153 g.free_compiled_bytes (); 154 } 155 156 protected: 157 UnsizedArrayOf<HBUINT8> 158 dataZ; /* Glyphs data. */ 159 public: 160 DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always 161 * check the size externally, allow Null() object of it by 162 * defining it _MIN instead. */ 163 }; 164 165 struct glyf_accelerator_t 166 { 167 glyf_accelerator_t (hb_face_t *face) 168 { 169 short_offset = false; 170 num_glyphs = 0; 171 loca_table = nullptr; 172 glyf_table = nullptr; 173 #ifndef HB_NO_VAR 174 gvar = nullptr; 175 #ifndef HB_NO_BEYOND_64K 176 GVAR = nullptr; 177 #endif 178 #endif 179 hmtx = nullptr; 180 #ifndef HB_NO_VERTICAL 181 vmtx = nullptr; 182 #endif 183 const OT::head &head = *face->table.head; 184 if (!glyf::has_valid_glyf_format (face)) 185 /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ 186 return; 187 short_offset = 0 == head.indexToLocFormat; 188 189 loca_table = face->table.loca.get_blob (); // Needs no destruct! 190 glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face); 191 #ifndef HB_NO_VAR 192 gvar = face->table.gvar; 193 #ifndef HB_NO_BEYOND_64K 194 GVAR = face->table.GVAR; 195 #endif 196 #endif 197 hmtx = face->table.hmtx; 198 #ifndef HB_NO_VERTICAL 199 vmtx = face->table.vmtx; 200 #endif 201 202 num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; 203 num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ()); 204 } 205 ~glyf_accelerator_t () 206 { 207 auto *scratch = cached_scratch.get_relaxed (); 208 if (scratch) 209 { 210 scratch->~hb_glyf_scratch_t (); 211 hb_free (scratch); 212 } 213 214 glyf_table.destroy (); 215 } 216 217 bool has_data () const { return num_glyphs; } 218 219 protected: 220 template<typename T> 221 bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer, 222 hb_array_t<const int> coords, 223 hb_glyf_scratch_t &scratch, 224 hb_scalar_cache_t *gvar_cache = nullptr) const 225 { 226 if (gid >= num_glyphs) return false; 227 228 auto &all_points = scratch.all_points; 229 all_points.resize (0); 230 231 bool phantom_only = !consumer.is_consuming_contour_points (); 232 if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords, gvar_cache))) 233 return false; 234 235 unsigned count = all_points.length; 236 assert (count >= glyf_impl::PHANTOM_COUNT); 237 count -= glyf_impl::PHANTOM_COUNT; 238 239 if (consumer.is_consuming_contour_points ()) 240 { 241 auto *points = all_points.arrayZ; 242 243 if (false) 244 { 245 /* Our path-builder was designed to work with this simple loop. 246 * But FreeType and CoreText do it differently, so we match those 247 * with the other, more complicated, code branch below. */ 248 for (unsigned i = 0; i < count; i++) 249 { 250 consumer.consume_point (points[i]); 251 if (points[i].is_end_point) 252 consumer.contour_end (); 253 } 254 } 255 else 256 { 257 for (unsigned i = 0; i < count; i++) 258 { 259 // Start of a contour. 260 if (points[i].flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE) 261 { 262 // First point is on-curve. Draw the contour. 263 for (; i < count; i++) 264 { 265 consumer.consume_point (points[i]); 266 if (points[i].is_end_point) 267 { 268 consumer.contour_end (); 269 break; 270 } 271 } 272 } 273 else 274 { 275 unsigned start = i; 276 277 // Find end of the contour. 278 for (; i < count; i++) 279 if (points[i].is_end_point) 280 break; 281 282 unsigned end = i; 283 284 // Enough to start from the end. Our path-builder takes care of the rest. 285 if (likely (end < count)) // Can only fail in case of alloc failure *maybe*. 286 consumer.consume_point (points[end]); 287 288 for (i = start; i < end; i++) 289 consumer.consume_point (points[i]); 290 291 consumer.contour_end (); 292 } 293 } 294 } 295 296 consumer.points_end (); 297 } 298 299 /* Where to write phantoms, nullptr if not requested */ 300 contour_point_t *phantoms = consumer.get_phantoms_sink (); 301 if (phantoms) 302 for (unsigned i = 0; i < glyf_impl::PHANTOM_COUNT; ++i) 303 phantoms[i] = all_points.arrayZ[count + i]; 304 305 return true; 306 } 307 308 public: 309 310 #ifndef HB_NO_VAR 311 struct points_aggregator_t 312 { 313 hb_font_t *font; 314 hb_glyph_extents_t *extents; 315 contour_point_t *phantoms; 316 bool scaled; 317 318 struct contour_bounds_t 319 { 320 contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; } 321 322 void add (const contour_point_t &p) 323 { 324 min_x = hb_min (min_x, p.x); 325 min_y = hb_min (min_y, p.y); 326 max_x = hb_max (max_x, p.x); 327 max_y = hb_max (max_y, p.y); 328 } 329 330 bool empty () const { return (min_x >= max_x) || (min_y >= max_y); } 331 332 void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scaled) 333 { 334 if (unlikely (empty ())) 335 { 336 extents->width = 0; 337 extents->x_bearing = 0; 338 extents->height = 0; 339 extents->y_bearing = 0; 340 return; 341 } 342 { 343 extents->x_bearing = roundf (min_x); 344 extents->width = roundf (max_x - extents->x_bearing); 345 extents->y_bearing = roundf (max_y); 346 extents->height = roundf (min_y - extents->y_bearing); 347 348 if (scaled) 349 font->scale_glyph_extents (extents); 350 } 351 } 352 353 protected: 354 float min_x, min_y, max_x, max_y; 355 } bounds; 356 357 points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_, bool scaled_) 358 { 359 font = font_; 360 extents = extents_; 361 phantoms = phantoms_; 362 scaled = scaled_; 363 if (extents) bounds = contour_bounds_t (); 364 } 365 366 HB_ALWAYS_INLINE 367 void consume_point (const contour_point_t &point) { bounds.add (point); } 368 void contour_end () {} 369 void points_end () { bounds.get_extents (font, extents, scaled); } 370 371 bool is_consuming_contour_points () { return extents; } 372 contour_point_t *get_phantoms_sink () { return phantoms; } 373 }; 374 375 #ifndef HB_NO_VAR 376 unsigned 377 get_advance_with_var_unscaled (hb_codepoint_t gid, 378 hb_font_t *font, 379 bool is_vertical, 380 hb_glyf_scratch_t &scratch, 381 hb_scalar_cache_t *gvar_cache = nullptr) const 382 { 383 if (unlikely (gid >= num_glyphs)) return 0; 384 385 bool success = false; 386 387 contour_point_t phantoms[glyf_impl::PHANTOM_COUNT]; 388 success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false), 389 hb_array (font->coords, 390 font->has_nonzero_coords ? font->num_coords : 0), 391 scratch, gvar_cache); 392 if (unlikely (!success)) 393 { 394 unsigned upem = font->face->get_upem (); 395 return is_vertical ? upem : upem / 2; 396 } 397 398 float result = is_vertical 399 ? phantoms[glyf_impl::PHANTOM_TOP].y - phantoms[glyf_impl::PHANTOM_BOTTOM].y 400 : phantoms[glyf_impl::PHANTOM_RIGHT].x - phantoms[glyf_impl::PHANTOM_LEFT].x; 401 return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2); 402 } 403 404 float 405 get_v_origin_with_var_unscaled (hb_codepoint_t gid, 406 hb_font_t *font, 407 hb_glyf_scratch_t &scratch, 408 hb_scalar_cache_t *gvar_cache = nullptr) const 409 { 410 if (unlikely (gid >= num_glyphs)) return 0; 411 412 bool success = false; 413 414 contour_point_t phantoms[glyf_impl::PHANTOM_COUNT]; 415 success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false), 416 hb_array (font->coords, 417 font->has_nonzero_coords ? font->num_coords : 0), 418 scratch, gvar_cache); 419 if (unlikely (!success)) 420 { 421 return font->face->get_upem (); 422 } 423 424 return phantoms[glyf_impl::PHANTOM_TOP].y; 425 } 426 #endif 427 #endif 428 429 public: 430 431 bool get_extents (hb_font_t *font, 432 hb_codepoint_t gid, 433 hb_glyph_extents_t *extents) const 434 { return get_extents_at (font, gid, extents, hb_array (font->coords, 435 font->has_nonzero_coords ? font->num_coords : 0)); } 436 437 bool get_extents_at (hb_font_t *font, 438 hb_codepoint_t gid, 439 hb_glyph_extents_t *extents, 440 hb_array_t<const int> coords) const 441 { 442 if (unlikely (gid >= num_glyphs)) return false; 443 444 #ifndef HB_NO_VAR 445 if (coords) 446 { 447 hb_glyf_scratch_t *scratch = acquire_scratch (); 448 if (unlikely (!scratch)) return false; 449 bool ret = get_points (font, 450 gid, 451 points_aggregator_t (font, extents, nullptr, true), 452 coords, 453 *scratch); 454 release_scratch (scratch); 455 return ret; 456 } 457 #endif 458 return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents); 459 } 460 461 const glyf_impl::Glyph 462 glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const 463 { 464 if (unlikely (gid >= num_glyphs)) return glyf_impl::Glyph (); 465 466 unsigned int start_offset, end_offset; 467 468 if (short_offset) 469 { 470 const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; 471 start_offset = 2 * offsets[gid]; 472 end_offset = 2 * offsets[gid + 1]; 473 } 474 else 475 { 476 const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; 477 start_offset = offsets[gid]; 478 end_offset = offsets[gid + 1]; 479 } 480 481 if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ())) 482 return glyf_impl::Glyph (); 483 484 glyf_impl::Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset, 485 end_offset - start_offset), gid); 486 return needs_padding_removal ? glyf_impl::Glyph (glyph.trim_padding (), gid) : glyph; 487 } 488 489 bool 490 get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session, hb_scalar_cache_t *gvar_cache = nullptr) const 491 { 492 if (!has_data ()) return false; 493 494 hb_glyf_scratch_t *scratch = acquire_scratch (); 495 if (unlikely (!scratch)) return true; 496 497 bool ret = get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), 498 hb_array (font->coords, 499 font->has_nonzero_coords ? font->num_coords : 0), 500 *scratch, 501 gvar_cache); 502 503 release_scratch (scratch); 504 505 return ret; 506 } 507 508 bool 509 get_path_at (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session, 510 hb_array_t<const int> coords, 511 hb_glyf_scratch_t &scratch, 512 hb_scalar_cache_t *gvar_cache = nullptr) const 513 { 514 if (!has_data ()) return false; 515 return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), 516 coords, 517 scratch, 518 gvar_cache); 519 } 520 521 522 hb_glyf_scratch_t *acquire_scratch () const 523 { 524 if (!has_data ()) return nullptr; 525 hb_glyf_scratch_t *scratch = cached_scratch.get_acquire (); 526 if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr))) 527 { 528 scratch = (hb_glyf_scratch_t *) hb_calloc (1, sizeof (hb_glyf_scratch_t)); 529 if (unlikely (!scratch)) 530 return nullptr; 531 } 532 return scratch; 533 } 534 void release_scratch (hb_glyf_scratch_t *scratch) const 535 { 536 if (!scratch) 537 return; 538 if (!cached_scratch.cmpexch (nullptr, scratch)) 539 { 540 scratch->~hb_glyf_scratch_t (); 541 hb_free (scratch); 542 } 543 } 544 545 #ifndef HB_NO_VAR 546 const gvar_accelerator_t *gvar; 547 #ifndef HB_NO_BEYOND_64K 548 const GVAR_accelerator_t *GVAR; 549 #endif 550 #endif 551 const hmtx_accelerator_t *hmtx; 552 #ifndef HB_NO_VERTICAL 553 const vmtx_accelerator_t *vmtx; 554 #endif 555 556 private: 557 bool short_offset; 558 unsigned int num_glyphs; 559 hb_blob_ptr_t<loca> loca_table; 560 hb_blob_ptr_t<glyf> glyf_table; 561 mutable hb_atomic_t<hb_glyf_scratch_t *> cached_scratch; 562 }; 563 564 565 inline bool 566 glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, 567 hb_font_t *font, 568 hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const 569 { 570 OT::glyf_accelerator_t glyf (plan->source); 571 if (!glyphs.alloc_exact (plan->new_to_old_gid_list.length)) return false; 572 573 for (const auto &pair : plan->new_to_old_gid_list) 574 { 575 hb_codepoint_t new_gid = pair.first; 576 hb_codepoint_t old_gid = pair.second; 577 glyf_impl::SubsetGlyph *p = glyphs.push (); 578 glyf_impl::SubsetGlyph& subset_glyph = *p; 579 subset_glyph.old_gid = old_gid; 580 581 if (unlikely (old_gid == 0 && new_gid == 0 && 582 !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) && 583 !plan->normalized_coords) 584 subset_glyph.source_glyph = glyf_impl::Glyph (); 585 else 586 { 587 /* If plan has an accelerator, the preprocessing step already trimmed glyphs. 588 * Don't trim them again! */ 589 subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, !plan->accelerator); 590 } 591 592 if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) 593 subset_glyph.drop_hints_bytes (); 594 else 595 subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); 596 597 if (font) 598 { 599 if (unlikely (!subset_glyph.compile_bytes_with_deltas (plan, font, glyf))) 600 { 601 // when pinned at default, only bounds are updated, thus no need to free 602 if (!plan->pinned_at_default) 603 _free_compiled_subset_glyphs (glyphs); 604 return false; 605 } 606 } 607 } 608 return true; 609 } 610 611 inline hb_font_t * 612 glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const 613 { 614 hb_font_t *font = hb_font_create (plan->source); 615 if (unlikely (font == hb_font_get_empty ())) return nullptr; 616 617 hb_vector_t<hb_variation_t> vars; 618 if (unlikely (!vars.alloc (plan->user_axes_location.get_population (), true))) 619 { 620 hb_font_destroy (font); 621 return nullptr; 622 } 623 624 for (auto _ : plan->user_axes_location) 625 { 626 hb_variation_t var; 627 var.tag = _.first; 628 var.value = _.second.middle; 629 vars.push (var); 630 } 631 632 #ifndef HB_NO_VAR 633 hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location.get_population ()); 634 #endif 635 return font; 636 } 637 638 639 } /* namespace OT */ 640 641 642 #endif /* OT_GLYF_GLYF_HH */