Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 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: | |
| 40 composite_iter_t get_composite_iterator () const | |
| 41 { | |
| 42 if (type != COMPOSITE) return composite_iter_t (); | |
| 43 return CompositeGlyph (*header, bytes).iter (); | |
| 44 } | |
| 45 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 | |
| 51 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 | |
| 60 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 | |
| 69 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 | |
| 78 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 | |
| 87 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 | |
| 112 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 | |
| 158 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> | |
| 208 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 | |
| 424 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 | |
| 431 hb_bytes_t get_bytes () const { return bytes; } | |
| 432 | |
| 433 Glyph () : bytes (), | |
| 434 header (bytes.as<GlyphHeader> ()), | |
| 435 gid (-1), | |
| 436 type(EMPTY) | |
| 437 {} | |
| 438 | |
| 439 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 */ |
