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