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-private.hh" 31 32 33 namespace OT { 34 35 36 /* 37 * name -- Naming 38 * https://docs.microsoft.com/en-us/typography/opentype/spec/name 39 */ 40 #define HB_OT_TAG_name HB_TAG('n','a','m','e') 41 42 43 struct NameRecord 44 { 45 static int cmp (const void *pa, const void *pb) 46 { 47 const NameRecord *a = (const NameRecord *) pa; 48 const NameRecord *b = (const NameRecord *) pb; 49 int ret; 50 ret = b->platformID.cmp (a->platformID); 51 if (ret) return ret; 52 ret = b->encodingID.cmp (a->encodingID); 53 if (ret) return ret; 54 ret = b->languageID.cmp (a->languageID); 55 if (ret) return ret; 56 ret = b->nameID.cmp (a->nameID); 57 if (ret) return ret; 58 return 0; 59 } 60 61 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const 62 { 63 TRACE_SANITIZE (this); 64 /* We can check from base all the way up to the end of string... */ 65 return_trace (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset)); 66 } 67 68 HBUINT16 platformID; /* Platform ID. */ 69 HBUINT16 encodingID; /* Platform-specific encoding ID. */ 70 HBUINT16 languageID; /* Language ID. */ 71 HBUINT16 nameID; /* Name ID. */ 72 HBUINT16 length; /* String length (in bytes). */ 73 HBUINT16 offset; /* String offset from start of storage area (in bytes). */ 74 public: 75 DEFINE_SIZE_STATIC (12); 76 }; 77 78 struct name 79 { 80 static const hb_tag_t tableTag = HB_OT_TAG_name; 81 82 inline unsigned int get_name (unsigned int platform_id, 83 unsigned int encoding_id, 84 unsigned int language_id, 85 unsigned int name_id, 86 void *buffer, 87 unsigned int buffer_length) const 88 { 89 NameRecord key; 90 key.platformID.set (platform_id); 91 key.encodingID.set (encoding_id); 92 key.languageID.set (language_id); 93 key.nameID.set (name_id); 94 NameRecord *match = (NameRecord *) bsearch (&key, nameRecord, count, sizeof (nameRecord[0]), NameRecord::cmp); 95 96 if (!match) 97 return 0; 98 99 unsigned int length = MIN (buffer_length, (unsigned int) match->length); 100 memcpy (buffer, (char *) this + stringOffset + match->offset, length); 101 return length; 102 } 103 104 inline unsigned int get_size (void) const 105 { return min_size + count * nameRecord[0].min_size; } 106 107 inline bool sanitize_records (hb_sanitize_context_t *c) const { 108 TRACE_SANITIZE (this); 109 char *string_pool = (char *) this + stringOffset; 110 unsigned int _count = count; 111 for (unsigned int i = 0; i < _count; i++) 112 if (!nameRecord[i].sanitize (c, string_pool)) return_trace (false); 113 return_trace (true); 114 } 115 116 inline bool sanitize (hb_sanitize_context_t *c) const 117 { 118 TRACE_SANITIZE (this); 119 return_trace (c->check_struct (this) && 120 likely (format == 0 || format == 1) && 121 c->check_array (nameRecord, nameRecord[0].static_size, count) && 122 sanitize_records (c)); 123 } 124 125 /* We only implement format 0 for now. */ 126 HBUINT16 format; /* Format selector (=0/1). */ 127 HBUINT16 count; /* Number of name records. */ 128 Offset16 stringOffset; /* Offset to start of string storage (from start of table). */ 129 NameRecord nameRecord[VAR]; /* The name records where count is the number of records. */ 130 public: 131 DEFINE_SIZE_ARRAY (6, nameRecord); 132 }; 133 134 135 } /* namespace OT */ 136 137 138 #endif /* HB_OT_NAME_TABLE_HH */ | 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 */ |