Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/harfbuzz/src/hb-ot-hmtx-table.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 /* | |
| 2 * Copyright © 2011,2012 Google, Inc. | |
| 3 * | |
| 4 * This is part of HarfBuzz, a text shaping library. | |
| 5 * | |
| 6 * Permission is hereby granted, without written agreement and without | |
| 7 * license or royalty fees, to use, copy, modify, and distribute this | |
| 8 * software and its documentation for any purpose, provided that the | |
| 9 * above copyright notice and the following two paragraphs appear in | |
| 10 * all copies of this software. | |
| 11 * | |
| 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | |
| 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | |
| 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | |
| 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |
| 16 * DAMAGE. | |
| 17 * | |
| 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | |
| 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | |
| 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | |
| 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | |
| 23 * | |
| 24 * Google Author(s): Behdad Esfahbod, Roderick Sheeter | |
| 25 */ | |
| 26 | |
| 27 #ifndef HB_OT_HMTX_TABLE_HH | |
| 28 #define HB_OT_HMTX_TABLE_HH | |
| 29 | |
| 30 #include "hb-open-type.hh" | |
| 31 #include "hb-ot-maxp-table.hh" | |
| 32 #include "hb-ot-hhea-table.hh" | |
| 33 #include "hb-ot-var-hvar-table.hh" | |
| 34 #include "hb-ot-metrics.hh" | |
| 35 | |
| 36 /* | |
| 37 * hmtx -- Horizontal Metrics | |
| 38 * https://docs.microsoft.com/en-us/typography/opentype/spec/hmtx | |
| 39 * vmtx -- Vertical Metrics | |
| 40 * https://docs.microsoft.com/en-us/typography/opentype/spec/vmtx | |
| 41 */ | |
| 42 #define HB_OT_TAG_hmtx HB_TAG('h','m','t','x') | |
| 43 #define HB_OT_TAG_vmtx HB_TAG('v','m','t','x') | |
| 44 | |
| 45 | |
| 46 HB_INTERNAL bool | |
| 47 _glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical, int *lsb); | |
| 48 | |
| 49 HB_INTERNAL unsigned | |
| 50 _glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); | |
| 51 | |
| 52 | |
| 53 namespace OT { | |
| 54 | |
| 55 | |
| 56 struct LongMetric | |
| 57 { | |
| 58 UFWORD advance; /* Advance width/height. */ | |
| 59 FWORD sb; /* Leading (left/top) side bearing. */ | |
| 60 public: | |
| 61 DEFINE_SIZE_STATIC (4); | |
| 62 }; | |
| 63 | |
| 64 | |
| 65 template <typename T/*Data table type*/, typename H/*Header table type*/, typename V/*Var table type*/> | |
| 66 struct hmtxvmtx | |
| 67 { | |
| 68 bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const | |
| 69 { | |
| 70 TRACE_SANITIZE (this); | |
| 71 /* We don't check for anything specific here. The users of the | |
| 72 * struct do all the hard work... */ | |
| 73 return_trace (true); | |
| 74 } | |
| 75 | |
| 76 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>* get_mtx_map (const hb_subset_plan_t *plan) const | |
| 77 { return T::is_horizontal ? plan->hmtx_map : plan->vmtx_map; } | |
| 78 | |
| 79 bool subset_update_header (hb_subset_plan_t *plan, | |
| 80 unsigned int num_hmetrics) const | |
| 81 { | |
| 82 hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (plan->source, H::tableTag); | |
| 83 hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob); | |
| 84 hb_blob_destroy (src_blob); | |
| 85 | |
| 86 if (unlikely (!dest_blob)) { | |
| 87 return false; | |
| 88 } | |
| 89 | |
| 90 unsigned int length; | |
| 91 H *table = (H *) hb_blob_get_data (dest_blob, &length); | |
| 92 table->numberOfLongMetrics = num_hmetrics; | |
| 93 | |
| 94 bool result = plan->add_table (H::tableTag, dest_blob); | |
| 95 hb_blob_destroy (dest_blob); | |
| 96 | |
| 97 return result; | |
| 98 } | |
| 99 | |
| 100 template<typename Iterator, | |
| 101 hb_requires (hb_is_iterator (Iterator))> | |
| 102 void serialize (hb_serialize_context_t *c, | |
| 103 Iterator it, | |
| 104 unsigned num_long_metrics) | |
| 105 { | |
| 106 unsigned idx = 0; | |
| 107 for (auto _ : it) | |
| 108 { | |
| 109 if (idx < num_long_metrics) | |
| 110 { | |
| 111 LongMetric lm; | |
| 112 lm.advance = _.first; | |
| 113 lm.sb = _.second; | |
| 114 if (unlikely (!c->embed<LongMetric> (&lm))) return; | |
| 115 } | |
| 116 else | |
| 117 { | |
| 118 FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size); | |
| 119 if (unlikely (!sb)) return; | |
| 120 *sb = _.second; | |
| 121 } | |
| 122 idx++; | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 bool subset (hb_subset_context_t *c) const | |
| 127 { | |
| 128 TRACE_SUBSET (this); | |
| 129 | |
| 130 T *table_prime = c->serializer->start_embed <T> (); | |
| 131 if (unlikely (!table_prime)) return_trace (false); | |
| 132 | |
| 133 accelerator_t _mtx (c->plan->source); | |
| 134 unsigned num_long_metrics; | |
| 135 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *mtx_map = get_mtx_map (c->plan); | |
| 136 { | |
| 137 /* Determine num_long_metrics to encode. */ | |
| 138 auto& plan = c->plan; | |
| 139 | |
| 140 num_long_metrics = plan->num_output_glyphs (); | |
| 141 unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx); | |
| 142 while (num_long_metrics > 1 && | |
| 143 last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx)) | |
| 144 { | |
| 145 num_long_metrics--; | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 auto it = | |
| 150 + hb_range (c->plan->num_output_glyphs ()) | |
| 151 | hb_map ([c, &_mtx, mtx_map] (unsigned _) | |
| 152 { | |
| 153 if (!mtx_map->has (_)) | |
| 154 { | |
| 155 hb_codepoint_t old_gid; | |
| 156 if (!c->plan->old_gid_for_new_gid (_, &old_gid)) | |
| 157 return hb_pair (0u, 0); | |
| 158 int lsb = 0; | |
| 159 (void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb); | |
| 160 return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb); | |
| 161 } | |
| 162 return mtx_map->get (_); | |
| 163 }) | |
| 164 ; | |
| 165 | |
| 166 table_prime->serialize (c->serializer, it, num_long_metrics); | |
| 167 | |
| 168 if (unlikely (c->serializer->in_error ())) | |
| 169 return_trace (false); | |
| 170 | |
| 171 // Amend header num hmetrics | |
| 172 if (unlikely (!subset_update_header (c->plan, num_long_metrics))) | |
| 173 return_trace (false); | |
| 174 | |
| 175 return_trace (true); | |
| 176 } | |
| 177 | |
| 178 struct accelerator_t | |
| 179 { | |
| 180 friend struct hmtxvmtx; | |
| 181 | |
| 182 accelerator_t (hb_face_t *face) | |
| 183 { | |
| 184 table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag); | |
| 185 var_table = hb_sanitize_context_t ().reference_table<V> (face, T::variationsTag); | |
| 186 | |
| 187 default_advance = T::is_horizontal ? hb_face_get_upem (face) / 2 : hb_face_get_upem (face); | |
| 188 | |
| 189 /* Populate count variables and sort them out as we go */ | |
| 190 | |
| 191 unsigned int len = table.get_length (); | |
| 192 if (len & 1) | |
| 193 len--; | |
| 194 | |
| 195 num_long_metrics = T::is_horizontal ? | |
| 196 face->table.hhea->numberOfLongMetrics : | |
| 197 #ifndef HB_NO_VERTICAL | |
| 198 face->table.vhea->numberOfLongMetrics | |
| 199 #else | |
| 200 0 | |
| 201 #endif | |
| 202 ; | |
| 203 if (unlikely (num_long_metrics * 4 > len)) | |
| 204 num_long_metrics = len / 4; | |
| 205 len -= num_long_metrics * 4; | |
| 206 | |
| 207 num_bearings = face->table.maxp->get_num_glyphs (); | |
| 208 | |
| 209 if (unlikely (num_bearings < num_long_metrics)) | |
| 210 num_bearings = num_long_metrics; | |
| 211 if (unlikely ((num_bearings - num_long_metrics) * 2 > len)) | |
| 212 num_bearings = num_long_metrics + len / 2; | |
| 213 len -= (num_bearings - num_long_metrics) * 2; | |
| 214 | |
| 215 /* We MUST set num_bearings to zero if num_long_metrics is zero. | |
| 216 * Our get_advance() depends on that. */ | |
| 217 if (unlikely (!num_long_metrics)) | |
| 218 num_bearings = num_long_metrics = 0; | |
| 219 | |
| 220 num_advances = num_bearings + len / 2; | |
| 221 num_glyphs = face->get_num_glyphs (); | |
| 222 if (num_glyphs < num_advances) | |
| 223 num_glyphs = num_advances; | |
| 224 } | |
| 225 ~accelerator_t () | |
| 226 { | |
| 227 table.destroy (); | |
| 228 var_table.destroy (); | |
| 229 } | |
| 230 | |
| 231 bool has_data () const { return (bool) num_bearings; } | |
| 232 | |
| 233 bool get_leading_bearing_without_var_unscaled (hb_codepoint_t glyph, | |
| 234 int *lsb) const | |
| 235 { | |
| 236 if (glyph < num_long_metrics) | |
| 237 { | |
| 238 *lsb = table->longMetricZ[glyph].sb; | |
| 239 return true; | |
| 240 } | |
| 241 | |
| 242 if (unlikely (glyph >= num_bearings)) | |
| 243 return false; | |
| 244 | |
| 245 const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics]; | |
| 246 *lsb = bearings[glyph - num_long_metrics]; | |
| 247 return true; | |
| 248 } | |
| 249 | |
| 250 bool get_leading_bearing_with_var_unscaled (hb_font_t *font, | |
| 251 hb_codepoint_t glyph, | |
| 252 int *lsb) const | |
| 253 { | |
| 254 if (!font->num_coords) | |
| 255 return get_leading_bearing_without_var_unscaled (glyph, lsb); | |
| 256 | |
| 257 #ifndef HB_NO_VAR | |
| 258 float delta; | |
| 259 if (var_table->get_lsb_delta_unscaled (glyph, font->coords, font->num_coords, &delta) && | |
| 260 get_leading_bearing_without_var_unscaled (glyph, lsb)) | |
| 261 { | |
| 262 *lsb += roundf (delta); | |
| 263 return true; | |
| 264 } | |
| 265 | |
| 266 return _glyf_get_leading_bearing_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx, lsb); | |
| 267 #else | |
| 268 return false; | |
| 269 #endif | |
| 270 } | |
| 271 | |
| 272 unsigned int get_advance_without_var_unscaled (hb_codepoint_t glyph) const | |
| 273 { | |
| 274 /* OpenType case. */ | |
| 275 if (glyph < num_bearings) | |
| 276 return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance; | |
| 277 | |
| 278 /* If num_advances is zero, it means we don't have the metrics table | |
| 279 * for this direction: return default advance. Otherwise, there's a | |
| 280 * well-defined answer. */ | |
| 281 if (unlikely (!num_advances)) | |
| 282 return default_advance; | |
| 283 | |
| 284 #ifdef HB_NO_BEYOND_64K | |
| 285 return 0; | |
| 286 #endif | |
| 287 | |
| 288 if (unlikely (glyph >= num_glyphs)) | |
| 289 return 0; | |
| 290 | |
| 291 /* num_bearings <= glyph < num_glyphs; | |
| 292 * num_bearings <= num_advances */ | |
| 293 | |
| 294 /* TODO Optimize */ | |
| 295 | |
| 296 if (num_bearings == num_advances) | |
| 297 return get_advance_without_var_unscaled (num_bearings - 1); | |
| 298 | |
| 299 const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics]; | |
| 300 const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics]; | |
| 301 | |
| 302 return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)]; | |
| 303 } | |
| 304 | |
| 305 unsigned get_advance_with_var_unscaled (hb_codepoint_t glyph, | |
| 306 hb_font_t *font, | |
| 307 VariationStore::cache_t *store_cache = nullptr) const | |
| 308 { | |
| 309 unsigned int advance = get_advance_without_var_unscaled (glyph); | |
| 310 | |
| 311 #ifndef HB_NO_VAR | |
| 312 if (unlikely (glyph >= num_bearings) || !font->num_coords) | |
| 313 return advance; | |
| 314 | |
| 315 if (var_table.get_length ()) | |
| 316 return advance + roundf (var_table->get_advance_delta_unscaled (glyph, | |
| 317 font->coords, font->num_coords, | |
| 318 store_cache)); // TODO Optimize?! | |
| 319 | |
| 320 return _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx); | |
| 321 #else | |
| 322 return advance; | |
| 323 #endif | |
| 324 } | |
| 325 | |
| 326 protected: | |
| 327 // 0 <= num_long_metrics <= num_bearings <= num_advances <= num_glyphs | |
| 328 unsigned num_long_metrics; | |
| 329 unsigned num_bearings; | |
| 330 unsigned num_advances; | |
| 331 unsigned num_glyphs; | |
| 332 | |
| 333 unsigned int default_advance; | |
| 334 | |
| 335 public: | |
| 336 hb_blob_ptr_t<hmtxvmtx> table; | |
| 337 hb_blob_ptr_t<V> var_table; | |
| 338 }; | |
| 339 | |
| 340 /* get advance: when no variations, call get_advance_without_var_unscaled. | |
| 341 * when there're variations, get advance value from mtx_map in subset_plan*/ | |
| 342 unsigned get_new_gid_advance_unscaled (const hb_subset_plan_t *plan, | |
| 343 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *mtx_map, | |
| 344 unsigned new_gid, | |
| 345 const accelerator_t &_mtx) const | |
| 346 { | |
| 347 if (mtx_map->is_empty () || | |
| 348 (new_gid == 0 && !mtx_map->has (new_gid))) | |
| 349 { | |
| 350 hb_codepoint_t old_gid = 0; | |
| 351 return plan->old_gid_for_new_gid (new_gid, &old_gid) ? | |
| 352 _mtx.get_advance_without_var_unscaled (old_gid) : 0; | |
| 353 } | |
| 354 else | |
| 355 { return mtx_map->get (new_gid).first; } | |
| 356 } | |
| 357 | |
| 358 protected: | |
| 359 UnsizedArrayOf<LongMetric> | |
| 360 longMetricZ; /* Paired advance width and leading | |
| 361 * bearing values for each glyph. The | |
| 362 * value numOfHMetrics comes from | |
| 363 * the 'hhea' table. If the font is | |
| 364 * monospaced, only one entry need | |
| 365 * be in the array, but that entry is | |
| 366 * required. The last entry applies to | |
| 367 * all subsequent glyphs. */ | |
| 368 /*UnsizedArrayOf<FWORD> leadingBearingX;*/ | |
| 369 /* Here the advance is assumed | |
| 370 * to be the same as the advance | |
| 371 * for the last entry above. The | |
| 372 * number of entries in this array is | |
| 373 * derived from numGlyphs (from 'maxp' | |
| 374 * table) minus numberOfLongMetrics. | |
| 375 * This generally is used with a run | |
| 376 * of monospaced glyphs (e.g., Kanji | |
| 377 * fonts or Courier fonts). Only one | |
| 378 * run is allowed and it must be at | |
| 379 * the end. This allows a monospaced | |
| 380 * font to vary the side bearing | |
| 381 * values for each glyph. */ | |
| 382 /*UnsizedArrayOf<UFWORD>advancesX;*/ | |
| 383 /* TODO Document. */ | |
| 384 public: | |
| 385 DEFINE_SIZE_ARRAY (0, longMetricZ); | |
| 386 }; | |
| 387 | |
| 388 struct hmtx : hmtxvmtx<hmtx, hhea, HVAR> { | |
| 389 static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx; | |
| 390 static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR; | |
| 391 static constexpr bool is_horizontal = true; | |
| 392 }; | |
| 393 struct vmtx : hmtxvmtx<vmtx, vhea, VVAR> { | |
| 394 static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx; | |
| 395 static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR; | |
| 396 static constexpr bool is_horizontal = false; | |
| 397 }; | |
| 398 | |
| 399 struct hmtx_accelerator_t : hmtx::accelerator_t { | |
| 400 hmtx_accelerator_t (hb_face_t *face) : hmtx::accelerator_t (face) {} | |
| 401 }; | |
| 402 struct vmtx_accelerator_t : vmtx::accelerator_t { | |
| 403 vmtx_accelerator_t (hb_face_t *face) : vmtx::accelerator_t (face) {} | |
| 404 }; | |
| 405 | |
| 406 } /* namespace OT */ | |
| 407 | |
| 408 | |
| 409 #endif /* HB_OT_HMTX_TABLE_HH */ |
