hb-ot-kern-table.hh (12371B)
1 /* 2 * Copyright © 2017 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 25 */ 26 27 #ifndef HB_OT_KERN_TABLE_HH 28 #define HB_OT_KERN_TABLE_HH 29 30 #include "hb-aat-layout-common.hh" 31 #include "hb-aat-layout-kerx-table.hh" 32 33 34 /* 35 * kern -- Kerning 36 * https://docs.microsoft.com/en-us/typography/opentype/spec/kern 37 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html 38 */ 39 #define HB_OT_TAG_kern HB_TAG('k','e','r','n') 40 41 42 namespace OT { 43 44 45 template <typename KernSubTableHeader> 46 struct KernSubTableFormat3 47 { 48 int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const 49 { 50 hb_array_t<const FWORD> kernValue = kernValueZ.as_array (kernValueCount); 51 hb_array_t<const HBUINT8> leftClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (kernValue).as_array (glyphCount); 52 hb_array_t<const HBUINT8> rightClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (leftClass).as_array (glyphCount); 53 hb_array_t<const HBUINT8> kernIndex = StructAfter<const UnsizedArrayOf<HBUINT8>> (rightClass).as_array (leftClassCount * rightClassCount); 54 55 unsigned int leftC = leftClass[left]; 56 unsigned int rightC = rightClass[right]; 57 if (unlikely (leftC >= leftClassCount || rightC >= rightClassCount)) 58 return 0; 59 unsigned int i = leftC * rightClassCount + rightC; 60 return kernValue[kernIndex[i]]; 61 } 62 63 bool apply (AAT::hb_aat_apply_context_t *c) const 64 { 65 TRACE_APPLY (this); 66 67 if (!c->plan->requested_kerning) 68 return false; 69 70 if (header.coverage & header.Backwards) 71 return false; 72 73 hb_kern_machine_t<KernSubTableFormat3> machine (*this, header.coverage & header.CrossStream); 74 machine.kern (c->font, c->buffer, c->plan->kern_mask); 75 76 return_trace (true); 77 } 78 79 bool sanitize (hb_sanitize_context_t *c) const 80 { 81 TRACE_SANITIZE (this); 82 return_trace (c->check_struct (this) && 83 hb_barrier () && 84 c->check_range (kernValueZ, 85 kernValueCount * sizeof (FWORD) + 86 glyphCount * 2 + 87 leftClassCount * rightClassCount)); 88 } 89 90 template <typename set_t> 91 void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const 92 { 93 if (likely (glyphCount)) 94 { 95 left_set.add_range (0, num_glyphs - 1); 96 right_set.add_range (0, num_glyphs - 1); 97 } 98 } 99 100 protected: 101 KernSubTableHeader 102 header; 103 HBUINT16 glyphCount; /* The number of glyphs in this font. */ 104 HBUINT8 kernValueCount; /* The number of kerning values. */ 105 HBUINT8 leftClassCount; /* The number of left-hand classes. */ 106 HBUINT8 rightClassCount;/* The number of right-hand classes. */ 107 HBUINT8 flags; /* Set to zero (reserved for future use). */ 108 UnsizedArrayOf<FWORD> 109 kernValueZ; /* The kerning values. 110 * Length kernValueCount. */ 111 #if 0 112 UnsizedArrayOf<HBUINT8> 113 leftClass; /* The left-hand classes. 114 * Length glyphCount. */ 115 UnsizedArrayOf<HBUINT8> 116 rightClass; /* The right-hand classes. 117 * Length glyphCount. */ 118 UnsizedArrayOf<HBUINT8>kernIndex; 119 /* The indices into the kernValue array. 120 * Length leftClassCount * rightClassCount */ 121 #endif 122 public: 123 DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 6, kernValueZ); 124 }; 125 126 template <typename KernSubTableHeader> 127 struct KernSubTable 128 { 129 unsigned int get_size () const { return u.header.length; } 130 unsigned int get_type () const { return u.header.format; } 131 132 int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const 133 { 134 switch (get_type ()) { 135 /* This method hooks up to hb_font_t's get_h_kerning. Only support Format0. */ 136 case 0: hb_barrier (); return u.format0.get_kerning (left, right); 137 default:return 0; 138 } 139 } 140 141 template <typename context_t, typename ...Ts> 142 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 143 { 144 unsigned int subtable_type = get_type (); 145 TRACE_DISPATCH (this, subtable_type); 146 switch (subtable_type) { 147 case 0: return_trace (c->dispatch (u.format0)); 148 #ifndef HB_NO_AAT_SHAPE 149 case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); 150 #endif 151 case 2: return_trace (c->dispatch (u.format2)); 152 #ifndef HB_NO_AAT_SHAPE 153 case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...)); 154 #endif 155 default: return_trace (c->default_return_value ()); 156 } 157 } 158 159 template <typename set_t> 160 void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const 161 { 162 unsigned int subtable_type = get_type (); 163 switch (subtable_type) { 164 case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return; 165 case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return; 166 case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return; 167 case 3: u.format3.collect_glyphs (left_set, right_set, num_glyphs); return; 168 default: return; 169 } 170 } 171 172 bool sanitize (hb_sanitize_context_t *c) const 173 { 174 TRACE_SANITIZE (this); 175 if (unlikely (!(u.header.sanitize (c) && 176 hb_barrier () && 177 u.header.length >= u.header.min_size && 178 c->check_range (this, u.header.length)))) return_trace (false); 179 180 return_trace (dispatch (c)); 181 } 182 183 public: 184 union { 185 KernSubTableHeader header; 186 AAT::KerxSubTableFormat0<KernSubTableHeader> format0; 187 AAT::KerxSubTableFormat1<KernSubTableHeader> format1; 188 AAT::KerxSubTableFormat2<KernSubTableHeader> format2; 189 KernSubTableFormat3<KernSubTableHeader> format3; 190 } u; 191 public: 192 DEFINE_SIZE_MIN (KernSubTableHeader::static_size); 193 }; 194 195 196 struct KernOTSubTableHeader 197 { 198 static constexpr bool apple = false; 199 typedef AAT::ObsoleteTypes Types; 200 201 unsigned tuple_count () const { return 0; } 202 bool is_horizontal () const { return (coverage & Horizontal); } 203 204 enum Coverage 205 { 206 Horizontal = 0x01u, 207 Minimum = 0x02u, 208 CrossStream = 0x04u, 209 Override = 0x08u, 210 211 /* Not supported: */ 212 Backwards = 0x00u, 213 Variation = 0x00u, 214 }; 215 216 bool sanitize (hb_sanitize_context_t *c) const 217 { 218 TRACE_SANITIZE (this); 219 return_trace (c->check_struct (this)); 220 } 221 222 public: 223 HBUINT16 versionZ; /* Unused. */ 224 HBUINT16 length; /* Length of the subtable (including this header). */ 225 HBUINT8 format; /* Subtable format. */ 226 HBUINT8 coverage; /* Coverage bits. */ 227 public: 228 DEFINE_SIZE_STATIC (6); 229 }; 230 231 struct KernOT : AAT::KerxTable<KernOT> 232 { 233 friend struct AAT::KerxTable<KernOT>; 234 235 static constexpr hb_tag_t tableTag = HB_OT_TAG_kern; 236 static constexpr unsigned minVersion = 0u; 237 238 typedef KernOTSubTableHeader SubTableHeader; 239 typedef SubTableHeader::Types Types; 240 typedef KernSubTable<SubTableHeader> SubTable; 241 242 protected: 243 HBUINT16 version; /* Version--0x0000u */ 244 HBUINT16 tableCount; /* Number of subtables in the kerning table. */ 245 SubTable firstSubTable; /* Subtables. */ 246 public: 247 DEFINE_SIZE_MIN (4); 248 }; 249 250 251 struct KernAATSubTableHeader 252 { 253 static constexpr bool apple = true; 254 typedef AAT::ObsoleteTypes Types; 255 256 unsigned tuple_count () const { return 0; } 257 bool is_horizontal () const { return !(coverage & Vertical); } 258 259 enum Coverage 260 { 261 Vertical = 0x80u, 262 CrossStream = 0x40u, 263 Variation = 0x20u, 264 265 /* Not supported: */ 266 Backwards = 0x00u, 267 }; 268 269 bool sanitize (hb_sanitize_context_t *c) const 270 { 271 TRACE_SANITIZE (this); 272 return_trace (c->check_struct (this)); 273 } 274 275 public: 276 HBUINT32 length; /* Length of the subtable (including this header). */ 277 HBUINT8 coverage; /* Coverage bits. */ 278 HBUINT8 format; /* Subtable format. */ 279 HBUINT16 tupleIndex; /* The tuple index (used for variations fonts). 280 * This value specifies which tuple this subtable covers. 281 * Note: We don't implement. */ 282 public: 283 DEFINE_SIZE_STATIC (8); 284 }; 285 286 struct KernAAT : AAT::KerxTable<KernAAT> 287 { 288 friend struct AAT::KerxTable<KernAAT>; 289 290 static constexpr hb_tag_t tableTag = HB_OT_TAG_kern; 291 static constexpr unsigned minVersion = 0x00010000u; 292 293 typedef KernAATSubTableHeader SubTableHeader; 294 typedef SubTableHeader::Types Types; 295 typedef KernSubTable<SubTableHeader> SubTable; 296 297 protected: 298 HBUINT32 version; /* Version--0x00010000u */ 299 HBUINT32 tableCount; /* Number of subtables in the kerning table. */ 300 SubTable firstSubTable; /* Subtables. */ 301 public: 302 DEFINE_SIZE_MIN (8); 303 }; 304 305 struct kern 306 { 307 static constexpr hb_tag_t tableTag = HB_OT_TAG_kern; 308 309 bool has_data () const { return u.version32.v; } 310 unsigned get_type () const { return u.major.v; } 311 312 bool has_state_machine () const 313 { 314 switch (get_type ()) { 315 case 0: hb_barrier (); return u.ot.has_state_machine (); 316 #ifndef HB_NO_AAT_SHAPE 317 case 1: hb_barrier (); return u.aat.has_state_machine (); 318 #endif 319 default:return false; 320 } 321 } 322 323 bool has_cross_stream () const 324 { 325 switch (get_type ()) { 326 case 0: hb_barrier (); return u.ot.has_cross_stream (); 327 #ifndef HB_NO_AAT_SHAPE 328 case 1: hb_barrier (); return u.aat.has_cross_stream (); 329 #endif 330 default:return false; 331 } 332 } 333 334 int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const 335 { 336 switch (get_type ()) { 337 case 0: hb_barrier (); return u.ot.get_h_kerning (left, right); 338 #ifndef HB_NO_AAT_SHAPE 339 case 1: hb_barrier (); return u.aat.get_h_kerning (left, right); 340 #endif 341 default:return 0; 342 } 343 } 344 345 bool apply (AAT::hb_aat_apply_context_t *c, 346 const AAT::kern_accelerator_data_t &accel_data) const 347 { return dispatch (c, accel_data); } 348 349 template <typename context_t, typename ...Ts> 350 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 351 { 352 unsigned int subtable_type = get_type (); 353 TRACE_DISPATCH (this, subtable_type); 354 switch (subtable_type) { 355 case 0: return_trace (c->dispatch (u.ot, std::forward<Ts> (ds)...)); 356 #ifndef HB_NO_AAT_SHAPE 357 case 1: return_trace (c->dispatch (u.aat, std::forward<Ts> (ds)...)); 358 #endif 359 default: return_trace (c->default_return_value ()); 360 } 361 } 362 363 bool sanitize (hb_sanitize_context_t *c) const 364 { 365 TRACE_SANITIZE (this); 366 if (!u.version32.v.sanitize (c)) return_trace (false); 367 hb_barrier (); 368 return_trace (dispatch (c)); 369 } 370 371 AAT::kern_accelerator_data_t create_accelerator_data (unsigned num_glyphs) const 372 { 373 switch (get_type ()) { 374 case 0: hb_barrier (); return u.ot.create_accelerator_data (num_glyphs); 375 #ifndef HB_NO_AAT_SHAPE 376 case 1: hb_barrier (); return u.aat.create_accelerator_data (num_glyphs); 377 #endif 378 default:return AAT::kern_accelerator_data_t (); 379 } 380 } 381 382 struct accelerator_t 383 { 384 accelerator_t (hb_face_t *face) 385 { 386 hb_sanitize_context_t sc; 387 this->table = sc.reference_table<kern> (face); 388 this->accel_data = this->table->create_accelerator_data (face->get_num_glyphs ()); 389 } 390 ~accelerator_t () 391 { 392 this->table.destroy (); 393 } 394 395 hb_blob_t *get_blob () const { return table.get_blob (); } 396 397 bool apply (AAT::hb_aat_apply_context_t *c) const 398 { 399 return table->apply (c, accel_data); 400 } 401 402 hb_blob_ptr_t<kern> table; 403 AAT::kern_accelerator_data_t accel_data; 404 AAT::hb_aat_scratch_t scratch; 405 }; 406 407 protected: 408 union { 409 struct { HBUINT32 v; } version32; 410 struct { HBUINT16 v; } major; 411 KernOT ot; 412 #ifndef HB_NO_AAT_SHAPE 413 KernAAT aat; 414 #endif 415 } u; 416 public: 417 DEFINE_SIZE_UNION (4, version32.v); 418 }; 419 420 struct kern_accelerator_t : kern::accelerator_t { 421 kern_accelerator_t (hb_face_t *face) : kern::accelerator_t (face) {} 422 }; 423 424 } /* namespace OT */ 425 426 427 #endif /* HB_OT_KERN_TABLE_HH */