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 #ifndef HB_GLYF_MAX_POINTS 22 #define HB_GLYF_MAX_POINTS 10000 23 #endif 24 25 26 enum phantom_point_index_t 27 { 28 PHANTOM_LEFT = 0, 29 PHANTOM_RIGHT = 1, 30 PHANTOM_TOP = 2, 31 PHANTOM_BOTTOM = 3, 32 PHANTOM_COUNT = 4 33 }; 34 35 struct Glyph 36 { 37 enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE, VAR_COMPOSITE }; 38 39 public: get_composite_iteratorOT::glyf_impl::Glyph40 composite_iter_t get_composite_iterator () const 41 { 42 if (type != COMPOSITE) return composite_iter_t (); 43 return CompositeGlyph (*header, bytes).iter (); 44 } get_var_composite_iteratorOT::glyf_impl::Glyph45 var_composite_iter_t get_var_composite_iterator () const 46 { 47 if (type != VAR_COMPOSITE) return var_composite_iter_t (); 48 return VarCompositeGlyph (*header, bytes).iter (); 49 } 50 trim_paddingOT::glyf_impl::Glyph51 const hb_bytes_t trim_padding () const 52 { 53 switch (type) { 54 case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding (); 55 case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding (); 56 default: return bytes; 57 } 58 } 59 drop_hintsOT::glyf_impl::Glyph60 void drop_hints () 61 { 62 switch (type) { 63 case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return; 64 case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return; 65 default: return; 66 } 67 } 68 set_overlaps_flagOT::glyf_impl::Glyph69 void set_overlaps_flag () 70 { 71 switch (type) { 72 case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return; 73 case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return; 74 default: return; 75 } 76 } 77 drop_hints_bytesOT::glyf_impl::Glyph78 void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const 79 { 80 switch (type) { 81 case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return; 82 case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return; 83 default: return; 84 } 85 } 86 update_mtxOT::glyf_impl::Glyph87 void update_mtx (const hb_subset_plan_t *plan, 88 int xMin, int yMax, 89 const contour_point_vector_t &all_points) const 90 { 91 hb_codepoint_t new_gid = 0; 92 if (!plan->new_gid_for_old_gid (gid, &new_gid)) 93 return; 94 95 unsigned len = all_points.length; 96 float leftSideX = all_points[len - 4].x; 97 float rightSideX = all_points[len - 3].x; 98 float topSideY = all_points[len - 2].y; 99 float bottomSideY = all_points[len - 1].y; 100 101 int hori_aw = roundf (rightSideX - leftSideX); 102 if (hori_aw < 0) hori_aw = 0; 103 int lsb = roundf (xMin - leftSideX); 104 plan->hmtx_map->set (new_gid, hb_pair (hori_aw, lsb)); 105 106 int vert_aw = roundf (topSideY - bottomSideY); 107 if (vert_aw < 0) vert_aw = 0; 108 int tsb = roundf (topSideY - yMax); 109 plan->vmtx_map->set (new_gid, hb_pair (vert_aw, tsb)); 110 } 111 compile_header_bytesOT::glyf_impl::Glyph112 bool compile_header_bytes (const hb_subset_plan_t *plan, 113 const contour_point_vector_t &all_points, 114 hb_bytes_t &dest_bytes /* OUT */) const 115 { 116 GlyphHeader *glyph_header = nullptr; 117 if (type != EMPTY && all_points.length > 4) 118 { 119 glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size); 120 if (unlikely (!glyph_header)) return false; 121 } 122 123 float xMin = 0, xMax = 0; 124 float yMin = 0, yMax = 0; 125 if (all_points.length > 4) 126 { 127 xMin = xMax = all_points[0].x; 128 yMin = yMax = all_points[0].y; 129 } 130 131 for (unsigned i = 1; i < all_points.length - 4; i++) 132 { 133 float x = all_points[i].x; 134 float y = all_points[i].y; 135 xMin = hb_min (xMin, x); 136 xMax = hb_max (xMax, x); 137 yMin = hb_min (yMin, y); 138 yMax = hb_max (yMax, y); 139 } 140 141 update_mtx (plan, roundf (xMin), roundf (yMax), all_points); 142 143 /*for empty glyphs: all_points only include phantom points. 144 *just update metrics and then return */ 145 if (!glyph_header) 146 return true; 147 148 glyph_header->numberOfContours = header->numberOfContours; 149 glyph_header->xMin = roundf (xMin); 150 glyph_header->yMin = roundf (yMin); 151 glyph_header->xMax = roundf (xMax); 152 glyph_header->yMax = roundf (yMax); 153 154 dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size); 155 return true; 156 } 157 compile_bytes_with_deltasOT::glyf_impl::Glyph158 bool compile_bytes_with_deltas (const hb_subset_plan_t *plan, 159 hb_font_t *font, 160 const glyf_accelerator_t &glyf, 161 hb_bytes_t &dest_start, /* IN/OUT */ 162 hb_bytes_t &dest_end /* OUT */) 163 { 164 contour_point_vector_t all_points, deltas; 165 if (!get_points (font, glyf, all_points, &deltas, false, false)) 166 return false; 167 168 // .notdef, set type to empty so we only update metrics and don't compile bytes for 169 // it 170 if (gid == 0 && 171 !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) 172 type = EMPTY; 173 174 switch (type) { 175 case COMPOSITE: 176 if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start, 177 deltas, 178 dest_end)) 179 return false; 180 break; 181 case SIMPLE: 182 if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points, 183 plan->flags & HB_SUBSET_FLAGS_NO_HINTING, 184 dest_end)) 185 return false; 186 break; 187 default: 188 /* set empty bytes for empty glyph 189 * do not use source glyph's pointers */ 190 dest_start = hb_bytes_t (); 191 dest_end = hb_bytes_t (); 192 break; 193 } 194 195 if (!compile_header_bytes (plan, all_points, dest_start)) 196 { 197 dest_end.fini (); 198 return false; 199 } 200 return true; 201 } 202 203 204 /* Note: Recursively calls itself. 205 * all_points includes phantom points 206 */ 207 template <typename accelerator_t> get_pointsOT::glyf_impl::Glyph208 bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, 209 contour_point_vector_t &all_points /* OUT */, 210 contour_point_vector_t *deltas = nullptr, /* OUT */ 211 bool shift_points_hori = true, 212 bool use_my_metrics = true, 213 bool phantom_only = false, 214 hb_array_t<int> coords = hb_array_t<int> (), 215 unsigned int depth = 0) const 216 { 217 if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false; 218 219 if (!coords) 220 coords = hb_array (font->coords, font->num_coords); 221 222 contour_point_vector_t stack_points; 223 bool inplace = type == SIMPLE && all_points.length == 0; 224 /* Load into all_points if it's empty, as an optimization. */ 225 contour_point_vector_t &points = inplace ? all_points : stack_points; 226 227 switch (type) { 228 case SIMPLE: 229 if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only))) 230 return false; 231 break; 232 case COMPOSITE: 233 { 234 /* pseudo component points for each component in composite glyph */ 235 unsigned num_points = hb_len (CompositeGlyph (*header, bytes).iter ()); 236 if (unlikely (!points.resize (num_points))) return false; 237 break; 238 } 239 #ifndef HB_NO_VAR_COMPOSITES 240 case VAR_COMPOSITE: 241 { 242 for (auto &item : get_var_composite_iterator ()) 243 if (unlikely (!item.get_points (points))) return false; 244 } 245 #endif 246 default: 247 break; 248 } 249 250 /* Init phantom points */ 251 if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; 252 hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); 253 { 254 int lsb = 0; 255 int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ? 256 (int) header->xMin - lsb : 0; 257 HB_UNUSED int tsb = 0; 258 int v_orig = (int) header->yMax + 259 #ifndef HB_NO_VERTICAL 260 ((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb) 261 #else 262 0 263 #endif 264 ; 265 unsigned h_adv = glyf_accelerator.hmtx->get_advance_without_var_unscaled (gid); 266 unsigned v_adv = 267 #ifndef HB_NO_VERTICAL 268 glyf_accelerator.vmtx->get_advance_without_var_unscaled (gid) 269 #else 270 - font->face->get_upem () 271 #endif 272 ; 273 phantoms[PHANTOM_LEFT].x = h_delta; 274 phantoms[PHANTOM_RIGHT].x = h_adv + h_delta; 275 phantoms[PHANTOM_TOP].y = v_orig; 276 phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; 277 } 278 279 if (deltas != nullptr && depth == 0 && type == COMPOSITE) 280 { 281 if (unlikely (!deltas->resize (points.length))) return false; 282 deltas->copy_vector (points); 283 } 284 285 #ifndef HB_NO_VAR 286 glyf_accelerator.gvar->apply_deltas_to_points (gid, 287 coords, 288 points.as_array ()); 289 #endif 290 291 // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it 292 // with child glyphs' points 293 if (deltas != nullptr && depth == 0 && type == COMPOSITE) 294 { 295 for (unsigned i = 0 ; i < points.length; i++) 296 { 297 deltas->arrayZ[i].x = points.arrayZ[i].x - deltas->arrayZ[i].x; 298 deltas->arrayZ[i].y = points.arrayZ[i].y - deltas->arrayZ[i].y; 299 } 300 } 301 302 switch (type) { 303 case SIMPLE: 304 if (!inplace) 305 all_points.extend (points.as_array ()); 306 break; 307 case COMPOSITE: 308 { 309 contour_point_vector_t comp_points; 310 unsigned int comp_index = 0; 311 for (auto &item : get_composite_iterator ()) 312 { 313 comp_points.reset (); 314 315 if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ()) 316 .get_points (font, 317 glyf_accelerator, 318 comp_points, 319 deltas, 320 shift_points_hori, 321 use_my_metrics, 322 phantom_only, 323 coords, 324 depth + 1))) 325 return false; 326 327 /* Copy phantom points from component if USE_MY_METRICS flag set */ 328 if (use_my_metrics && item.is_use_my_metrics ()) 329 for (unsigned int i = 0; i < PHANTOM_COUNT; i++) 330 phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; 331 332 /* Apply component transformation & translation */ 333 item.transform_points (comp_points); 334 335 /* Apply translation from gvar */ 336 comp_points.translate (points[comp_index]); 337 338 if (item.is_anchored ()) 339 { 340 unsigned int p1, p2; 341 item.get_anchor_points (p1, p2); 342 if (likely (p1 < all_points.length && p2 < comp_points.length)) 343 { 344 contour_point_t delta; 345 delta.init (all_points[p1].x - comp_points[p2].x, 346 all_points[p1].y - comp_points[p2].y); 347 348 comp_points.translate (delta); 349 } 350 } 351 352 all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT)); 353 354 if (all_points.length > HB_GLYF_MAX_POINTS) 355 return false; 356 357 comp_index++; 358 } 359 360 all_points.extend (phantoms); 361 } break; 362 #ifndef HB_NO_VAR_COMPOSITES 363 case VAR_COMPOSITE: 364 { 365 contour_point_vector_t comp_points; 366 hb_array_t<contour_point_t> points_left = points.as_array (); 367 for (auto &item : get_var_composite_iterator ()) 368 { 369 hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item.get_num_points ()); 370 371 comp_points.reset (); 372 373 coord_setter_t coord_setter (coords); 374 item.set_variations (coord_setter, record_points); 375 376 if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ()) 377 .get_points (font, 378 glyf_accelerator, 379 comp_points, 380 deltas, 381 shift_points_hori, 382 use_my_metrics, 383 phantom_only, 384 coord_setter.get_coords (), 385 depth + 1))) 386 return false; 387 388 /* Apply component transformation */ 389 item.transform_points (record_points, comp_points); 390 391 /* Copy phantom points from component if USE_MY_METRICS flag set */ 392 if (use_my_metrics && item.is_use_my_metrics ()) 393 for (unsigned int i = 0; i < PHANTOM_COUNT; i++) 394 phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; 395 396 all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT)); 397 398 if (all_points.length > HB_GLYF_MAX_POINTS) 399 return false; 400 401 points_left += item.get_num_points (); 402 } 403 all_points.extend (phantoms); 404 } break; 405 #endif 406 default: 407 all_points.extend (phantoms); 408 break; 409 } 410 411 if (depth == 0 && shift_points_hori) /* Apply at top level */ 412 { 413 /* Undocumented rasterizer behavior: 414 * Shift points horizontally by the updated left side bearing 415 */ 416 contour_point_t delta; 417 delta.init (-phantoms[PHANTOM_LEFT].x, 0.f); 418 if (delta.x) all_points.translate (delta); 419 } 420 421 return !all_points.in_error (); 422 } 423 get_extents_without_var_scaledOT::glyf_impl::Glyph424 bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator, 425 hb_glyph_extents_t *extents) const 426 { 427 if (type == EMPTY) return true; /* Empty glyph; zero extents. */ 428 return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents); 429 } 430 get_bytesOT::glyf_impl::Glyph431 hb_bytes_t get_bytes () const { return bytes; } 432 GlyphOT::glyf_impl::Glyph433 Glyph () : bytes (), 434 header (bytes.as<GlyphHeader> ()), 435 gid (-1), 436 type(EMPTY) 437 {} 438 GlyphOT::glyf_impl::Glyph439 Glyph (hb_bytes_t bytes_, 440 hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_), 441 header (bytes.as<GlyphHeader> ()), 442 gid (gid_) 443 { 444 int num_contours = header->numberOfContours; 445 if (unlikely (num_contours == 0)) type = EMPTY; 446 else if (num_contours > 0) type = SIMPLE; 447 else if (num_contours == -2) type = VAR_COMPOSITE; 448 else type = COMPOSITE; /* negative numbers */ 449 } 450 451 protected: 452 hb_bytes_t bytes; 453 const GlyphHeader *header; 454 hb_codepoint_t gid; 455 unsigned type; 456 }; 457 458 459 } /* namespace glyf_impl */ 460 } /* namespace OT */ 461 462 463 #endif /* OT_GLYF_GLYPH_HH */ 464