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-os2-table.hh" 33 #include "hb-ot-var-hvar-table.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 namespace OT { 46 47 48 struct LongMetric 49 { 50 UFWORD advance; /* Advance width/height. */ 51 FWORD sb; /* Leading (left/top) side bearing. */ 52 public: 53 DEFINE_SIZE_STATIC (4); 54 }; 55 56 template <typename T, typename H> 57 struct hmtxvmtx 58 { sanitizeOT::hmtxvmtx59 bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const 60 { 61 TRACE_SANITIZE (this); 62 /* We don't check for anything specific here. The users of the 63 * struct do all the hard work... */ 64 return_trace (true); 65 } 66 67 subset_update_headerOT::hmtxvmtx68 bool subset_update_header (hb_subset_plan_t *plan, 69 unsigned int num_hmetrics) const 70 { 71 hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (plan->source, H::tableTag); 72 hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob); 73 hb_blob_destroy (src_blob); 74 75 if (unlikely (!dest_blob)) { 76 return false; 77 } 78 79 unsigned int length; 80 H *table = (H *) hb_blob_get_data (dest_blob, &length); 81 table->numberOfLongMetrics.set (num_hmetrics); 82 83 bool result = plan->add_table (H::tableTag, dest_blob); 84 hb_blob_destroy (dest_blob); 85 86 return result; 87 } 88 subsetOT::hmtxvmtx89 bool subset (hb_subset_plan_t *plan) const 90 { 91 typename T::accelerator_t _mtx; 92 _mtx.init (plan->source); 93 94 /* All the trailing glyphs with the same advance can use one LongMetric 95 * and just keep LSB */ 96 hb_vector_t<hb_codepoint_t> &gids = plan->glyphs; 97 unsigned int num_advances = gids.len; 98 unsigned int last_advance = _mtx.get_advance (gids[num_advances - 1]); 99 while (num_advances > 1 && 100 last_advance == _mtx.get_advance (gids[num_advances - 2])) 101 { 102 num_advances--; 103 } 104 105 /* alloc the new table */ 106 size_t dest_sz = num_advances * 4 107 + (gids.len - num_advances) * 2; 108 void *dest = (void *) malloc (dest_sz); 109 if (unlikely (!dest)) 110 { 111 return false; 112 } 113 DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in src has %d advances, %d lsbs", HB_UNTAG(T::tableTag), _mtx.num_advances, _mtx.num_metrics - _mtx.num_advances); 114 DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in dest has %d advances, %d lsbs, %u bytes", HB_UNTAG(T::tableTag), num_advances, gids.len - num_advances, (unsigned int) dest_sz); 115 116 const char *source_table = hb_blob_get_data (_mtx.table.get_blob (), nullptr); 117 // Copy everything over 118 LongMetric * old_metrics = (LongMetric *) source_table; 119 FWORD *lsbs = (FWORD *) (old_metrics + _mtx.num_advances); 120 char * dest_pos = (char *) dest; 121 122 bool failed = false; 123 for (unsigned int i = 0; i < gids.len; i++) 124 { 125 /* the last metric or the one for gids[i] */ 126 LongMetric *src_metric = old_metrics + MIN ((hb_codepoint_t) _mtx.num_advances - 1, gids[i]); 127 if (gids[i] < _mtx.num_advances) 128 { 129 /* src is a LongMetric */ 130 if (i < num_advances) 131 { 132 /* dest is a LongMetric, copy it */ 133 *((LongMetric *) dest_pos) = *src_metric; 134 } 135 else 136 { 137 /* dest just sb */ 138 *((FWORD *) dest_pos) = src_metric->sb; 139 } 140 } 141 else 142 { 143 if (gids[i] >= _mtx.num_metrics) 144 { 145 DEBUG_MSG(SUBSET, nullptr, "gid %d is >= number of source metrics %d", 146 gids[i], _mtx.num_metrics); 147 failed = true; 148 break; 149 } 150 FWORD src_sb = *(lsbs + gids[i] - _mtx.num_advances); 151 if (i < num_advances) 152 { 153 /* dest needs a full LongMetric */ 154 LongMetric *metric = (LongMetric *)dest_pos; 155 metric->advance = src_metric->advance; 156 metric->sb = src_sb; 157 } 158 else 159 { 160 /* dest just needs an sb */ 161 *((FWORD *) dest_pos) = src_sb; 162 } 163 } 164 dest_pos += (i < num_advances ? 4 : 2); 165 } 166 _mtx.fini (); 167 168 // Amend header num hmetrics 169 if (failed || unlikely (!subset_update_header (plan, num_advances))) 170 { 171 free (dest); 172 return false; 173 } 174 175 hb_blob_t *result = hb_blob_create ((const char *)dest, 176 dest_sz, 177 HB_MEMORY_MODE_READONLY, 178 dest, 179 free); 180 bool success = plan->add_table (T::tableTag, result); 181 hb_blob_destroy (result); 182 return success; 183 } 184 185 struct accelerator_t 186 { 187 friend struct hmtxvmtx; 188 initOT::hmtxvmtx::accelerator_t189 void init (hb_face_t *face, 190 unsigned int default_advance_ = 0) 191 { 192 default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face); 193 194 bool got_font_extents = false; 195 if (T::os2Tag != HB_TAG_NONE && face->table.OS2->is_typo_metrics ()) 196 { 197 ascender = abs (face->table.OS2->sTypoAscender); 198 descender = -abs (face->table.OS2->sTypoDescender); 199 line_gap = face->table.OS2->sTypoLineGap; 200 got_font_extents = (ascender | descender) != 0; 201 } 202 203 hb_blob_t *_hea_blob = hb_sanitize_context_t().reference_table<H> (face); 204 const H *_hea_table = _hea_blob->as<H> (); 205 num_advances = _hea_table->numberOfLongMetrics; 206 if (!got_font_extents) 207 { 208 ascender = abs (_hea_table->ascender); 209 descender = -abs (_hea_table->descender); 210 line_gap = _hea_table->lineGap; 211 got_font_extents = (ascender | descender) != 0; 212 } 213 hb_blob_destroy (_hea_blob); 214 215 has_font_extents = got_font_extents; 216 217 table = hb_sanitize_context_t().reference_table<hmtxvmtx> (face, T::tableTag); 218 219 /* Cap num_metrics() and num_advances() based on table length. */ 220 unsigned int len = table.get_length (); 221 if (unlikely (num_advances * 4 > len)) 222 num_advances = len / 4; 223 num_metrics = num_advances + (len - 4 * num_advances) / 2; 224 225 /* We MUST set num_metrics to zero if num_advances is zero. 226 * Our get_advance() depends on that. */ 227 if (unlikely (!num_advances)) 228 { 229 num_metrics = num_advances = 0; 230 table.destroy (); 231 table = hb_blob_get_empty (); 232 } 233 234 var_table = hb_sanitize_context_t().reference_table<HVARVVAR> (face, T::variationsTag); 235 } 236 finiOT::hmtxvmtx::accelerator_t237 void fini () 238 { 239 table.destroy (); 240 var_table.destroy (); 241 } 242 243 /* TODO Add variations version. */ get_side_bearingOT::hmtxvmtx::accelerator_t244 unsigned int get_side_bearing (hb_codepoint_t glyph) const 245 { 246 if (glyph < num_advances) 247 return table->longMetricZ[glyph].sb; 248 249 if (unlikely (glyph >= num_metrics)) 250 return 0; 251 252 const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances]; 253 return bearings[glyph - num_advances]; 254 } 255 get_advanceOT::hmtxvmtx::accelerator_t256 unsigned int get_advance (hb_codepoint_t glyph) const 257 { 258 if (unlikely (glyph >= num_metrics)) 259 { 260 /* If num_metrics is zero, it means we don't have the metrics table 261 * for this direction: return default advance. Otherwise, it means that the 262 * glyph index is out of bound: return zero. */ 263 if (num_metrics) 264 return 0; 265 else 266 return default_advance; 267 } 268 269 return table->longMetricZ[MIN (glyph, (uint32_t) num_advances - 1)].advance; 270 } 271 get_advanceOT::hmtxvmtx::accelerator_t272 unsigned int get_advance (hb_codepoint_t glyph, 273 hb_font_t *font) const 274 { 275 unsigned int advance = get_advance (glyph); 276 if (likely (glyph < num_metrics)) 277 { 278 advance += (font->num_coords ? var_table->get_advance_var (glyph, font->coords, font->num_coords) : 0); // TODO Optimize?! 279 } 280 return advance; 281 } 282 283 public: 284 bool has_font_extents; 285 int ascender; 286 int descender; 287 int line_gap; 288 289 protected: 290 unsigned int num_metrics; 291 unsigned int num_advances; 292 unsigned int default_advance; 293 294 private: 295 hb_blob_ptr_t<hmtxvmtx> table; 296 hb_blob_ptr_t<HVARVVAR> var_table; 297 }; 298 299 protected: 300 UnsizedArrayOf<LongMetric>longMetricZ;/* Paired advance width and leading 301 * bearing values for each glyph. The 302 * value numOfHMetrics comes from 303 * the 'hhea' table. If the font is 304 * monospaced, only one entry need 305 * be in the array, but that entry is 306 * required. The last entry applies to 307 * all subsequent glyphs. */ 308 /*UnsizedArrayOf<FWORD> leadingBearingX;*//* Here the advance is assumed 309 * to be the same as the advance 310 * for the last entry above. The 311 * number of entries in this array is 312 * derived from numGlyphs (from 'maxp' 313 * table) minus numberOfLongMetrics. 314 * This generally is used with a run 315 * of monospaced glyphs (e.g., Kanji 316 * fonts or Courier fonts). Only one 317 * run is allowed and it must be at 318 * the end. This allows a monospaced 319 * font to vary the side bearing 320 * values for each glyph. */ 321 public: 322 DEFINE_SIZE_ARRAY (0, longMetricZ); 323 }; 324 325 struct hmtx : hmtxvmtx<hmtx, hhea> { 326 enum { tableTag = HB_OT_TAG_hmtx }; 327 enum { variationsTag = HB_OT_TAG_HVAR }; 328 enum { os2Tag = HB_OT_TAG_OS2 }; 329 }; 330 struct vmtx : hmtxvmtx<vmtx, vhea> { 331 enum { tableTag = HB_OT_TAG_vmtx }; 332 enum { variationsTag = HB_OT_TAG_VVAR }; 333 enum { os2Tag = HB_TAG_NONE }; 334 }; 335 336 struct hmtx_accelerator_t : hmtx::accelerator_t {}; 337 struct vmtx_accelerator_t : vmtx::accelerator_t {}; 338 339 } /* namespace OT */ 340 341 342 #endif /* HB_OT_HMTX_TABLE_HH */ 343