Glyph.hh (18279B)
1 #ifndef OT_GLYF_GLYPH_HH 2 #define OT_GLYF_GLYPH_HH 3 4 5 #include "../../hb-open-type.hh" 6 7 #include "GlyphHeader.hh" 8 #include "SimpleGlyph.hh" 9 #include "CompositeGlyph.hh" 10 11 12 namespace OT { 13 14 struct glyf_accelerator_t; 15 16 namespace glyf_impl { 17 18 19 enum phantom_point_index_t 20 { 21 PHANTOM_LEFT = 0, 22 PHANTOM_RIGHT = 1, 23 PHANTOM_TOP = 2, 24 PHANTOM_BOTTOM = 3, 25 PHANTOM_COUNT = 4 26 }; 27 28 struct Glyph 29 { 30 enum glyph_type_t { 31 EMPTY, 32 SIMPLE, 33 COMPOSITE, 34 }; 35 36 public: 37 composite_iter_t get_composite_iterator () const 38 { 39 if (type != COMPOSITE) return composite_iter_t (); 40 return CompositeGlyph (*header, bytes).iter (); 41 } 42 43 const hb_bytes_t trim_padding () const 44 { 45 switch (type) { 46 case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding (); 47 case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding (); 48 case EMPTY: return bytes; 49 default: return bytes; 50 } 51 } 52 53 void drop_hints () 54 { 55 switch (type) { 56 case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return; 57 case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return; 58 case EMPTY: return; 59 } 60 } 61 62 void set_overlaps_flag () 63 { 64 switch (type) { 65 case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return; 66 case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return; 67 case EMPTY: return; 68 } 69 } 70 71 void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const 72 { 73 switch (type) { 74 case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return; 75 case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return; 76 case EMPTY: return; 77 } 78 } 79 80 bool is_composite () const 81 { return type == COMPOSITE; } 82 83 bool get_all_points_without_var (const hb_face_t *face, 84 contour_point_vector_t &points /* OUT */) const 85 { 86 switch (type) { 87 case SIMPLE: 88 if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points))) 89 return false; 90 break; 91 case COMPOSITE: 92 { 93 for (auto &item : get_composite_iterator ()) 94 if (unlikely (!item.get_points (points))) return false; 95 break; 96 } 97 case EMPTY: 98 break; 99 } 100 101 /* Init phantom points */ 102 if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; 103 hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); 104 { 105 // Duplicated code. 106 int lsb = 0; 107 face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb); 108 int h_delta = (int) header->xMin - lsb; 109 HB_UNUSED int tsb = 0; 110 #ifndef HB_NO_VERTICAL 111 face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb); 112 #endif 113 int v_orig = (int) header->yMax + tsb; 114 unsigned h_adv = face->table.hmtx->get_advance_without_var_unscaled (gid); 115 unsigned v_adv = 116 #ifndef HB_NO_VERTICAL 117 face->table.vmtx->get_advance_without_var_unscaled (gid) 118 #else 119 - face->get_upem () 120 #endif 121 ; 122 phantoms[PHANTOM_LEFT].x = h_delta; 123 phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta; 124 phantoms[PHANTOM_TOP].y = v_orig; 125 phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; 126 } 127 return true; 128 } 129 130 void update_mtx (const hb_subset_plan_t *plan, 131 int xMin, int xMax, 132 int yMin, int yMax, 133 const contour_point_vector_t &all_points) const 134 { 135 hb_codepoint_t new_gid = 0; 136 if (!plan->new_gid_for_old_gid (gid, &new_gid)) 137 return; 138 139 if (type != EMPTY) 140 { 141 plan->bounds_width_vec[new_gid] = xMax - xMin; 142 plan->bounds_height_vec[new_gid] = yMax - yMin; 143 } 144 145 unsigned len = all_points.length; 146 float leftSideX = all_points[len - 4].x; 147 float rightSideX = all_points[len - 3].x; 148 float topSideY = all_points[len - 2].y; 149 float bottomSideY = all_points[len - 1].y; 150 151 uint32_t hash = hb_hash (new_gid); 152 153 signed hori_aw = roundf (rightSideX - leftSideX); 154 if (hori_aw < 0) hori_aw = 0; 155 int lsb = roundf (xMin - leftSideX); 156 plan->hmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) hori_aw, lsb)); 157 //flag value should be computed using non-empty glyphs 158 if (type != EMPTY && lsb != xMin) 159 plan->head_maxp_info.allXMinIsLsb = false; 160 161 signed vert_aw = roundf (topSideY - bottomSideY); 162 if (vert_aw < 0) vert_aw = 0; 163 int tsb = roundf (topSideY - yMax); 164 plan->vmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) vert_aw, tsb)); 165 } 166 167 bool compile_header_bytes (const hb_subset_plan_t *plan, 168 const contour_point_vector_t &all_points, 169 hb_bytes_t &dest_bytes /* OUT */) const 170 { 171 GlyphHeader *glyph_header = nullptr; 172 if (!plan->pinned_at_default && type != EMPTY && all_points.length >= 4) 173 { 174 glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size); 175 if (unlikely (!glyph_header)) return false; 176 } 177 178 float xMin = 0, xMax = 0; 179 float yMin = 0, yMax = 0; 180 if (all_points.length > 4) 181 { 182 xMin = xMax = all_points[0].x; 183 yMin = yMax = all_points[0].y; 184 185 unsigned count = all_points.length - 4; 186 for (unsigned i = 1; i < count; i++) 187 { 188 float x = all_points[i].x; 189 float y = all_points[i].y; 190 xMin = hb_min (xMin, x); 191 xMax = hb_max (xMax, x); 192 yMin = hb_min (yMin, y); 193 yMax = hb_max (yMax, y); 194 } 195 } 196 197 198 // These are destined for storage in a 16 bit field to clamp the values to 199 // fit into a 16 bit signed integer. 200 int rounded_xMin = hb_clamp (roundf (xMin), -32768.0f, 32767.0f); 201 int rounded_xMax = hb_clamp (roundf (xMax), -32768.0f, 32767.0f); 202 int rounded_yMin = hb_clamp (roundf (yMin), -32768.0f, 32767.0f); 203 int rounded_yMax = hb_clamp (roundf (yMax), -32768.0f, 32767.0f); 204 205 update_mtx (plan, rounded_xMin, rounded_xMax, rounded_yMin, rounded_yMax, all_points); 206 207 if (type != EMPTY) 208 { 209 plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, rounded_xMin); 210 plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, rounded_yMin); 211 plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, rounded_xMax); 212 plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, rounded_yMax); 213 } 214 215 /* when pinned at default, no need to compile glyph header 216 * and for empty glyphs: all_points only include phantom points. 217 * just update metrics and then return */ 218 if (!glyph_header) 219 return true; 220 221 glyph_header->numberOfContours = header->numberOfContours; 222 223 glyph_header->xMin = rounded_xMin; 224 glyph_header->yMin = rounded_yMin; 225 glyph_header->xMax = rounded_xMax; 226 glyph_header->yMax = rounded_yMax; 227 228 dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size); 229 return true; 230 } 231 232 bool compile_bytes_with_deltas (const hb_subset_plan_t *plan, 233 hb_font_t *font, 234 const glyf_accelerator_t &glyf, 235 hb_bytes_t &dest_start, /* IN/OUT */ 236 hb_bytes_t &dest_end /* OUT */) 237 { 238 contour_point_vector_t all_points, points_with_deltas; 239 unsigned composite_contours = 0; 240 head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info; 241 unsigned *composite_contours_p = &composite_contours; 242 243 // don't compute head/maxp values when glyph has no contours(type is EMPTY) 244 // also ignore .notdef glyph when --notdef-outline is not enabled 245 if (type == EMPTY || 246 (gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))) 247 { 248 head_maxp_info_p = nullptr; 249 composite_contours_p = nullptr; 250 } 251 252 hb_glyf_scratch_t scratch; 253 if (!get_points (font, glyf, all_points, scratch, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false)) 254 return false; 255 256 // .notdef, set type to empty so we only update metrics and don't compile bytes for 257 // it 258 if (gid == 0 && 259 !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) 260 { 261 type = EMPTY; 262 dest_start = hb_bytes_t (); 263 dest_end = hb_bytes_t (); 264 } 265 266 //dont compile bytes when pinned at default, just recalculate bounds 267 if (!plan->pinned_at_default) 268 { 269 switch (type) 270 { 271 case COMPOSITE: 272 if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start, 273 points_with_deltas, 274 dest_end)) 275 return false; 276 break; 277 case SIMPLE: 278 if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points, 279 plan->flags & HB_SUBSET_FLAGS_NO_HINTING, 280 dest_end)) 281 return false; 282 break; 283 case EMPTY: 284 /* set empty bytes for empty glyph 285 * do not use source glyph's pointers */ 286 dest_start = hb_bytes_t (); 287 dest_end = hb_bytes_t (); 288 break; 289 } 290 } 291 292 if (!compile_header_bytes (plan, all_points, dest_start)) 293 { 294 dest_end.fini (); 295 return false; 296 } 297 return true; 298 } 299 300 301 /* Note: Recursively calls itself. 302 * all_points includes phantom points 303 */ 304 template <typename accelerator_t> 305 bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, 306 contour_point_vector_t &all_points /* OUT */, 307 hb_glyf_scratch_t &scratch, 308 contour_point_vector_t *points_with_deltas = nullptr, /* OUT */ 309 head_maxp_info_t * head_maxp_info = nullptr, /* OUT */ 310 unsigned *composite_contours = nullptr, /* OUT */ 311 bool shift_points_hori = true, 312 bool use_my_metrics = true, 313 bool phantom_only = false, 314 hb_array_t<const int> coords = hb_array_t<const int> (), 315 hb_scalar_cache_t *gvar_cache = nullptr, 316 unsigned int depth = 0, 317 unsigned *edge_count = nullptr) const 318 { 319 if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false; 320 unsigned stack_edge_count = 0; 321 if (!edge_count) edge_count = &stack_edge_count; 322 if (unlikely (*edge_count > HB_MAX_GRAPH_EDGE_COUNT)) return false; 323 (*edge_count)++; 324 325 if (head_maxp_info) 326 { 327 head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth); 328 } 329 330 if (!coords && font->has_nonzero_coords) 331 coords = hb_array (font->coords, font->num_coords); 332 333 contour_point_vector_t &points = type == SIMPLE ? all_points : scratch.comp_points; 334 unsigned old_length = points.length; 335 336 switch (type) { 337 case SIMPLE: 338 if (depth == 0 && head_maxp_info) 339 head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours); 340 if (depth > 0 && composite_contours) 341 *composite_contours += (unsigned) header->numberOfContours; 342 if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (all_points, phantom_only))) 343 return false; 344 break; 345 case COMPOSITE: 346 { 347 for (auto &item : get_composite_iterator ()) 348 if (unlikely (!item.get_points (points))) return false; 349 break; 350 } 351 case EMPTY: 352 break; 353 } 354 355 /* Init phantom points */ 356 if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; 357 hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); 358 { 359 // Duplicated code. 360 int lsb = 0; 361 glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb); 362 int h_delta = (int) header->xMin - lsb; 363 HB_UNUSED int tsb = 0; 364 #ifndef HB_NO_VERTICAL 365 glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb); 366 #endif 367 int v_orig = (int) header->yMax + tsb; 368 unsigned h_adv = glyf_accelerator.hmtx->get_advance_without_var_unscaled (gid); 369 unsigned v_adv = 370 #ifndef HB_NO_VERTICAL 371 glyf_accelerator.vmtx->get_advance_without_var_unscaled (gid) 372 #else 373 - font->face->get_upem () 374 #endif 375 ; 376 phantoms[PHANTOM_LEFT].x = h_delta; 377 phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta; 378 phantoms[PHANTOM_TOP].y = v_orig; 379 phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; 380 } 381 382 #ifndef HB_NO_VAR 383 if (hb_any (coords)) 384 { 385 #ifndef HB_NO_BEYOND_64K 386 if (glyf_accelerator.GVAR->has_data ()) 387 glyf_accelerator.GVAR->apply_deltas_to_points (gid, 388 coords, 389 points.as_array ().sub_array (old_length), 390 scratch, 391 gvar_cache, 392 phantom_only && type == SIMPLE); 393 else 394 #endif 395 glyf_accelerator.gvar->apply_deltas_to_points (gid, 396 coords, 397 points.as_array ().sub_array (old_length), 398 scratch, 399 gvar_cache, 400 phantom_only && type == SIMPLE); 401 } 402 #endif 403 404 // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it 405 // with child glyphs' points 406 if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE) 407 { 408 assert (old_length == 0); 409 *points_with_deltas = points; 410 } 411 412 float shift = 0; 413 switch (type) { 414 case SIMPLE: 415 if (depth == 0 && head_maxp_info) 416 head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4); 417 shift = phantoms[PHANTOM_LEFT].x; 418 break; 419 case COMPOSITE: 420 { 421 hb_decycler_node_t decycler_node (scratch.decycler); 422 423 unsigned int comp_index = 0; 424 for (auto &item : get_composite_iterator ()) 425 { 426 hb_codepoint_t item_gid = item.get_gid (); 427 428 if (unlikely (!decycler_node.visit (item_gid))) 429 { 430 comp_index++; 431 continue; 432 } 433 434 unsigned old_count = all_points.length; 435 436 if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) && 437 !glyf_accelerator.glyph_for_gid (item_gid) 438 .get_points (font, 439 glyf_accelerator, 440 all_points, 441 scratch, 442 points_with_deltas, 443 head_maxp_info, 444 composite_contours, 445 shift_points_hori, 446 use_my_metrics, 447 phantom_only, 448 coords, 449 gvar_cache, 450 depth + 1, 451 edge_count))) 452 { 453 points.resize (old_length); 454 return false; 455 } 456 457 // points might have been reallocated. Relocate phantoms. 458 phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); 459 460 auto comp_points = all_points.as_array ().sub_array (old_count); 461 462 /* Copy phantom points from component if USE_MY_METRICS flag set */ 463 if (use_my_metrics && item.is_use_my_metrics ()) 464 for (unsigned int i = 0; i < PHANTOM_COUNT; i++) 465 phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; 466 467 if (comp_points) // Empty in case of phantom_only 468 { 469 float matrix[4]; 470 contour_point_t default_trans; 471 item.get_transformation (matrix, default_trans); 472 473 /* Apply component transformation & translation (with deltas applied) */ 474 item.transform_points (comp_points, matrix, points[old_length + comp_index]); 475 } 476 477 if (item.is_anchored () && !phantom_only) 478 { 479 unsigned int p1, p2; 480 item.get_anchor_points (p1, p2); 481 if (likely (p1 < all_points.length && p2 < comp_points.length)) 482 { 483 contour_point_t delta; 484 delta.init (all_points[p1].x - comp_points[p2].x, 485 all_points[p1].y - comp_points[p2].y); 486 487 item.translate (delta, comp_points); 488 } 489 } 490 491 all_points.resize (all_points.length - PHANTOM_COUNT); 492 493 if (all_points.length > HB_GLYF_MAX_POINTS) 494 { 495 points.resize (old_length); 496 return false; 497 } 498 499 comp_index++; 500 } 501 502 if (head_maxp_info && depth == 0) 503 { 504 if (composite_contours) 505 head_maxp_info->maxCompositeContours = hb_max (head_maxp_info->maxCompositeContours, *composite_contours); 506 head_maxp_info->maxCompositePoints = hb_max (head_maxp_info->maxCompositePoints, all_points.length); 507 head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index); 508 } 509 all_points.extend (phantoms); 510 shift = phantoms[PHANTOM_LEFT].x; 511 points.resize (old_length); 512 } break; 513 case EMPTY: 514 all_points.extend (phantoms); 515 shift = phantoms[PHANTOM_LEFT].x; 516 points.resize (old_length); 517 break; 518 } 519 520 if (depth == 0 && shift_points_hori) /* Apply at top level */ 521 { 522 /* Undocumented rasterizer behavior: 523 * Shift points horizontally by the updated left side bearing 524 */ 525 if (shift) 526 for (auto &point : all_points) 527 point.x -= shift; 528 } 529 530 return !all_points.in_error (); 531 } 532 533 bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator, 534 hb_glyph_extents_t *extents) const 535 { 536 if (type == EMPTY) 537 { 538 *extents = {0, 0, 0, 0}; 539 return true; /* Empty glyph; zero extents. */ 540 } 541 return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents); 542 } 543 544 hb_bytes_t get_bytes () const { return bytes; } 545 glyph_type_t get_type () const { return type; } 546 const GlyphHeader *get_header () const { return header; } 547 548 Glyph () : bytes (), 549 header (bytes.as<GlyphHeader> ()), 550 gid (-1), 551 type(EMPTY) 552 {} 553 554 Glyph (hb_bytes_t bytes_, 555 hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_), 556 header (bytes.as<GlyphHeader> ()), 557 gid (gid_) 558 { 559 int num_contours = header->numberOfContours; 560 if (unlikely (num_contours == 0)) type = EMPTY; 561 else if (num_contours > 0) type = SIMPLE; 562 else if (num_contours <= -1) type = COMPOSITE; 563 else type = EMPTY; // Spec deviation; Spec says COMPOSITE, but not seen in the wild. 564 } 565 566 protected: 567 hb_bytes_t bytes; 568 const GlyphHeader *header; 569 hb_codepoint_t gid; 570 glyph_type_t type; 571 }; 572 573 574 } /* namespace glyf_impl */ 575 } /* namespace OT */ 576 577 578 #endif /* OT_GLYF_GLYPH_HH */