name.hh (17555B)
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 OT_NAME_NAME_HH 28 #define OT_NAME_NAME_HH 29 30 #include "../../hb-open-type.hh" 31 #include "../../hb-ot-name-language.hh" 32 #include "../../hb-aat-layout.hh" 33 #include "../../hb-utf.hh" 34 35 36 namespace OT { 37 38 template <typename in_utf_t, typename out_utf_t> 39 inline unsigned int 40 hb_ot_name_convert_utf (hb_bytes_t bytes, 41 unsigned int *text_size /* IN/OUT */, 42 typename out_utf_t::codepoint_t *text /* OUT */) 43 { 44 unsigned int src_len = bytes.length / sizeof (typename in_utf_t::codepoint_t); 45 const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes.arrayZ; 46 const typename in_utf_t::codepoint_t *src_end = src + src_len; 47 48 typename out_utf_t::codepoint_t *dst = text; 49 50 hb_codepoint_t unicode; 51 const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; 52 53 if (text_size && *text_size) 54 { 55 (*text_size)--; /* Save room for NUL-termination. */ 56 const typename out_utf_t::codepoint_t *dst_end = text + *text_size; 57 58 while (src < src_end && dst < dst_end) 59 { 60 const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement); 61 typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode); 62 if (dst_next == dst) 63 break; /* Out-of-room. */ 64 65 dst = dst_next; 66 src = src_next; 67 } 68 69 *text_size = dst - text; 70 *dst = 0; /* NUL-terminate. */ 71 } 72 73 /* Accumulate length of rest. */ 74 unsigned int dst_len = dst - text; 75 while (src < src_end) 76 { 77 src = in_utf_t::next (src, src_end, &unicode, replacement); 78 dst_len += out_utf_t::encode_len (unicode); 79 } 80 return dst_len; 81 } 82 83 #define entry_score var.u16[0] 84 #define entry_index var.u16[1] 85 86 87 /* 88 * name -- Naming 89 * https://docs.microsoft.com/en-us/typography/opentype/spec/name 90 */ 91 #define HB_OT_TAG_name HB_TAG('n','a','m','e') 92 93 #define UNSUPPORTED 42 94 95 struct NameRecord 96 { 97 hb_language_t language (hb_face_t *face) const 98 { 99 #ifndef HB_NO_OT_NAME_LANGUAGE 100 unsigned int p = platformID; 101 unsigned int l = languageID; 102 103 if (p == 3) 104 return _hb_ot_name_language_for_ms_code (l); 105 106 if (p == 1) 107 return _hb_ot_name_language_for_mac_code (l); 108 109 #ifndef HB_NO_OT_NAME_LANGUAGE_AAT 110 if (p == 0) 111 return face->table.ltag->get_language (l); 112 #endif 113 114 #endif 115 return HB_LANGUAGE_INVALID; 116 } 117 118 uint16_t score () const 119 { 120 /* Same order as in cmap::find_best_subtable(). */ 121 unsigned int p = platformID; 122 unsigned int e = encodingID; 123 124 /* 32-bit. */ 125 if (p == 3 && e == 10) return 0; 126 if (p == 0 && e == 6) return 1; 127 if (p == 0 && e == 4) return 2; 128 129 /* 16-bit. */ 130 if (p == 3 && e == 1) return 3; 131 if (p == 0 && e == 3) return 4; 132 if (p == 0 && e == 2) return 5; 133 if (p == 0 && e == 1) return 6; 134 if (p == 0 && e == 0) return 7; 135 136 /* Symbol. */ 137 if (p == 3 && e == 0) return 8; 138 139 /* We treat all Mac Latin names as ASCII only. */ 140 if (p == 1 && e == 0) return 10; /* 10 is magic number :| */ 141 142 return UNSUPPORTED; 143 } 144 145 NameRecord* copy (hb_serialize_context_t *c, const void *base 146 #ifdef HB_EXPERIMENTAL_API 147 , const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides 148 #endif 149 ) const 150 { 151 TRACE_SERIALIZE (this); 152 HB_UNUSED auto snap = c->snapshot (); 153 auto *out = c->embed (this); 154 if (unlikely (!out)) return_trace (nullptr); 155 #ifdef HB_EXPERIMENTAL_API 156 hb_ot_name_record_ids_t record_ids (platformID, encodingID, languageID, nameID); 157 hb_bytes_t* name_bytes; 158 159 if (name_table_overrides->has (record_ids, &name_bytes)) { 160 hb_bytes_t encoded_bytes = *name_bytes; 161 char *name_str_utf16_be = nullptr; 162 163 if (platformID != 1) 164 { 165 unsigned text_size = hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, nullptr, nullptr); 166 167 text_size++; // needs to consider NULL terminator for use in hb_ot_name_convert_utf() 168 unsigned byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size; 169 name_str_utf16_be = (char *) hb_calloc (byte_len, 1); 170 if (!name_str_utf16_be) 171 { 172 c->revert (snap); 173 return_trace (nullptr); 174 } 175 hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, &text_size, 176 (hb_utf16_be_t::codepoint_t *) name_str_utf16_be); 177 178 unsigned encoded_byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size; 179 if (!encoded_byte_len || !c->check_assign (out->length, encoded_byte_len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) { 180 c->revert (snap); 181 hb_free (name_str_utf16_be); 182 return_trace (nullptr); 183 } 184 185 encoded_bytes = hb_bytes_t (name_str_utf16_be, encoded_byte_len); 186 } 187 else 188 { 189 // mac platform, copy the UTF-8 string(all ascii characters) as is 190 if (!c->check_assign (out->length, encoded_bytes.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) { 191 c->revert (snap); 192 return_trace (nullptr); 193 } 194 } 195 196 out->offset = 0; 197 c->push (); 198 encoded_bytes.copy (c); 199 c->add_link (out->offset, c->pop_pack (), hb_serialize_context_t::Tail, 0); 200 hb_free (name_str_utf16_be); 201 } 202 else 203 #endif 204 { 205 out->offset.serialize_copy (c, offset, base, 0, hb_serialize_context_t::Tail, length); 206 } 207 return_trace (out); 208 } 209 210 bool isUnicode () const 211 { 212 unsigned int p = platformID; 213 unsigned int e = encodingID; 214 215 return (p == 0 || 216 (p == 3 && (e == 0 || e == 1 || e == 10))); 217 } 218 219 static int cmp (const void *pa, const void *pb) 220 { 221 const NameRecord *a = (const NameRecord *)pa; 222 const NameRecord *b = (const NameRecord *)pb; 223 224 if (a->platformID != b->platformID) 225 return a->platformID - b->platformID; 226 227 if (a->encodingID != b->encodingID) 228 return a->encodingID - b->encodingID; 229 230 if (a->languageID != b->languageID) 231 return a->languageID - b->languageID; 232 233 if (a->nameID != b->nameID) 234 return a->nameID - b->nameID; 235 236 if (a->length != b->length) 237 return a->length - b->length; 238 239 return 0; 240 } 241 242 bool sanitize (hb_sanitize_context_t *c, const void *base) const 243 { 244 TRACE_SANITIZE (this); 245 return_trace (c->check_struct (this) && 246 hb_barrier () && 247 offset.sanitize (c, base, length)); 248 } 249 250 HBUINT16 platformID; /* Platform ID. */ 251 HBUINT16 encodingID; /* Platform-specific encoding ID. */ 252 HBUINT16 languageID; /* Language ID. */ 253 HBUINT16 nameID; /* Name ID. */ 254 HBUINT16 length; /* String length (in bytes). */ 255 NNOffset16To<UnsizedArrayOf<HBUINT8>> 256 offset; /* String offset from start of storage area (in bytes). */ 257 public: 258 DEFINE_SIZE_STATIC (12); 259 }; 260 261 static int 262 _hb_ot_name_entry_cmp_key (const void *pa, const void *pb, bool exact) 263 { 264 const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; 265 const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; 266 267 /* Compare by name_id, then language. */ 268 269 if (a->name_id != b->name_id) 270 return a->name_id - b->name_id; 271 272 if (a->language == b->language) return 0; 273 if (!a->language) return -1; 274 if (!b->language) return +1; 275 276 const char *astr = hb_language_to_string (a->language); 277 const char *bstr = hb_language_to_string (b->language); 278 279 signed c = strcmp (astr, bstr); 280 281 // 'a' is the user request, and 'b' is string in the font. 282 // If eg. user asks for "en-us" and font has "en", approve. 283 if (!exact && c && 284 hb_language_matches (b->language, a->language)) 285 return 0; 286 287 return c; 288 } 289 290 static int 291 _hb_ot_name_entry_cmp (const void *pa, const void *pb) 292 { 293 /* Compare by name_id, then language, then score, then index. */ 294 295 int v = _hb_ot_name_entry_cmp_key (pa, pb, true); 296 if (v) 297 return v; 298 299 const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; 300 const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; 301 302 if (a->entry_score != b->entry_score) 303 return a->entry_score - b->entry_score; 304 305 if (a->entry_index != b->entry_index) 306 return a->entry_index - b->entry_index; 307 308 return 0; 309 } 310 311 struct name 312 { 313 static constexpr hb_tag_t tableTag = HB_OT_TAG_name; 314 315 unsigned int get_size () const 316 { return min_size + count * nameRecordZ.item_size; } 317 318 template <typename Iterator, 319 hb_requires (hb_is_source_of (Iterator, const NameRecord &))> 320 bool serialize (hb_serialize_context_t *c, 321 Iterator it, 322 const void *src_string_pool 323 #ifdef HB_EXPERIMENTAL_API 324 , const hb_vector_t<hb_ot_name_record_ids_t>& insert_name_records 325 , const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides 326 #endif 327 ) 328 { 329 TRACE_SERIALIZE (this); 330 331 if (unlikely (!c->extend_min ((*this)))) return_trace (false); 332 333 unsigned total_count = it.len () 334 #ifdef HB_EXPERIMENTAL_API 335 + insert_name_records.length 336 #endif 337 ; 338 this->format = 0; 339 if (!c->check_assign (this->count, total_count, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 340 return false; 341 342 NameRecord *name_records = (NameRecord *) hb_calloc (total_count, NameRecord::static_size); 343 if (unlikely (!name_records)) return_trace (false); 344 345 hb_array_t<NameRecord> records (name_records, total_count); 346 347 for (const NameRecord& record : it) 348 { 349 hb_memcpy (name_records, &record, NameRecord::static_size); 350 name_records++; 351 } 352 353 #ifdef HB_EXPERIMENTAL_API 354 for (unsigned i = 0; i < insert_name_records.length; i++) 355 { 356 const hb_ot_name_record_ids_t& ids = insert_name_records[i]; 357 NameRecord record; 358 record.platformID = ids.platform_id; 359 record.encodingID = ids.encoding_id; 360 record.languageID = ids.language_id; 361 record.nameID = ids.name_id; 362 record.length = 0; // handled in NameRecord copy() 363 record.offset = 0; 364 hb_memcpy (name_records, &record, NameRecord::static_size); 365 name_records++; 366 } 367 #endif 368 369 records.qsort (); 370 371 c->copy_all (records, 372 src_string_pool 373 #ifdef HB_EXPERIMENTAL_API 374 , name_table_overrides 375 #endif 376 ); 377 hb_free (records.arrayZ); 378 379 380 if (unlikely (c->ran_out_of_room ())) return_trace (false); 381 382 this->stringOffset = c->length (); 383 384 return_trace (true); 385 } 386 387 bool subset (hb_subset_context_t *c) const 388 { 389 auto *name_prime = c->serializer->start_embed<name> (); 390 391 #ifdef HB_EXPERIMENTAL_API 392 const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides = 393 &c->plan->name_table_overrides; 394 #endif 395 396 auto it = 397 + nameRecordZ.as_array (count) 398 | hb_filter (c->plan->name_ids, &NameRecord::nameID) 399 | hb_filter (c->plan->name_languages, &NameRecord::languageID) 400 | hb_filter ([&] (const NameRecord& namerecord) { 401 return 402 (c->plan->flags & HB_SUBSET_FLAGS_NAME_LEGACY) 403 || namerecord.isUnicode (); 404 }) 405 #ifdef HB_EXPERIMENTAL_API 406 | hb_filter ([&] (const NameRecord& namerecord) { 407 if (name_table_overrides->is_empty ()) 408 return true; 409 hb_ot_name_record_ids_t rec_ids (namerecord.platformID, 410 namerecord.encodingID, 411 namerecord.languageID, 412 namerecord.nameID); 413 414 hb_bytes_t *p; 415 if (name_table_overrides->has (rec_ids, &p) && 416 (*p).length == 0) 417 return false; 418 return true; 419 }) 420 #endif 421 ; 422 423 #ifdef HB_EXPERIMENTAL_API 424 hb_hashmap_t<hb_ot_name_record_ids_t, unsigned> retained_name_record_ids; 425 for (const NameRecord& rec : it) 426 { 427 hb_ot_name_record_ids_t rec_ids (rec.platformID, 428 rec.encodingID, 429 rec.languageID, 430 rec.nameID); 431 retained_name_record_ids.set (rec_ids, 1); 432 } 433 434 hb_vector_t<hb_ot_name_record_ids_t> insert_name_records; 435 if (!name_table_overrides->is_empty ()) 436 { 437 if (unlikely (!insert_name_records.alloc (name_table_overrides->get_population (), true))) 438 return false; 439 for (const auto& record_ids : name_table_overrides->keys ()) 440 { 441 if (name_table_overrides->get (record_ids).length == 0) 442 continue; 443 if (retained_name_record_ids.has (record_ids)) 444 continue; 445 insert_name_records.push (record_ids); 446 } 447 } 448 #endif 449 450 return name_prime->serialize (c->serializer, it, 451 std::addressof (this + stringOffset) 452 #ifdef HB_EXPERIMENTAL_API 453 , insert_name_records 454 , name_table_overrides 455 #endif 456 ); 457 } 458 459 bool sanitize_records (hb_sanitize_context_t *c) const 460 { 461 TRACE_SANITIZE (this); 462 const void *string_pool = (this+stringOffset).arrayZ; 463 return_trace (nameRecordZ.sanitize (c, count, string_pool)); 464 } 465 466 bool sanitize (hb_sanitize_context_t *c) const 467 { 468 TRACE_SANITIZE (this); 469 return_trace (c->check_struct (this) && 470 hb_barrier () && 471 likely (format == 0 || format == 1) && 472 c->check_array (nameRecordZ.arrayZ, count) && 473 c->check_range (this, stringOffset) && 474 sanitize_records (c)); 475 } 476 477 struct accelerator_t 478 { 479 accelerator_t (hb_face_t *face) 480 { 481 this->table = hb_sanitize_context_t ().reference_table<name> (face); 482 assert (this->table.get_length () >= this->table->stringOffset); 483 this->pool = (const char *) (const void *) (this->table+this->table->stringOffset); 484 this->pool_len = this->table.get_length () - this->table->stringOffset; 485 const hb_array_t<const NameRecord> all_names (this->table->nameRecordZ.arrayZ, 486 this->table->count); 487 488 this->names.alloc_exact (all_names.length); 489 490 for (unsigned int i = 0; i < all_names.length; i++) 491 { 492 hb_ot_name_entry_t *entry = this->names.push (); 493 494 entry->name_id = all_names[i].nameID; 495 entry->language = all_names[i].language (face); 496 entry->entry_score = all_names[i].score (); 497 entry->entry_index = i; 498 } 499 500 this->names.qsort (_hb_ot_name_entry_cmp); 501 /* Walk and pick best only for each name_id,language pair, 502 * while dropping unsupported encodings. */ 503 unsigned int j = 0; 504 for (unsigned int i = 0; i < this->names.length; i++) 505 { 506 if (this->names[i].entry_score == UNSUPPORTED || 507 this->names[i].language == HB_LANGUAGE_INVALID) 508 continue; 509 if (i && 510 this->names[i - 1].name_id == this->names[i].name_id && 511 this->names[i - 1].language == this->names[i].language) 512 continue; 513 this->names[j++] = this->names[i]; 514 } 515 this->names.resize (j); 516 } 517 ~accelerator_t () 518 { 519 this->table.destroy (); 520 } 521 522 int get_index (hb_ot_name_id_t name_id, 523 hb_language_t language, 524 unsigned int *width=nullptr) const 525 { 526 const hb_ot_name_entry_t key = {name_id, {0}, language}; 527 const hb_ot_name_entry_t *entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names, 528 this->names.length, 529 sizeof (hb_ot_name_entry_t), 530 _hb_ot_name_entry_cmp_key, 531 true); 532 533 if (!entry) 534 { 535 entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names, 536 this->names.length, 537 sizeof (hb_ot_name_entry_t), 538 _hb_ot_name_entry_cmp_key, 539 false); 540 } 541 542 if (!entry) 543 return -1; 544 545 if (width) 546 *width = entry->entry_score < 10 ? 2 : 1; 547 548 return entry->entry_index; 549 } 550 551 hb_bytes_t get_name (unsigned int idx) const 552 { 553 const hb_array_t<const NameRecord> all_names (table->nameRecordZ.arrayZ, table->count); 554 const NameRecord &record = all_names[idx]; 555 const hb_bytes_t string_pool (pool, pool_len); 556 return string_pool.sub_array (record.offset, record.length); 557 } 558 559 private: 560 const char *pool; 561 unsigned int pool_len; 562 public: 563 hb_blob_ptr_t<name> table; 564 hb_vector_t<hb_ot_name_entry_t> names; 565 }; 566 567 public: 568 /* We only implement format 0 for now. */ 569 HBUINT16 format; /* Format selector (=0/1). */ 570 HBUINT16 count; /* Number of name records. */ 571 NNOffset16To<UnsizedArrayOf<HBUINT8>> 572 stringOffset; /* Offset to start of string storage (from start of table). */ 573 UnsizedArrayOf<NameRecord> 574 nameRecordZ; /* The name records where count is the number of records. */ 575 public: 576 DEFINE_SIZE_ARRAY (6, nameRecordZ); 577 }; 578 579 #undef entry_index 580 #undef entry_score 581 582 struct name_accelerator_t : name::accelerator_t { 583 name_accelerator_t (hb_face_t *face) : name::accelerator_t (face) {} 584 }; 585 586 } /* namespace OT */ 587 588 589 #endif /* OT_NAME_NAME_HH */