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: get_composite_iteratorOT::glyf_impl::Glyph37 composite_iter_t get_composite_iterator () const 38 { 39 if (type != COMPOSITE) return composite_iter_t (); 40 return CompositeGlyph (*header, bytes).iter (); 41 } 42 trim_paddingOT::glyf_impl::Glyph43 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 drop_hintsOT::glyf_impl::Glyph53 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 set_overlaps_flagOT::glyf_impl::Glyph62 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 drop_hints_bytesOT::glyf_impl::Glyph71 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 is_compositeOT::glyf_impl::Glyph80 bool is_composite () const 81 { return type == COMPOSITE; } 82 get_all_points_without_varOT::glyf_impl::Glyph83 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 int lsb = 0; 106 int h_delta = face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ? 107 (int) header->xMin - lsb : 0; 108 HB_UNUSED int tsb = 0; 109 int v_orig = (int) header->yMax + 110 #ifndef HB_NO_VERTICAL 111 ((void) face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb) 112 #else 113 0 114 #endif 115 ; 116 unsigned h_adv = face->table.hmtx->get_advance_without_var_unscaled (gid); 117 unsigned v_adv = 118 #ifndef HB_NO_VERTICAL 119 face->table.vmtx->get_advance_without_var_unscaled (gid) 120 #else 121 - face->get_upem () 122 #endif 123 ; 124 phantoms[PHANTOM_LEFT].x = h_delta; 125 phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta; 126 phantoms[PHANTOM_TOP].y = v_orig; 127 phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; 128 } 129 return true; 130 } 131 update_mtxOT::glyf_impl::Glyph132 void update_mtx (const hb_subset_plan_t *plan, 133 int xMin, int xMax, 134 int yMin, int yMax, 135 const contour_point_vector_t &all_points) const 136 { 137 hb_codepoint_t new_gid = 0; 138 if (!plan->new_gid_for_old_gid (gid, &new_gid)) 139 return; 140 141 if (type != EMPTY) 142 { 143 plan->bounds_width_vec[new_gid] = xMax - xMin; 144 plan->bounds_height_vec[new_gid] = yMax - yMin; 145 } 146 147 unsigned len = all_points.length; 148 float leftSideX = all_points[len - 4].x; 149 float rightSideX = all_points[len - 3].x; 150 float topSideY = all_points[len - 2].y; 151 float bottomSideY = all_points[len - 1].y; 152 153 uint32_t hash = hb_hash (new_gid); 154 155 signed hori_aw = roundf (rightSideX - leftSideX); 156 if (hori_aw < 0) hori_aw = 0; 157 int lsb = roundf (xMin - leftSideX); 158 plan->hmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) hori_aw, lsb)); 159 //flag value should be computed using non-empty glyphs 160 if (type != EMPTY && lsb != xMin) 161 plan->head_maxp_info.allXMinIsLsb = false; 162 163 signed vert_aw = roundf (topSideY - bottomSideY); 164 if (vert_aw < 0) vert_aw = 0; 165 int tsb = roundf (topSideY - yMax); 166 plan->vmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) vert_aw, tsb)); 167 } 168 compile_header_bytesOT::glyf_impl::Glyph169 bool compile_header_bytes (const hb_subset_plan_t *plan, 170 const contour_point_vector_t &all_points, 171 hb_bytes_t &dest_bytes /* OUT */) const 172 { 173 GlyphHeader *glyph_header = nullptr; 174 if (!plan->pinned_at_default && type != EMPTY && all_points.length >= 4) 175 { 176 glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size); 177 if (unlikely (!glyph_header)) return false; 178 } 179 180 float xMin = 0, xMax = 0; 181 float yMin = 0, yMax = 0; 182 if (all_points.length > 4) 183 { 184 xMin = xMax = all_points[0].x; 185 yMin = yMax = all_points[0].y; 186 187 unsigned count = all_points.length - 4; 188 for (unsigned i = 1; i < count; i++) 189 { 190 float x = all_points[i].x; 191 float y = all_points[i].y; 192 xMin = hb_min (xMin, x); 193 xMax = hb_max (xMax, x); 194 yMin = hb_min (yMin, y); 195 yMax = hb_max (yMax, y); 196 } 197 } 198 199 200 // These are destined for storage in a 16 bit field to clamp the values to 201 // fit into a 16 bit signed integer. 202 int rounded_xMin = hb_clamp (roundf (xMin), -32768.0f, 32767.0f); 203 int rounded_xMax = hb_clamp (roundf (xMax), -32768.0f, 32767.0f); 204 int rounded_yMin = hb_clamp (roundf (yMin), -32768.0f, 32767.0f); 205 int rounded_yMax = hb_clamp (roundf (yMax), -32768.0f, 32767.0f); 206 207 update_mtx (plan, rounded_xMin, rounded_xMax, rounded_yMin, rounded_yMax, all_points); 208 209 if (type != EMPTY) 210 { 211 plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, rounded_xMin); 212 plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, rounded_yMin); 213 plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, rounded_xMax); 214 plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, rounded_yMax); 215 } 216 217 /* when pinned at default, no need to compile glyph header 218 * and for empty glyphs: all_points only include phantom points. 219 * just update metrics and then return */ 220 if (!glyph_header) 221 return true; 222 223 glyph_header->numberOfContours = header->numberOfContours; 224 225 glyph_header->xMin = rounded_xMin; 226 glyph_header->yMin = rounded_yMin; 227 glyph_header->xMax = rounded_xMax; 228 glyph_header->yMax = rounded_yMax; 229 230 dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size); 231 return true; 232 } 233 compile_bytes_with_deltasOT::glyf_impl::Glyph234 bool compile_bytes_with_deltas (const hb_subset_plan_t *plan, 235 hb_font_t *font, 236 const glyf_accelerator_t &glyf, 237 hb_bytes_t &dest_start, /* IN/OUT */ 238 hb_bytes_t &dest_end /* OUT */) 239 { 240 contour_point_vector_t all_points, points_with_deltas; 241 unsigned composite_contours = 0; 242 head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info; 243 unsigned *composite_contours_p = &composite_contours; 244 245 // don't compute head/maxp values when glyph has no contours(type is EMPTY) 246 // also ignore .notdef glyph when --notdef-outline is not enabled 247 if (type == EMPTY || 248 (gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))) 249 { 250 head_maxp_info_p = nullptr; 251 composite_contours_p = nullptr; 252 } 253 254 if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false)) 255 return false; 256 257 // .notdef, set type to empty so we only update metrics and don't compile bytes for 258 // it 259 if (gid == 0 && 260 !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) 261 { 262 type = EMPTY; 263 dest_start = hb_bytes_t (); 264 dest_end = hb_bytes_t (); 265 } 266 267 //dont compile bytes when pinned at default, just recalculate bounds 268 if (!plan->pinned_at_default) 269 { 270 switch (type) 271 { 272 case COMPOSITE: 273 if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start, 274 points_with_deltas, 275 dest_end)) 276 return false; 277 break; 278 case SIMPLE: 279 if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points, 280 plan->flags & HB_SUBSET_FLAGS_NO_HINTING, 281 dest_end)) 282 return false; 283 break; 284 case EMPTY: 285 /* set empty bytes for empty glyph 286 * do not use source glyph's pointers */ 287 dest_start = hb_bytes_t (); 288 dest_end = hb_bytes_t (); 289 break; 290 } 291 } 292 293 if (!compile_header_bytes (plan, all_points, dest_start)) 294 { 295 dest_end.fini (); 296 return false; 297 } 298 return true; 299 } 300 301 302 /* Note: Recursively calls itself. 303 * all_points includes phantom points 304 */ 305 template <typename accelerator_t> get_pointsOT::glyf_impl::Glyph306 bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, 307 contour_point_vector_t &all_points /* OUT */, 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_map_t *current_glyphs = 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 hb_map_t current_glyphs_stack; 326 if (current_glyphs == nullptr) 327 current_glyphs = ¤t_glyphs_stack; 328 329 if (head_maxp_info) 330 { 331 head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth); 332 } 333 334 if (!coords) 335 coords = hb_array (font->coords, font->num_coords); 336 337 contour_point_vector_t stack_points; 338 contour_point_vector_t &points = type == SIMPLE ? all_points : stack_points; 339 unsigned old_length = points.length; 340 341 switch (type) { 342 case SIMPLE: 343 if (depth == 0 && head_maxp_info) 344 head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours); 345 if (depth > 0 && composite_contours) 346 *composite_contours += (unsigned) header->numberOfContours; 347 if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (all_points, phantom_only))) 348 return false; 349 break; 350 case COMPOSITE: 351 { 352 for (auto &item : get_composite_iterator ()) 353 if (unlikely (!item.get_points (points))) return false; 354 break; 355 } 356 case EMPTY: 357 break; 358 } 359 360 /* Init phantom points */ 361 if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; 362 hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); 363 { 364 int lsb = 0; 365 int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ? 366 (int) header->xMin - lsb : 0; 367 HB_UNUSED int tsb = 0; 368 int v_orig = (int) header->yMax + 369 #ifndef HB_NO_VERTICAL 370 ((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb) 371 #else 372 0 373 #endif 374 ; 375 unsigned h_adv = glyf_accelerator.hmtx->get_advance_without_var_unscaled (gid); 376 unsigned v_adv = 377 #ifndef HB_NO_VERTICAL 378 glyf_accelerator.vmtx->get_advance_without_var_unscaled (gid) 379 #else 380 - font->face->get_upem () 381 #endif 382 ; 383 phantoms[PHANTOM_LEFT].x = h_delta; 384 phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta; 385 phantoms[PHANTOM_TOP].y = v_orig; 386 phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; 387 } 388 389 #ifndef HB_NO_VAR 390 if (coords) 391 glyf_accelerator.gvar->apply_deltas_to_points (gid, 392 coords, 393 points.as_array ().sub_array (old_length), 394 phantom_only && type == SIMPLE); 395 #endif 396 397 // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it 398 // with child glyphs' points 399 if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE) 400 { 401 if (unlikely (!points_with_deltas->resize (points.length))) return false; 402 *points_with_deltas = points; 403 } 404 405 switch (type) { 406 case SIMPLE: 407 if (depth == 0 && head_maxp_info) 408 head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4); 409 break; 410 case COMPOSITE: 411 { 412 unsigned int comp_index = 0; 413 for (auto &item : get_composite_iterator ()) 414 { 415 hb_codepoint_t item_gid = item.get_gid (); 416 417 if (unlikely (current_glyphs->has (item_gid))) 418 continue; 419 420 current_glyphs->add (item_gid); 421 422 unsigned old_count = all_points.length; 423 424 if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) && 425 !glyf_accelerator.glyph_for_gid (item_gid) 426 .get_points (font, 427 glyf_accelerator, 428 all_points, 429 points_with_deltas, 430 head_maxp_info, 431 composite_contours, 432 shift_points_hori, 433 use_my_metrics, 434 phantom_only, 435 coords, 436 current_glyphs, 437 depth + 1, 438 edge_count))) 439 { 440 current_glyphs->del (item_gid); 441 return false; 442 } 443 444 auto comp_points = all_points.as_array ().sub_array (old_count); 445 446 /* Copy phantom points from component if USE_MY_METRICS flag set */ 447 if (use_my_metrics && item.is_use_my_metrics ()) 448 for (unsigned int i = 0; i < PHANTOM_COUNT; i++) 449 phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; 450 451 if (comp_points) // Empty in case of phantom_only 452 { 453 float matrix[4]; 454 contour_point_t default_trans; 455 item.get_transformation (matrix, default_trans); 456 457 /* Apply component transformation & translation (with deltas applied) */ 458 item.transform_points (comp_points, matrix, points[comp_index]); 459 } 460 461 if (item.is_anchored () && !phantom_only) 462 { 463 unsigned int p1, p2; 464 item.get_anchor_points (p1, p2); 465 if (likely (p1 < all_points.length && p2 < comp_points.length)) 466 { 467 contour_point_t delta; 468 delta.init (all_points[p1].x - comp_points[p2].x, 469 all_points[p1].y - comp_points[p2].y); 470 471 item.translate (delta, comp_points); 472 } 473 } 474 475 all_points.resize (all_points.length - PHANTOM_COUNT); 476 477 if (all_points.length > HB_GLYF_MAX_POINTS) 478 { 479 current_glyphs->del (item_gid); 480 return false; 481 } 482 483 comp_index++; 484 current_glyphs->del (item_gid); 485 } 486 487 if (head_maxp_info && depth == 0) 488 { 489 if (composite_contours) 490 head_maxp_info->maxCompositeContours = hb_max (head_maxp_info->maxCompositeContours, *composite_contours); 491 head_maxp_info->maxCompositePoints = hb_max (head_maxp_info->maxCompositePoints, all_points.length); 492 head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index); 493 } 494 all_points.extend (phantoms); 495 } break; 496 case EMPTY: 497 all_points.extend (phantoms); 498 break; 499 } 500 501 if (depth == 0 && shift_points_hori) /* Apply at top level */ 502 { 503 /* Undocumented rasterizer behavior: 504 * Shift points horizontally by the updated left side bearing 505 */ 506 float v = -phantoms[PHANTOM_LEFT].x; 507 if (v) 508 for (auto &point : all_points) 509 point.x += v; 510 } 511 512 return !all_points.in_error (); 513 } 514 get_extents_without_var_scaledOT::glyf_impl::Glyph515 bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator, 516 hb_glyph_extents_t *extents) const 517 { 518 if (type == EMPTY) return true; /* Empty glyph; zero extents. */ 519 return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents); 520 } 521 get_bytesOT::glyf_impl::Glyph522 hb_bytes_t get_bytes () const { return bytes; } get_typeOT::glyf_impl::Glyph523 glyph_type_t get_type () const { return type; } get_headerOT::glyf_impl::Glyph524 const GlyphHeader *get_header () const { return header; } 525 GlyphOT::glyf_impl::Glyph526 Glyph () : bytes (), 527 header (bytes.as<GlyphHeader> ()), 528 gid (-1), 529 type(EMPTY) 530 {} 531 GlyphOT::glyf_impl::Glyph532 Glyph (hb_bytes_t bytes_, 533 hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_), 534 header (bytes.as<GlyphHeader> ()), 535 gid (gid_) 536 { 537 int num_contours = header->numberOfContours; 538 if (unlikely (num_contours == 0)) type = EMPTY; 539 else if (num_contours > 0) type = SIMPLE; 540 else if (num_contours <= -1) type = COMPOSITE; 541 else type = EMPTY; // Spec deviation; Spec says COMPOSITE, but not seen in the wild. 542 } 543 544 protected: 545 hb_bytes_t bytes; 546 const GlyphHeader *header; 547 hb_codepoint_t gid; 548 glyph_type_t type; 549 }; 550 551 552 } /* namespace glyf_impl */ 553 } /* namespace OT */ 554 555 556 #endif /* OT_GLYF_GLYPH_HH */ 557