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 25 */ 26 27 #ifndef HB_OT_NAME_TABLE_HH 28 #define HB_OT_NAME_TABLE_HH 29 30 #include "hb-open-type.hh" 31 #include "hb-ot-name-language.hh" 32 #include "hb-aat-layout.hh" 33 34 35 namespace OT { 36 37 38 #define entry_score var.u16[0] 39 #define entry_index var.u16[1] 40 41 42 /* 43 * name -- Naming 44 * https://docs.microsoft.com/en-us/typography/opentype/spec/name 45 */ 46 #define HB_OT_TAG_name HB_TAG('n','a','m','e') 47 48 #define UNSUPPORTED 42 49 50 struct NameRecord 51 { 52 hb_language_t language (hb_face_t *face) const 53 { 54 unsigned int p = platformID; 55 unsigned int l = languageID; 56 57 if (p == 3) 58 return _hb_ot_name_language_for_ms_code (l); 59 60 if (p == 1) 61 return _hb_ot_name_language_for_mac_code (l); 62 63 if (p == 0) 64 return _hb_aat_language_get (face, l); 65 66 return HB_LANGUAGE_INVALID; 67 } 68 69 uint16_t score () const 70 { 71 /* Same order as in cmap::find_best_subtable(). */ 72 unsigned int p = platformID; 73 unsigned int e = encodingID; 74 75 /* 32-bit. */ 76 if (p == 3 && e == 10) return 0; 77 if (p == 0 && e == 6) return 1; 78 if (p == 0 && e == 4) return 2; 79 80 /* 16-bit. */ 81 if (p == 3 && e == 1) return 3; 82 if (p == 0 && e == 3) return 4; 83 if (p == 0 && e == 2) return 5; 84 if (p == 0 && e == 1) return 6; 85 if (p == 0 && e == 0) return 7; 86 87 /* Symbol. */ 88 if (p == 3 && e == 0) return 8; 89 90 /* We treat all Mac Latin names as ASCII only. */ 91 if (p == 1 && e == 0) return 10; /* 10 is magic number :| */ 92 93 return UNSUPPORTED; 94 } 95 96 bool sanitize (hb_sanitize_context_t *c, const void *base) const 97 { 98 TRACE_SANITIZE (this); 99 /* We can check from base all the way up to the end of string... */ 100 return_trace (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset)); 101 } 102 103 HBUINT16 platformID; /* Platform ID. */ 104 HBUINT16 encodingID; /* Platform-specific encoding ID. */ 105 HBUINT16 languageID; /* Language ID. */ 106 HBUINT16 nameID; /* Name ID. */ 107 HBUINT16 length; /* String length (in bytes). */ 108 HBUINT16 offset; /* String offset from start of storage area (in bytes). */ 109 public: 110 DEFINE_SIZE_STATIC (12); 111 }; 112 113 static int 114 _hb_ot_name_entry_cmp_key (const void *pa, const void *pb) 115 { 116 const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; 117 const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; 118 119 /* Compare by name_id, then language. */ 120 121 if (a->name_id != b->name_id) 122 return a->name_id < b->name_id ? -1 : +1; 123 124 if (a->language == b->language) return 0; 125 if (!a->language) return -1; 126 if (!b->language) return +1; 127 return strcmp (hb_language_to_string (a->language), 128 hb_language_to_string (b->language)); 129 } 130 131 static int 132 _hb_ot_name_entry_cmp (const void *pa, const void *pb) 133 { 134 /* Compare by name_id, then language, then score, then index. */ 135 136 int v = _hb_ot_name_entry_cmp_key (pa, pb); 137 if (v) 138 return v; 139 140 const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; 141 const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; 142 143 if (a->entry_score != b->entry_score) 144 return a->entry_score < b->entry_score ? -1 : +1; 145 146 if (a->entry_index != b->entry_index) 147 return a->entry_index < b->entry_index ? -1 : +1; 148 149 return 0; 150 } 151 152 struct name 153 { 154 static constexpr hb_tag_t tableTag = HB_OT_TAG_name; 155 156 unsigned int get_size () const 157 { return min_size + count * nameRecordZ.item_size; } 158 159 bool sanitize_records (hb_sanitize_context_t *c) const 160 { 161 TRACE_SANITIZE (this); 162 const void *string_pool = (this+stringOffset).arrayZ; 163 unsigned int _count = count; 164 /* Move to run-time?! */ 165 for (unsigned int i = 0; i < _count; i++) 166 if (!nameRecordZ[i].sanitize (c, string_pool)) return_trace (false); 167 return_trace (true); 168 } 169 170 bool sanitize (hb_sanitize_context_t *c) const 171 { 172 TRACE_SANITIZE (this); 173 return_trace (c->check_struct (this) && 174 likely (format == 0 || format == 1) && 175 c->check_array (nameRecordZ.arrayZ, count) && 176 c->check_range (this, stringOffset)); 177 } 178 179 struct accelerator_t 180 { 181 void init (hb_face_t *face) 182 { 183 this->table = hb_sanitize_context_t().reference_table<name> (face); 184 assert (this->table.get_length () >= this->table->stringOffset); 185 this->pool = (const char *) (const void *) (this->table+this->table->stringOffset); 186 this->pool_len = this->table.get_length () - this->table->stringOffset; 187 const hb_array_t<const NameRecord> all_names (this->table->nameRecordZ.arrayZ, 188 this->table->count); 189 190 this->names.init (); 191 this->names.alloc (all_names.length); 192 193 for (unsigned int i = 0; i < all_names.length; i++) 194 { 195 hb_ot_name_entry_t *entry = this->names.push (); 196 197 entry->name_id = all_names[i].nameID; 198 entry->language = all_names[i].language (face); 199 entry->entry_score = all_names[i].score (); 200 entry->entry_index = i; 201 } 202 203 this->names.qsort (_hb_ot_name_entry_cmp); 204 /* Walk and pick best only for each name_id,language pair, 205 * while dropping unsupported encodings. */ 206 unsigned int j = 0; 207 for (unsigned int i = 0; i < this->names.length; i++) 208 { 209 if (this->names[i].entry_score == UNSUPPORTED || 210 this->names[i].language == HB_LANGUAGE_INVALID) 211 continue; 212 if (i && 213 this->names[i - 1].name_id == this->names[i].name_id && 214 this->names[i - 1].language == this->names[i].language) 215 continue; 216 this->names[j++] = this->names[i]; 217 } 218 this->names.resize (j); 219 } 220 221 void fini () 222 { 223 this->names.fini (); 224 this->table.destroy (); 225 } 226 227 int get_index (hb_ot_name_id_t name_id, 228 hb_language_t language, 229 unsigned int *width=nullptr) const 230 { 231 const hb_ot_name_entry_t key = {name_id, {0}, language}; 232 const hb_ot_name_entry_t *entry = (const hb_ot_name_entry_t *) 233 hb_bsearch (&key, 234 (const hb_ot_name_entry_t *) this->names, 235 this->names.length, 236 sizeof (key), 237 _hb_ot_name_entry_cmp_key); 238 if (!entry) 239 return -1; 240 241 if (width) 242 *width = entry->entry_score < 10 ? 2 : 1; 243 244 return entry->entry_index; 245 } 246 247 hb_bytes_t get_name (unsigned int idx) const 248 { 249 const hb_array_t<const NameRecord> all_names (table->nameRecordZ.arrayZ, table->count); 250 const NameRecord &record = all_names[idx]; 251 const hb_bytes_t string_pool (pool, pool_len); 252 return string_pool.sub_array (record.offset, record.length); 253 } 254 255 private: 256 const char *pool; 257 unsigned int pool_len; 258 public: 259 hb_blob_ptr_t<name> table; 260 hb_vector_t<hb_ot_name_entry_t> names; 261 }; 262 263 /* We only implement format 0 for now. */ 264 HBUINT16 format; /* Format selector (=0/1). */ 265 HBUINT16 count; /* Number of name records. */ 266 NNOffsetTo<UnsizedArrayOf<HBUINT8> > 267 stringOffset; /* Offset to start of string storage (from start of table). */ 268 UnsizedArrayOf<NameRecord> 269 nameRecordZ; /* The name records where count is the number of records. */ 270 public: 271 DEFINE_SIZE_ARRAY (6, nameRecordZ); 272 }; 273 274 struct name_accelerator_t : name::accelerator_t {}; 275 276 } /* namespace OT */ 277 278 279 #endif /* HB_OT_NAME_TABLE_HH */