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