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