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-hhea-table.hh" 32 #include "hb-ot-var-hvar-table.hh" 33 #include "hb-ot-metrics.hh" 34 35 /* 36 * hmtx -- Horizontal Metrics 37 * https://docs.microsoft.com/en-us/typography/opentype/spec/hmtx 38 * vmtx -- Vertical Metrics 39 * https://docs.microsoft.com/en-us/typography/opentype/spec/vmtx 40 */ 41 #define HB_OT_TAG_hmtx HB_TAG('h','m','t','x') 42 #define HB_OT_TAG_vmtx HB_TAG('v','m','t','x') 43 44 45 HB_INTERNAL int 46 _glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); 47 48 HB_INTERNAL unsigned 49 _glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); 50 51 52 namespace OT { 53 54 55 struct LongMetric 56 { 57 UFWORD advance; /* Advance width/height. */ 58 FWORD sb; /* Leading (left/top) side bearing. */ 59 public: 60 DEFINE_SIZE_STATIC (4); 61 }; 62 63 64 template <typename T, typename H> 65 struct hmtxvmtx 66 { sanitizeOT::hmtxvmtx67 bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const 68 { 69 TRACE_SANITIZE (this); 70 /* We don't check for anything specific here. The users of the 71 * struct do all the hard work... */ 72 return_trace (true); 73 } 74 75 subset_update_headerOT::hmtxvmtx76 bool subset_update_header (hb_subset_plan_t *plan, 77 unsigned int num_hmetrics) const 78 { 79 hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (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 table->numberOfLongMetrics = num_hmetrics; 90 91 bool result = plan->add_table (H::tableTag, dest_blob); 92 hb_blob_destroy (dest_blob); 93 94 return result; 95 } 96 97 template<typename Iterator, 98 hb_requires (hb_is_iterator (Iterator))> serializeOT::hmtxvmtx99 void serialize (hb_serialize_context_t *c, 100 Iterator it, 101 unsigned num_advances) 102 { 103 unsigned idx = 0; 104 + it 105 | hb_apply ([c, &idx, num_advances] (const hb_item_type<Iterator>& _) 106 { 107 if (idx < num_advances) 108 { 109 LongMetric lm; 110 lm.advance = _.first; 111 lm.sb = _.second; 112 if (unlikely (!c->embed<LongMetric> (&lm))) return; 113 } 114 else 115 { 116 FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size); 117 if (unlikely (!sb)) return; 118 *sb = _.second; 119 } 120 idx++; 121 }) 122 ; 123 } 124 subsetOT::hmtxvmtx125 bool subset (hb_subset_context_t *c) const 126 { 127 TRACE_SUBSET (this); 128 129 T *table_prime = c->serializer->start_embed <T> (); 130 if (unlikely (!table_prime)) return_trace (false); 131 132 accelerator_t _mtx; 133 _mtx.init (c->plan->source); 134 unsigned num_advances = _mtx.num_advances_for_subset (c->plan); 135 136 auto it = 137 + hb_range (c->plan->num_output_glyphs ()) 138 | hb_map ([c, &_mtx] (unsigned _) 139 { 140 hb_codepoint_t old_gid; 141 if (!c->plan->old_gid_for_new_gid (_, &old_gid)) 142 return hb_pair (0u, 0); 143 return hb_pair (_mtx.get_advance (old_gid), _mtx.get_side_bearing (old_gid)); 144 }) 145 ; 146 147 table_prime->serialize (c->serializer, it, num_advances); 148 149 _mtx.fini (); 150 151 if (unlikely (c->serializer->ran_out_of_room || c->serializer->in_error ())) 152 return_trace (false); 153 154 // Amend header num hmetrics 155 if (unlikely (!subset_update_header (c->plan, num_advances))) 156 return_trace (false); 157 158 return_trace (true); 159 } 160 161 struct accelerator_t 162 { 163 friend struct hmtxvmtx; 164 initOT::hmtxvmtx::accelerator_t165 void init (hb_face_t *face, 166 unsigned int default_advance_ = 0) 167 { 168 default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face); 169 170 num_advances = T::is_horizontal ? face->table.hhea->numberOfLongMetrics : face->table.vhea->numberOfLongMetrics; 171 172 table = hb_sanitize_context_t().reference_table<hmtxvmtx> (face, T::tableTag); 173 174 /* Cap num_metrics() and num_advances() based on table length. */ 175 unsigned int len = table.get_length (); 176 if (unlikely (num_advances * 4 > len)) 177 num_advances = len / 4; 178 num_metrics = num_advances + (len - 4 * num_advances) / 2; 179 180 /* We MUST set num_metrics to zero if num_advances is zero. 181 * Our get_advance() depends on that. */ 182 if (unlikely (!num_advances)) 183 { 184 num_metrics = num_advances = 0; 185 table.destroy (); 186 table = hb_blob_get_empty (); 187 } 188 189 var_table = hb_sanitize_context_t().reference_table<HVARVVAR> (face, T::variationsTag); 190 } 191 finiOT::hmtxvmtx::accelerator_t192 void fini () 193 { 194 table.destroy (); 195 var_table.destroy (); 196 } 197 get_side_bearingOT::hmtxvmtx::accelerator_t198 int get_side_bearing (hb_codepoint_t glyph) const 199 { 200 if (glyph < num_advances) 201 return table->longMetricZ[glyph].sb; 202 203 if (unlikely (glyph >= num_metrics)) 204 return 0; 205 206 const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances]; 207 return bearings[glyph - num_advances]; 208 } 209 get_side_bearingOT::hmtxvmtx::accelerator_t210 int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const 211 { 212 int side_bearing = get_side_bearing (glyph); 213 214 #ifndef HB_NO_VAR 215 if (unlikely (glyph >= num_metrics) || !font->num_coords) 216 return side_bearing; 217 218 if (var_table.get_length ()) 219 return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?! 220 221 return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); 222 #else 223 return side_bearing; 224 #endif 225 } 226 get_advanceOT::hmtxvmtx::accelerator_t227 unsigned int get_advance (hb_codepoint_t glyph) const 228 { 229 if (unlikely (glyph >= num_metrics)) 230 { 231 /* If num_metrics is zero, it means we don't have the metrics table 232 * for this direction: return default advance. Otherwise, it means that the 233 * glyph index is out of bound: return zero. */ 234 if (num_metrics) 235 return 0; 236 else 237 return default_advance; 238 } 239 240 return table->longMetricZ[hb_min (glyph, (uint32_t) num_advances - 1)].advance; 241 } 242 get_advanceOT::hmtxvmtx::accelerator_t243 unsigned int get_advance (hb_codepoint_t glyph, 244 hb_font_t *font) const 245 { 246 unsigned int advance = get_advance (glyph); 247 248 #ifndef HB_NO_VAR 249 if (unlikely (glyph >= num_metrics) || !font->num_coords) 250 return advance; 251 252 if (var_table.get_length ()) 253 return advance + roundf (var_table->get_advance_var (font, glyph)); // TODO Optimize?! 254 255 return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); 256 #else 257 return advance; 258 #endif 259 } 260 num_advances_for_subsetOT::hmtxvmtx::accelerator_t261 unsigned int num_advances_for_subset (const hb_subset_plan_t *plan) const 262 { 263 unsigned int num_advances = plan->num_output_glyphs (); 264 unsigned int last_advance = _advance_for_new_gid (plan, 265 num_advances - 1); 266 while (num_advances > 1 && 267 last_advance == _advance_for_new_gid (plan, 268 num_advances - 2)) 269 { 270 num_advances--; 271 } 272 273 return num_advances; 274 } 275 276 private: _advance_for_new_gidOT::hmtxvmtx::accelerator_t277 unsigned int _advance_for_new_gid (const hb_subset_plan_t *plan, 278 hb_codepoint_t new_gid) const 279 { 280 hb_codepoint_t old_gid; 281 if (!plan->old_gid_for_new_gid (new_gid, &old_gid)) 282 return 0; 283 284 return get_advance (old_gid); 285 } 286 287 protected: 288 unsigned int num_metrics; 289 unsigned int num_advances; 290 unsigned int default_advance; 291 292 private: 293 hb_blob_ptr_t<hmtxvmtx> table; 294 hb_blob_ptr_t<HVARVVAR> var_table; 295 }; 296 297 protected: 298 UnsizedArrayOf<LongMetric>longMetricZ;/* Paired advance width and leading 299 * bearing values for each glyph. The 300 * value numOfHMetrics comes from 301 * the 'hhea' table. If the font is 302 * monospaced, only one entry need 303 * be in the array, but that entry is 304 * required. The last entry applies to 305 * all subsequent glyphs. */ 306 /*UnsizedArrayOf<FWORD> leadingBearingX;*//* Here the advance is assumed 307 * to be the same as the advance 308 * for the last entry above. The 309 * number of entries in this array is 310 * derived from numGlyphs (from 'maxp' 311 * table) minus numberOfLongMetrics. 312 * This generally is used with a run 313 * of monospaced glyphs (e.g., Kanji 314 * fonts or Courier fonts). Only one 315 * run is allowed and it must be at 316 * the end. This allows a monospaced 317 * font to vary the side bearing 318 * values for each glyph. */ 319 public: 320 DEFINE_SIZE_ARRAY (0, longMetricZ); 321 }; 322 323 struct hmtx : hmtxvmtx<hmtx, hhea> { 324 static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx; 325 static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR; 326 static constexpr bool is_horizontal = true; 327 }; 328 struct vmtx : hmtxvmtx<vmtx, vhea> { 329 static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx; 330 static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR; 331 static constexpr bool is_horizontal = false; 332 }; 333 334 struct hmtx_accelerator_t : hmtx::accelerator_t {}; 335 struct vmtx_accelerator_t : vmtx::accelerator_t {}; 336 337 } /* namespace OT */ 338 339 340 #endif /* HB_OT_HMTX_TABLE_HH */ 341