Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/harfbuzz/src/OT/glyf/glyf.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_GLYF_HH | |
| 2 #define OT_GLYF_GLYF_HH | |
| 3 | |
| 4 | |
| 5 #include "../../hb-open-type.hh" | |
| 6 #include "../../hb-ot-head-table.hh" | |
| 7 #include "../../hb-ot-hmtx-table.hh" | |
| 8 #include "../../hb-ot-var-gvar-table.hh" | |
| 9 #include "../../hb-draw.hh" | |
| 10 | |
| 11 #include "glyf-helpers.hh" | |
| 12 #include "Glyph.hh" | |
| 13 #include "SubsetGlyph.hh" | |
| 14 #include "loca.hh" | |
| 15 #include "path-builder.hh" | |
| 16 | |
| 17 | |
| 18 namespace OT { | |
| 19 | |
| 20 | |
| 21 /* | |
| 22 * glyf -- TrueType Glyph Data | |
| 23 * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf | |
| 24 */ | |
| 25 #define HB_OT_TAG_glyf HB_TAG('g','l','y','f') | |
| 26 | |
| 27 struct glyf | |
| 28 { | |
| 29 friend struct glyf_accelerator_t; | |
| 30 | |
| 31 static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf; | |
| 32 | |
| 33 bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const | |
| 34 { | |
| 35 TRACE_SANITIZE (this); | |
| 36 /* Runtime checks as eager sanitizing each glyph is costy */ | |
| 37 return_trace (true); | |
| 38 } | |
| 39 | |
| 40 /* requires source of SubsetGlyph complains the identifier isn't declared */ | |
| 41 template <typename Iterator> | |
| 42 bool serialize (hb_serialize_context_t *c, | |
| 43 Iterator it, | |
| 44 bool use_short_loca, | |
| 45 const hb_subset_plan_t *plan, | |
| 46 hb_font_t *font) | |
| 47 { | |
| 48 TRACE_SERIALIZE (this); | |
| 49 | |
| 50 unsigned init_len = c->length (); | |
| 51 for (auto &_ : it) | |
| 52 if (unlikely (!_.serialize (c, use_short_loca, plan, font))) | |
| 53 return false; | |
| 54 | |
| 55 /* As a special case when all glyph in the font are empty, add a zero byte | |
| 56 * to the table, so that OTS doesn’t reject it, and to make the table work | |
| 57 * on Windows as well. | |
| 58 * See https://github.com/khaledhosny/ots/issues/52 */ | |
| 59 if (init_len == c->length ()) | |
| 60 { | |
| 61 HBUINT8 empty_byte; | |
| 62 empty_byte = 0; | |
| 63 c->copy (empty_byte); | |
| 64 } | |
| 65 return_trace (true); | |
| 66 } | |
| 67 | |
| 68 /* Byte region(s) per glyph to output | |
| 69 unpadded, hints removed if so requested | |
| 70 If we fail to process a glyph we produce an empty (0-length) glyph */ | |
| 71 bool subset (hb_subset_context_t *c) const | |
| 72 { | |
| 73 TRACE_SUBSET (this); | |
| 74 | |
| 75 glyf *glyf_prime = c->serializer->start_embed <glyf> (); | |
| 76 if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); | |
| 77 | |
| 78 hb_vector_t<glyf_impl::SubsetGlyph> glyphs; | |
| 79 _populate_subset_glyphs (c->plan, glyphs); | |
| 80 | |
| 81 hb_font_t *font = nullptr; | |
| 82 if (!c->plan->pinned_at_default) | |
| 83 { | |
| 84 font = _create_font_for_instancing (c->plan); | |
| 85 if (unlikely (!font)) return false; | |
| 86 } | |
| 87 | |
| 88 auto padded_offsets = | |
| 89 + hb_iter (glyphs) | |
| 90 | hb_map (&glyf_impl::SubsetGlyph::padded_size) | |
| 91 ; | |
| 92 | |
| 93 bool use_short_loca = false; | |
| 94 if (likely (!c->plan->force_long_loca)) | |
| 95 { | |
| 96 unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0); | |
| 97 use_short_loca = max_offset < 0x1FFFF; | |
| 98 } | |
| 99 | |
| 100 glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan, font); | |
| 101 if (!use_short_loca) { | |
| 102 padded_offsets = | |
| 103 + hb_iter (glyphs) | |
| 104 | hb_map (&glyf_impl::SubsetGlyph::length) | |
| 105 ; | |
| 106 } | |
| 107 | |
| 108 if (font) | |
| 109 { | |
| 110 _free_compiled_subset_glyphs (&glyphs); | |
| 111 hb_font_destroy (font); | |
| 112 } | |
| 113 | |
| 114 if (unlikely (c->serializer->in_error ())) return_trace (false); | |
| 115 return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan, | |
| 116 padded_offsets, | |
| 117 use_short_loca))); | |
| 118 } | |
| 119 | |
| 120 void | |
| 121 _populate_subset_glyphs (const hb_subset_plan_t *plan, | |
| 122 hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const; | |
| 123 | |
| 124 hb_font_t * | |
| 125 _create_font_for_instancing (const hb_subset_plan_t *plan) const; | |
| 126 | |
| 127 void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> *glyphs) const | |
| 128 { | |
| 129 for (auto _ : *glyphs) | |
| 130 _.free_compiled_bytes (); | |
| 131 } | |
| 132 | |
| 133 protected: | |
| 134 UnsizedArrayOf<HBUINT8> | |
| 135 dataZ; /* Glyphs data. */ | |
| 136 public: | |
| 137 DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always | |
| 138 * check the size externally, allow Null() object of it by | |
| 139 * defining it _MIN instead. */ | |
| 140 }; | |
| 141 | |
| 142 struct glyf_accelerator_t | |
| 143 { | |
| 144 glyf_accelerator_t (hb_face_t *face) | |
| 145 { | |
| 146 short_offset = false; | |
| 147 num_glyphs = 0; | |
| 148 loca_table = nullptr; | |
| 149 glyf_table = nullptr; | |
| 150 #ifndef HB_NO_VAR | |
| 151 gvar = nullptr; | |
| 152 #endif | |
| 153 hmtx = nullptr; | |
| 154 #ifndef HB_NO_VERTICAL | |
| 155 vmtx = nullptr; | |
| 156 #endif | |
| 157 const OT::head &head = *face->table.head; | |
| 158 if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0) | |
| 159 /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ | |
| 160 return; | |
| 161 short_offset = 0 == head.indexToLocFormat; | |
| 162 | |
| 163 loca_table = face->table.loca.get_blob (); // Needs no destruct! | |
| 164 glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face); | |
| 165 #ifndef HB_NO_VAR | |
| 166 gvar = face->table.gvar; | |
| 167 #endif | |
| 168 hmtx = face->table.hmtx; | |
| 169 #ifndef HB_NO_VERTICAL | |
| 170 vmtx = face->table.vmtx; | |
| 171 #endif | |
| 172 | |
| 173 num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; | |
| 174 num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ()); | |
| 175 } | |
| 176 ~glyf_accelerator_t () | |
| 177 { | |
| 178 glyf_table.destroy (); | |
| 179 } | |
| 180 | |
| 181 bool has_data () const { return num_glyphs; } | |
| 182 | |
| 183 protected: | |
| 184 template<typename T> | |
| 185 bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const | |
| 186 { | |
| 187 if (gid >= num_glyphs) return false; | |
| 188 | |
| 189 /* Making this allocfree is not that easy | |
| 190 https://github.com/harfbuzz/harfbuzz/issues/2095 | |
| 191 mostly because of gvar handling in VF fonts, | |
| 192 perhaps a separate path for non-VF fonts can be considered */ | |
| 193 contour_point_vector_t all_points; | |
| 194 | |
| 195 bool phantom_only = !consumer.is_consuming_contour_points (); | |
| 196 if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, true, true, phantom_only))) | |
| 197 return false; | |
| 198 | |
| 199 if (consumer.is_consuming_contour_points ()) | |
| 200 { | |
| 201 unsigned count = all_points.length; | |
| 202 assert (count >= glyf_impl::PHANTOM_COUNT); | |
| 203 count -= glyf_impl::PHANTOM_COUNT; | |
| 204 for (unsigned point_index = 0; point_index < count; point_index++) | |
| 205 consumer.consume_point (all_points[point_index]); | |
| 206 consumer.points_end (); | |
| 207 } | |
| 208 | |
| 209 /* Where to write phantoms, nullptr if not requested */ | |
| 210 contour_point_t *phantoms = consumer.get_phantoms_sink (); | |
| 211 if (phantoms) | |
| 212 for (unsigned i = 0; i < glyf_impl::PHANTOM_COUNT; ++i) | |
| 213 phantoms[i] = all_points[all_points.length - glyf_impl::PHANTOM_COUNT + i]; | |
| 214 | |
| 215 return true; | |
| 216 } | |
| 217 | |
| 218 #ifndef HB_NO_VAR | |
| 219 struct points_aggregator_t | |
| 220 { | |
| 221 hb_font_t *font; | |
| 222 hb_glyph_extents_t *extents; | |
| 223 contour_point_t *phantoms; | |
| 224 bool scaled; | |
| 225 | |
| 226 struct contour_bounds_t | |
| 227 { | |
| 228 contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; } | |
| 229 | |
| 230 void add (const contour_point_t &p) | |
| 231 { | |
| 232 min_x = hb_min (min_x, p.x); | |
| 233 min_y = hb_min (min_y, p.y); | |
| 234 max_x = hb_max (max_x, p.x); | |
| 235 max_y = hb_max (max_y, p.y); | |
| 236 } | |
| 237 | |
| 238 bool empty () const { return (min_x >= max_x) || (min_y >= max_y); } | |
| 239 | |
| 240 void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scaled) | |
| 241 { | |
| 242 if (unlikely (empty ())) | |
| 243 { | |
| 244 extents->width = 0; | |
| 245 extents->x_bearing = 0; | |
| 246 extents->height = 0; | |
| 247 extents->y_bearing = 0; | |
| 248 return; | |
| 249 } | |
| 250 if (scaled) | |
| 251 { | |
| 252 extents->x_bearing = font->em_scalef_x (min_x); | |
| 253 extents->width = font->em_scalef_x (max_x) - extents->x_bearing; | |
| 254 extents->y_bearing = font->em_scalef_y (max_y); | |
| 255 extents->height = font->em_scalef_y (min_y) - extents->y_bearing; | |
| 256 } | |
| 257 else | |
| 258 { | |
| 259 extents->x_bearing = roundf (min_x); | |
| 260 extents->width = roundf (max_x - extents->x_bearing); | |
| 261 extents->y_bearing = roundf (max_y); | |
| 262 extents->height = roundf (min_y - extents->y_bearing); | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 protected: | |
| 267 float min_x, min_y, max_x, max_y; | |
| 268 } bounds; | |
| 269 | |
| 270 points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_, bool scaled_) | |
| 271 { | |
| 272 font = font_; | |
| 273 extents = extents_; | |
| 274 phantoms = phantoms_; | |
| 275 scaled = scaled_; | |
| 276 if (extents) bounds = contour_bounds_t (); | |
| 277 } | |
| 278 | |
| 279 void consume_point (const contour_point_t &point) { bounds.add (point); } | |
| 280 void points_end () { bounds.get_extents (font, extents, scaled); } | |
| 281 | |
| 282 bool is_consuming_contour_points () { return extents; } | |
| 283 contour_point_t *get_phantoms_sink () { return phantoms; } | |
| 284 }; | |
| 285 | |
| 286 public: | |
| 287 unsigned | |
| 288 get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const | |
| 289 { | |
| 290 if (unlikely (gid >= num_glyphs)) return 0; | |
| 291 | |
| 292 bool success = false; | |
| 293 | |
| 294 contour_point_t phantoms[glyf_impl::PHANTOM_COUNT]; | |
| 295 if (font->num_coords) | |
| 296 success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false)); | |
| 297 | |
| 298 if (unlikely (!success)) | |
| 299 return | |
| 300 #ifndef HB_NO_VERTICAL | |
| 301 is_vertical ? vmtx->get_advance_without_var_unscaled (gid) : | |
| 302 #endif | |
| 303 hmtx->get_advance_without_var_unscaled (gid); | |
| 304 | |
| 305 float result = is_vertical | |
| 306 ? phantoms[glyf_impl::PHANTOM_TOP].y - phantoms[glyf_impl::PHANTOM_BOTTOM].y | |
| 307 : phantoms[glyf_impl::PHANTOM_RIGHT].x - phantoms[glyf_impl::PHANTOM_LEFT].x; | |
| 308 return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2); | |
| 309 } | |
| 310 | |
| 311 bool get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical, int *lsb) const | |
| 312 { | |
| 313 if (unlikely (gid >= num_glyphs)) return false; | |
| 314 | |
| 315 hb_glyph_extents_t extents; | |
| 316 | |
| 317 contour_point_t phantoms[glyf_impl::PHANTOM_COUNT]; | |
| 318 if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms, false)))) | |
| 319 return false; | |
| 320 | |
| 321 *lsb = is_vertical | |
| 322 ? roundf (phantoms[glyf_impl::PHANTOM_TOP].y) - extents.y_bearing | |
| 323 : roundf (phantoms[glyf_impl::PHANTOM_LEFT].x); | |
| 324 return true; | |
| 325 } | |
| 326 #endif | |
| 327 | |
| 328 public: | |
| 329 bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const | |
| 330 { | |
| 331 if (unlikely (gid >= num_glyphs)) return false; | |
| 332 | |
| 333 #ifndef HB_NO_VAR | |
| 334 if (font->num_coords) | |
| 335 return get_points (font, gid, points_aggregator_t (font, extents, nullptr, true)); | |
| 336 #endif | |
| 337 return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents); | |
| 338 } | |
| 339 | |
| 340 const glyf_impl::Glyph | |
| 341 glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const | |
| 342 { | |
| 343 if (unlikely (gid >= num_glyphs)) return glyf_impl::Glyph (); | |
| 344 | |
| 345 unsigned int start_offset, end_offset; | |
| 346 | |
| 347 if (short_offset) | |
| 348 { | |
| 349 const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; | |
| 350 start_offset = 2 * offsets[gid]; | |
| 351 end_offset = 2 * offsets[gid + 1]; | |
| 352 } | |
| 353 else | |
| 354 { | |
| 355 const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; | |
| 356 start_offset = offsets[gid]; | |
| 357 end_offset = offsets[gid + 1]; | |
| 358 } | |
| 359 | |
| 360 if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ())) | |
| 361 return glyf_impl::Glyph (); | |
| 362 | |
| 363 glyf_impl::Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset, | |
| 364 end_offset - start_offset), gid); | |
| 365 return needs_padding_removal ? glyf_impl::Glyph (glyph.trim_padding (), gid) : glyph; | |
| 366 } | |
| 367 | |
| 368 bool | |
| 369 get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const | |
| 370 { return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session)); } | |
| 371 | |
| 372 #ifndef HB_NO_VAR | |
| 373 const gvar_accelerator_t *gvar; | |
| 374 #endif | |
| 375 const hmtx_accelerator_t *hmtx; | |
| 376 #ifndef HB_NO_VERTICAL | |
| 377 const vmtx_accelerator_t *vmtx; | |
| 378 #endif | |
| 379 | |
| 380 private: | |
| 381 bool short_offset; | |
| 382 unsigned int num_glyphs; | |
| 383 hb_blob_ptr_t<loca> loca_table; | |
| 384 hb_blob_ptr_t<glyf> glyf_table; | |
| 385 }; | |
| 386 | |
| 387 | |
| 388 inline void | |
| 389 glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, | |
| 390 hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const | |
| 391 { | |
| 392 OT::glyf_accelerator_t glyf (plan->source); | |
| 393 unsigned num_glyphs = plan->num_output_glyphs (); | |
| 394 if (!glyphs.resize (num_glyphs)) return; | |
| 395 | |
| 396 for (auto p : plan->glyph_map->iter ()) | |
| 397 { | |
| 398 unsigned new_gid = p.second; | |
| 399 glyf_impl::SubsetGlyph& subset_glyph = glyphs.arrayZ[new_gid]; | |
| 400 subset_glyph.old_gid = p.first; | |
| 401 | |
| 402 if (unlikely (new_gid == 0 && | |
| 403 !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) && | |
| 404 plan->pinned_at_default) | |
| 405 subset_glyph.source_glyph = glyf_impl::Glyph (); | |
| 406 else | |
| 407 { | |
| 408 /* If plan has an accelerator, the preprocessing step already trimmed glyphs. | |
| 409 * Don't trim them again! */ | |
| 410 subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, !plan->accelerator); | |
| 411 } | |
| 412 | |
| 413 if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) | |
| 414 subset_glyph.drop_hints_bytes (); | |
| 415 else | |
| 416 subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); | |
| 417 } | |
| 418 } | |
| 419 | |
| 420 inline hb_font_t * | |
| 421 glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const | |
| 422 { | |
| 423 hb_font_t *font = hb_font_create (plan->source); | |
| 424 if (unlikely (font == hb_font_get_empty ())) return nullptr; | |
| 425 | |
| 426 hb_vector_t<hb_variation_t> vars; | |
| 427 if (unlikely (!vars.alloc (plan->user_axes_location->get_population ()))) | |
| 428 return nullptr; | |
| 429 | |
| 430 for (auto _ : *plan->user_axes_location) | |
| 431 { | |
| 432 hb_variation_t var; | |
| 433 var.tag = _.first; | |
| 434 var.value = _.second; | |
| 435 vars.push (var); | |
| 436 } | |
| 437 | |
| 438 #ifndef HB_NO_VAR | |
| 439 hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ()); | |
| 440 #endif | |
| 441 return font; | |
| 442 } | |
| 443 | |
| 444 | |
| 445 } /* namespace OT */ | |
| 446 | |
| 447 | |
| 448 #endif /* OT_GLYF_GLYF_HH */ |
