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 for (auto _ : it) 105 { 106 if (idx < num_advances) 107 { 108 LongMetric lm; 109 lm.advance = _.first; 110 lm.sb = _.second; 111 if (unlikely (!c->embed<LongMetric> (&lm))) return; 112 } 113 else 114 { 115 FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size); 116 if (unlikely (!sb)) return; 117 *sb = _.second; 118 } 119 idx++; 120 } 121 } 122 subsetOT::hmtxvmtx123 bool subset (hb_subset_context_t *c) const 124 { 125 TRACE_SUBSET (this); 126 127 T *table_prime = c->serializer->start_embed <T> (); 128 if (unlikely (!table_prime)) return_trace (false); 129 130 accelerator_t _mtx (c->plan->source); 131 unsigned num_advances; 132 { 133 /* Determine num_advances to encode. */ 134 auto& plan = c->plan; 135 num_advances = plan->num_output_glyphs (); 136 hb_codepoint_t old_gid = 0; 137 unsigned int last_advance = plan->old_gid_for_new_gid (num_advances - 1, &old_gid) ? _mtx.get_advance (old_gid) : 0; 138 while (num_advances > 1 && 139 last_advance == (plan->old_gid_for_new_gid (num_advances - 2, &old_gid) ? _mtx.get_advance (old_gid) : 0)) 140 { 141 num_advances--; 142 } 143 } 144 145 auto it = 146 + hb_range (c->plan->num_output_glyphs ()) 147 | hb_map ([c, &_mtx] (unsigned _) 148 { 149 hb_codepoint_t old_gid; 150 if (!c->plan->old_gid_for_new_gid (_, &old_gid)) 151 return hb_pair (0u, 0); 152 return hb_pair (_mtx.get_advance (old_gid), _mtx.get_side_bearing (old_gid)); 153 }) 154 ; 155 156 table_prime->serialize (c->serializer, it, num_advances); 157 158 if (unlikely (c->serializer->in_error ())) 159 return_trace (false); 160 161 // Amend header num hmetrics 162 if (unlikely (!subset_update_header (c->plan, num_advances))) 163 return_trace (false); 164 165 return_trace (true); 166 } 167 168 struct accelerator_t 169 { 170 friend struct hmtxvmtx; 171 accelerator_tOT::hmtxvmtx::accelerator_t172 accelerator_t (hb_face_t *face, 173 unsigned int default_advance_ = 0) 174 { 175 default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face); 176 177 num_advances = T::is_horizontal ? 178 face->table.hhea->numberOfLongMetrics : 179 #ifndef HB_NO_VERTICAL 180 face->table.vhea->numberOfLongMetrics 181 #else 182 0 183 #endif 184 ; 185 186 table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag); 187 188 /* Cap num_metrics() and num_advances() based on table length. */ 189 unsigned int len = table.get_length (); 190 if (unlikely (num_advances * 4 > len)) 191 num_advances = len / 4; 192 num_metrics = num_advances + (len - 4 * num_advances) / 2; 193 194 /* We MUST set num_metrics to zero if num_advances is zero. 195 * Our get_advance() depends on that. */ 196 if (unlikely (!num_advances)) 197 { 198 num_metrics = num_advances = 0; 199 table.destroy (); 200 table = hb_blob_get_empty (); 201 } 202 203 var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag); 204 } ~accelerator_tOT::hmtxvmtx::accelerator_t205 ~accelerator_t () 206 { 207 table.destroy (); 208 var_table.destroy (); 209 } 210 get_side_bearingOT::hmtxvmtx::accelerator_t211 int get_side_bearing (hb_codepoint_t glyph) const 212 { 213 if (glyph < num_advances) 214 return table->longMetricZ[glyph].sb; 215 216 if (unlikely (glyph >= num_metrics)) 217 return 0; 218 219 const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances]; 220 return bearings[glyph - num_advances]; 221 } 222 get_side_bearingOT::hmtxvmtx::accelerator_t223 int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const 224 { 225 int side_bearing = get_side_bearing (glyph); 226 227 #ifndef HB_NO_VAR 228 if (unlikely (glyph >= num_metrics) || !font->num_coords) 229 return side_bearing; 230 231 if (var_table.get_length ()) 232 return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?! 233 234 return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); 235 #else 236 return side_bearing; 237 #endif 238 } 239 get_advanceOT::hmtxvmtx::accelerator_t240 unsigned int get_advance (hb_codepoint_t glyph) const 241 { 242 if (unlikely (glyph >= num_metrics)) 243 { 244 /* If num_metrics is zero, it means we don't have the metrics table 245 * for this direction: return default advance. Otherwise, it means that the 246 * glyph index is out of bound: return zero. */ 247 if (num_metrics) 248 return 0; 249 else 250 return default_advance; 251 } 252 253 return table->longMetricZ[hb_min (glyph, (uint32_t) num_advances - 1)].advance; 254 } 255 get_advanceOT::hmtxvmtx::accelerator_t256 unsigned int get_advance (hb_codepoint_t glyph, 257 hb_font_t *font) const 258 { 259 unsigned int advance = get_advance (glyph); 260 261 #ifndef HB_NO_VAR 262 if (unlikely (glyph >= num_metrics) || !font->num_coords) 263 return advance; 264 265 if (var_table.get_length ()) 266 return advance + roundf (var_table->get_advance_var (glyph, font)); // TODO Optimize?! 267 268 return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); 269 #else 270 return advance; 271 #endif 272 } 273 274 protected: 275 unsigned int num_metrics; 276 unsigned int num_advances; 277 unsigned int default_advance; 278 279 private: 280 hb_blob_ptr_t<hmtxvmtx> table; 281 hb_blob_ptr_t<HVARVVAR> var_table; 282 }; 283 284 protected: 285 UnsizedArrayOf<LongMetric> 286 longMetricZ; /* Paired advance width and leading 287 * bearing values for each glyph. The 288 * value numOfHMetrics comes from 289 * the 'hhea' table. If the font is 290 * monospaced, only one entry need 291 * be in the array, but that entry is 292 * required. The last entry applies to 293 * all subsequent glyphs. */ 294 /*UnsizedArrayOf<FWORD> leadingBearingX;*/ 295 /* Here the advance is assumed 296 * to be the same as the advance 297 * for the last entry above. The 298 * number of entries in this array is 299 * derived from numGlyphs (from 'maxp' 300 * table) minus numberOfLongMetrics. 301 * This generally is used with a run 302 * of monospaced glyphs (e.g., Kanji 303 * fonts or Courier fonts). Only one 304 * run is allowed and it must be at 305 * the end. This allows a monospaced 306 * font to vary the side bearing 307 * values for each glyph. */ 308 public: 309 DEFINE_SIZE_ARRAY (0, longMetricZ); 310 }; 311 312 struct hmtx : hmtxvmtx<hmtx, hhea> { 313 static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx; 314 static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR; 315 static constexpr bool is_horizontal = true; 316 }; 317 struct vmtx : hmtxvmtx<vmtx, vhea> { 318 static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx; 319 static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR; 320 static constexpr bool is_horizontal = false; 321 }; 322 323 struct hmtx_accelerator_t : hmtx::accelerator_t { hmtx_accelerator_tOT::hmtx_accelerator_t324 hmtx_accelerator_t (hb_face_t *face) : hmtx::accelerator_t (face) {} 325 }; 326 struct vmtx_accelerator_t : vmtx::accelerator_t { vmtx_accelerator_tOT::vmtx_accelerator_t327 vmtx_accelerator_t (hb_face_t *face) : vmtx::accelerator_t (face) {} 328 }; 329 330 } /* namespace OT */ 331 332 333 #endif /* HB_OT_HMTX_TABLE_HH */ 334