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-os2-table.hh" 34 #include "hb-ot-var-hvar-table.hh" 35 #include "hb-ot-var-mvar-table.hh" 36 #include "hb-ot-metrics.hh" 37 38 /* 39 * hmtx -- Horizontal Metrics 40 * https://docs.microsoft.com/en-us/typography/opentype/spec/hmtx 41 * vmtx -- Vertical Metrics 42 * https://docs.microsoft.com/en-us/typography/opentype/spec/vmtx 43 */ 44 #define HB_OT_TAG_hmtx HB_TAG('h','m','t','x') 45 #define HB_OT_TAG_vmtx HB_TAG('v','m','t','x') 46 47 48 HB_INTERNAL bool 49 _glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical, int *lsb); 50 51 HB_INTERNAL unsigned 52 _glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); 53 54 HB_INTERNAL bool 55 _glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb); 56 57 58 namespace OT { 59 60 61 struct LongMetric 62 { 63 UFWORD advance; /* Advance width/height. */ 64 FWORD sb; /* Leading (left/top) side bearing. */ 65 public: 66 DEFINE_SIZE_STATIC (4); 67 }; 68 69 70 template <typename T/*Data table type*/, typename H/*Header table type*/, typename V/*Var table type*/> 71 struct hmtxvmtx 72 { sanitizeOT::hmtxvmtx73 bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const 74 { 75 TRACE_SANITIZE (this); 76 /* We don't check for anything specific here. The users of the 77 * struct do all the hard work... */ 78 return_trace (true); 79 } 80 get_mtx_mapOT::hmtxvmtx81 const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>>* get_mtx_map (const hb_subset_plan_t *plan) const 82 { return T::is_horizontal ? &plan->hmtx_map : &plan->vmtx_map; } 83 subset_update_headerOT::hmtxvmtx84 bool subset_update_header (hb_subset_context_t *c, 85 unsigned int num_hmetrics, 86 const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> *mtx_map, 87 const hb_vector_t<unsigned> &bounds_vec) const 88 { 89 hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (c->plan->source, H::tableTag); 90 hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob); 91 hb_blob_destroy (src_blob); 92 93 if (unlikely (!dest_blob)) { 94 return false; 95 } 96 97 unsigned int length; 98 H *table = (H *) hb_blob_get_data (dest_blob, &length); 99 c->serializer->check_assign (table->numberOfLongMetrics, num_hmetrics, HB_SERIALIZE_ERROR_INT_OVERFLOW); 100 101 #ifndef HB_NO_VAR 102 if (c->plan->normalized_coords) 103 { 104 auto &MVAR = *c->plan->source->table.MVAR; 105 if (T::is_horizontal) 106 { 107 HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE, caretSlopeRise); 108 HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN, caretSlopeRun); 109 HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET, caretOffset); 110 } 111 else 112 { 113 HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_RISE, caretSlopeRise); 114 HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_RUN, caretSlopeRun); 115 HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET, caretOffset); 116 } 117 118 bool empty = true; 119 int min_lsb = 0x7FFF; 120 int min_rsb = 0x7FFF; 121 int max_extent = -0x7FFF; 122 unsigned max_adv = 0; 123 for (const auto _ : *mtx_map) 124 { 125 hb_codepoint_t gid = _.first; 126 unsigned adv = _.second.first; 127 int lsb = _.second.second; 128 max_adv = hb_max (max_adv, adv); 129 130 if (bounds_vec[gid] != 0xFFFFFFFF) 131 { 132 empty = false; 133 unsigned bound_width = bounds_vec[gid]; 134 int rsb = adv - lsb - bound_width; 135 int extent = lsb + bound_width; 136 min_lsb = hb_min (min_lsb, lsb); 137 min_rsb = hb_min (min_rsb, rsb); 138 max_extent = hb_max (max_extent, extent); 139 } 140 } 141 142 table->advanceMax = max_adv; 143 if (!empty) 144 { 145 table->minLeadingBearing = min_lsb; 146 table->minTrailingBearing = min_rsb; 147 table->maxExtent = max_extent; 148 } 149 150 if (T::is_horizontal) 151 { 152 const auto &OS2 = *c->plan->source->table.OS2; 153 if (OS2.has_data () && 154 table->ascender == OS2.sTypoAscender && 155 table->descender == OS2.sTypoDescender && 156 table->lineGap == OS2.sTypoLineGap) 157 { 158 table->ascender = static_cast<int> (roundf (OS2.sTypoAscender + 159 MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, 160 c->plan->normalized_coords.arrayZ, 161 c->plan->normalized_coords.length))); 162 table->descender = static_cast<int> (roundf (OS2.sTypoDescender + 163 MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, 164 c->plan->normalized_coords.arrayZ, 165 c->plan->normalized_coords.length))); 166 table->lineGap = static_cast<int> (roundf (OS2.sTypoLineGap + 167 MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, 168 c->plan->normalized_coords.arrayZ, 169 c->plan->normalized_coords.length))); 170 } 171 } 172 } 173 #endif 174 175 bool result = c->plan->add_table (H::tableTag, dest_blob); 176 hb_blob_destroy (dest_blob); 177 178 return result; 179 } 180 181 template<typename Iterator, 182 hb_requires (hb_is_iterator (Iterator))> serializeOT::hmtxvmtx183 void serialize (hb_serialize_context_t *c, 184 Iterator it, 185 const hb_vector_t<hb_codepoint_pair_t> new_to_old_gid_list, 186 unsigned num_long_metrics, 187 unsigned total_num_metrics) 188 { 189 LongMetric* long_metrics = c->allocate_size<LongMetric> (num_long_metrics * LongMetric::static_size); 190 FWORD* short_metrics = c->allocate_size<FWORD> ((total_num_metrics - num_long_metrics) * FWORD::static_size); 191 if (!long_metrics || !short_metrics) return; 192 193 short_metrics -= num_long_metrics; 194 195 for (auto _ : new_to_old_gid_list) 196 { 197 hb_codepoint_t gid = _.first; 198 auto mtx = *it++; 199 200 if (gid < num_long_metrics) 201 { 202 LongMetric& lm = long_metrics[gid]; 203 lm.advance = mtx.first; 204 lm.sb = mtx.second; 205 } 206 // TODO(beyond-64k): This assumes that maxp.numGlyphs is 0xFFFF. 207 else if (gid < 0x10000u) 208 short_metrics[gid] = mtx.second; 209 else 210 ((UFWORD*) short_metrics)[gid] = mtx.first; 211 } 212 } 213 subsetOT::hmtxvmtx214 bool subset (hb_subset_context_t *c) const 215 { 216 TRACE_SUBSET (this); 217 218 auto *table_prime = c->serializer->start_embed <T> (); 219 220 accelerator_t _mtx (c->plan->source); 221 unsigned num_long_metrics; 222 const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> *mtx_map = get_mtx_map (c->plan); 223 { 224 /* Determine num_long_metrics to encode. */ 225 auto& plan = c->plan; 226 227 // TODO Don't consider retaingid holes here. 228 229 num_long_metrics = hb_min (plan->num_output_glyphs (), 0xFFFFu); 230 unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx); 231 while (num_long_metrics > 1 && 232 last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx)) 233 { 234 num_long_metrics--; 235 } 236 } 237 238 auto it = 239 + hb_iter (c->plan->new_to_old_gid_list) 240 | hb_map ([c, &_mtx, mtx_map] (hb_codepoint_pair_t _) 241 { 242 hb_codepoint_t new_gid = _.first; 243 hb_codepoint_t old_gid = _.second; 244 245 hb_pair_t<unsigned, int> *v = nullptr; 246 if (!mtx_map->has (new_gid, &v)) 247 { 248 int lsb = 0; 249 if (!_mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb)) 250 (void) _glyf_get_leading_bearing_without_var_unscaled (c->plan->source, old_gid, !T::is_horizontal, &lsb); 251 return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb); 252 } 253 return *v; 254 }) 255 ; 256 257 table_prime->serialize (c->serializer, 258 it, 259 c->plan->new_to_old_gid_list, 260 num_long_metrics, 261 c->plan->num_output_glyphs ()); 262 263 if (unlikely (c->serializer->in_error ())) 264 return_trace (false); 265 266 // Amend header num hmetrics 267 if (unlikely (!subset_update_header (c, num_long_metrics, mtx_map, 268 T::is_horizontal ? c->plan->bounds_width_vec : c->plan->bounds_height_vec))) 269 return_trace (false); 270 271 return_trace (true); 272 } 273 274 struct accelerator_t 275 { 276 friend struct hmtxvmtx; 277 accelerator_tOT::hmtxvmtx::accelerator_t278 accelerator_t (hb_face_t *face) 279 { 280 table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag); 281 var_table = hb_sanitize_context_t ().reference_table<V> (face, T::variationsTag); 282 283 default_advance = T::is_horizontal ? hb_face_get_upem (face) / 2 : hb_face_get_upem (face); 284 285 /* Populate count variables and sort them out as we go */ 286 287 unsigned int len = table.get_length (); 288 if (len & 1) 289 len--; 290 291 num_long_metrics = T::is_horizontal ? 292 face->table.hhea->numberOfLongMetrics : 293 #ifndef HB_NO_VERTICAL 294 face->table.vhea->numberOfLongMetrics 295 #else 296 0 297 #endif 298 ; 299 if (unlikely (num_long_metrics * 4 > len)) 300 num_long_metrics = len / 4; 301 len -= num_long_metrics * 4; 302 303 num_bearings = face->table.maxp->get_num_glyphs (); 304 305 if (unlikely (num_bearings < num_long_metrics)) 306 num_bearings = num_long_metrics; 307 if (unlikely ((num_bearings - num_long_metrics) * 2 > len)) 308 num_bearings = num_long_metrics + len / 2; 309 len -= (num_bearings - num_long_metrics) * 2; 310 311 /* We MUST set num_bearings to zero if num_long_metrics is zero. 312 * Our get_advance() depends on that. */ 313 if (unlikely (!num_long_metrics)) 314 num_bearings = num_long_metrics = 0; 315 316 num_advances = num_bearings + len / 2; 317 num_glyphs = face->get_num_glyphs (); 318 if (num_glyphs < num_advances) 319 num_glyphs = num_advances; 320 } ~accelerator_tOT::hmtxvmtx::accelerator_t321 ~accelerator_t () 322 { 323 table.destroy (); 324 var_table.destroy (); 325 } 326 has_dataOT::hmtxvmtx::accelerator_t327 bool has_data () const { return (bool) num_bearings; } 328 get_leading_bearing_without_var_unscaledOT::hmtxvmtx::accelerator_t329 bool get_leading_bearing_without_var_unscaled (hb_codepoint_t glyph, 330 int *lsb) const 331 { 332 if (glyph < num_long_metrics) 333 { 334 *lsb = table->longMetricZ[glyph].sb; 335 return true; 336 } 337 338 if (unlikely (glyph >= num_bearings)) 339 return false; 340 341 const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics]; 342 *lsb = bearings[glyph - num_long_metrics]; 343 return true; 344 } 345 get_leading_bearing_with_var_unscaledOT::hmtxvmtx::accelerator_t346 bool get_leading_bearing_with_var_unscaled (hb_font_t *font, 347 hb_codepoint_t glyph, 348 int *lsb) const 349 { 350 if (!font->num_coords) 351 return get_leading_bearing_without_var_unscaled (glyph, lsb); 352 353 #ifndef HB_NO_VAR 354 float delta; 355 if (var_table->get_lsb_delta_unscaled (glyph, font->coords, font->num_coords, &delta) && 356 get_leading_bearing_without_var_unscaled (glyph, lsb)) 357 { 358 *lsb += roundf (delta); 359 return true; 360 } 361 362 return _glyf_get_leading_bearing_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx, lsb); 363 #else 364 return false; 365 #endif 366 } 367 get_advance_without_var_unscaledOT::hmtxvmtx::accelerator_t368 unsigned int get_advance_without_var_unscaled (hb_codepoint_t glyph) const 369 { 370 /* OpenType case. */ 371 if (glyph < num_bearings) 372 return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance; 373 374 /* If num_advances is zero, it means we don't have the metrics table 375 * for this direction: return default advance. Otherwise, there's a 376 * well-defined answer. */ 377 if (unlikely (!num_advances)) 378 return default_advance; 379 380 #ifdef HB_NO_BEYOND_64K 381 return 0; 382 #endif 383 384 if (unlikely (glyph >= num_glyphs)) 385 return 0; 386 387 /* num_bearings <= glyph < num_glyphs; 388 * num_bearings <= num_advances */ 389 390 if (num_bearings == num_advances) 391 return get_advance_without_var_unscaled (num_bearings - 1); 392 393 const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics]; 394 const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics]; 395 396 return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)]; 397 } 398 get_advance_with_var_unscaledOT::hmtxvmtx::accelerator_t399 unsigned get_advance_with_var_unscaled (hb_codepoint_t glyph, 400 hb_font_t *font, 401 ItemVariationStore::cache_t *store_cache = nullptr) const 402 { 403 unsigned int advance = get_advance_without_var_unscaled (glyph); 404 405 #ifndef HB_NO_VAR 406 if (unlikely (glyph >= num_bearings) || !font->num_coords) 407 return advance; 408 409 if (var_table.get_length ()) 410 return advance + roundf (var_table->get_advance_delta_unscaled (glyph, 411 font->coords, font->num_coords, 412 store_cache)); 413 414 unsigned glyf_advance = _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx); 415 return glyf_advance ? glyf_advance : advance; 416 #else 417 return advance; 418 #endif 419 } 420 421 protected: 422 // 0 <= num_long_metrics <= num_bearings <= num_advances <= num_glyphs 423 unsigned num_long_metrics; 424 unsigned num_bearings; 425 unsigned num_advances; 426 unsigned num_glyphs; 427 428 unsigned int default_advance; 429 430 public: 431 hb_blob_ptr_t<hmtxvmtx> table; 432 hb_blob_ptr_t<V> var_table; 433 }; 434 435 /* get advance: when no variations, call get_advance_without_var_unscaled. 436 * when there're variations, get advance value from mtx_map in subset_plan*/ get_new_gid_advance_unscaledOT::hmtxvmtx437 unsigned get_new_gid_advance_unscaled (const hb_subset_plan_t *plan, 438 const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> *mtx_map, 439 unsigned new_gid, 440 const accelerator_t &_mtx) const 441 { 442 if (mtx_map->is_empty ()) 443 { 444 hb_codepoint_t old_gid = 0; 445 return plan->old_gid_for_new_gid (new_gid, &old_gid) ? 446 _mtx.get_advance_without_var_unscaled (old_gid) : 0; 447 } 448 return mtx_map->get (new_gid).first; 449 } 450 451 protected: 452 UnsizedArrayOf<LongMetric> 453 longMetricZ; /* Paired advance width and leading 454 * bearing values for each glyph. The 455 * value numOfHMetrics comes from 456 * the 'hhea' table. If the font is 457 * monospaced, only one entry need 458 * be in the array, but that entry is 459 * required. The last entry applies to 460 * all subsequent glyphs. */ 461 /*UnsizedArrayOf<FWORD> leadingBearingX;*/ 462 /* Here the advance is assumed 463 * to be the same as the advance 464 * for the last entry above. The 465 * number of entries in this array is 466 * derived from numGlyphs (from 'maxp' 467 * table) minus numberOfLongMetrics. 468 * This generally is used with a run 469 * of monospaced glyphs (e.g., Kanji 470 * fonts or Courier fonts). Only one 471 * run is allowed and it must be at 472 * the end. This allows a monospaced 473 * font to vary the side bearing 474 * values for each glyph. */ 475 /*UnsizedArrayOf<UFWORD>advancesX;*/ 476 /* TODO Document. */ 477 public: 478 DEFINE_SIZE_ARRAY (0, longMetricZ); 479 }; 480 481 struct hmtx : hmtxvmtx<hmtx, hhea, HVAR> { 482 static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx; 483 static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR; 484 static constexpr bool is_horizontal = true; 485 }; 486 struct vmtx : hmtxvmtx<vmtx, vhea, VVAR> { 487 static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx; 488 static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR; 489 static constexpr bool is_horizontal = false; 490 }; 491 492 struct hmtx_accelerator_t : hmtx::accelerator_t { hmtx_accelerator_tOT::hmtx_accelerator_t493 hmtx_accelerator_t (hb_face_t *face) : hmtx::accelerator_t (face) {} 494 }; 495 struct vmtx_accelerator_t : vmtx::accelerator_t { vmtx_accelerator_tOT::vmtx_accelerator_t496 vmtx_accelerator_t (hb_face_t *face) : vmtx::accelerator_t (face) {} 497 }; 498 499 } /* namespace OT */ 500 501 502 #endif /* HB_OT_HMTX_TABLE_HH */ 503