hb-subset-plan.cc (28926B)
1 /* 2 * Copyright © 2018 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): Garret Rieger, Roderick Sheeter 25 */ 26 27 #include "hb-subset-plan.hh" 28 #include "hb-subset-accelerator.hh" 29 #include "hb-map.hh" 30 #include "hb-multimap.hh" 31 #include "hb-set.hh" 32 #include "hb-subset.h" 33 #include "hb-unicode.h" 34 35 #include "hb-ot-cmap-table.hh" 36 #include "hb-ot-glyf-table.hh" 37 #include "hb-ot-layout-base-table.hh" 38 #include "hb-ot-cff1-table.hh" 39 #include "hb-ot-cff2-table.hh" 40 #include "OT/Color/COLR/COLR.hh" 41 #include "OT/Color/COLR/colrv1-closure.hh" 42 #include "OT/Color/CPAL/CPAL.hh" 43 #include "hb-ot-var-fvar-table.hh" 44 #include "hb-ot-stat-table.hh" 45 #include "hb-ot-math-table.hh" 46 47 hb_subset_accelerator_t::~hb_subset_accelerator_t () 48 { 49 if (cmap_cache && destroy_cmap_cache) 50 destroy_cmap_cache ((void*) cmap_cache); 51 52 #ifndef HB_NO_SUBSET_CFF 53 cff1_accel.fini (); 54 cff2_accel.fini (); 55 #endif 56 hb_face_destroy (source); 57 } 58 59 60 #ifndef HB_NO_SUBSET_CFF 61 static inline bool 62 _add_cff_seac_components (const OT::cff1::accelerator_subset_t &cff, 63 hb_codepoint_t gid, 64 hb_set_t *gids_to_retain) 65 { 66 hb_codepoint_t base_gid, accent_gid; 67 if (cff.get_seac_components (gid, &base_gid, &accent_gid)) 68 { 69 gids_to_retain->add (base_gid); 70 gids_to_retain->add (accent_gid); 71 return true; 72 } 73 return false; 74 } 75 #endif 76 77 static void 78 _remap_palette_indexes (const hb_set_t *palette_indexes, 79 hb_map_t *mapping /* OUT */) 80 { 81 unsigned new_idx = 0; 82 for (unsigned palette_index : palette_indexes->iter ()) 83 { 84 if (palette_index == 0xFFFF) 85 { 86 mapping->set (palette_index, palette_index); 87 continue; 88 } 89 mapping->set (palette_index, new_idx); 90 new_idx++; 91 } 92 } 93 94 void 95 remap_indexes (const hb_set_t *indexes, 96 hb_map_t *mapping /* OUT */) 97 { 98 for (auto _ : + hb_enumerate (indexes->iter ())) 99 mapping->set (_.second, _.first); 100 } 101 102 static inline void 103 _cmap_closure (hb_face_t *face, 104 const hb_set_t *unicodes, 105 hb_set_t *glyphset) 106 { 107 OT::cmap::accelerator_t cmap (face); 108 cmap.table->closure_glyphs (unicodes, glyphset); 109 } 110 111 static void _colr_closure (hb_subset_plan_t* plan, 112 hb_set_t *glyphs_colred) 113 { 114 OT::COLR::accelerator_t colr (plan->source); 115 if (!colr.is_valid ()) return; 116 117 hb_set_t palette_indices, layer_indices; 118 // Collect all glyphs referenced by COLRv0 119 hb_set_t glyphset_colrv0; 120 for (hb_codepoint_t gid : *glyphs_colred) 121 colr.closure_glyphs (gid, &glyphset_colrv0); 122 123 glyphs_colred->union_ (glyphset_colrv0); 124 125 //closure for COLRv1 126 hb_set_t variation_indices, delta_set_indices; 127 colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices, &variation_indices, &delta_set_indices); 128 129 colr.closure_V0palette_indices (glyphs_colred, &palette_indices); 130 remap_indexes (&layer_indices, &plan->colrv1_layers); 131 _remap_palette_indexes (&palette_indices, &plan->colr_palettes); 132 133 #ifndef HB_NO_VAR 134 if (!colr.has_var_store () || !variation_indices) return; 135 136 const OT::ItemVariationStore &var_store = colr.get_var_store (); 137 // generated inner_maps is used by ItemVariationStore serialize(), which is subset only 138 unsigned subtable_count = var_store.get_sub_table_count (); 139 generate_varstore_inner_maps (variation_indices, subtable_count, plan->colrv1_varstore_inner_maps); 140 141 /* colr variation indices mapping during planning phase: 142 * generate colrv1_variation_idx_delta_map. When delta set index map is not 143 * included, it's a mapping from varIdx-> (new varIdx,delta). Otherwise, it's 144 * a mapping from old delta set idx-> (new delta set idx, delta). Mapping 145 * delta set indices is the same as gid mapping. 146 * Besides, we need to generate a delta set idx-> new var_idx map for updating 147 * delta set index map if exists. This map will be updated again after 148 * instancing. */ 149 if (!plan->all_axes_pinned) 150 { 151 remap_variation_indices (var_store, 152 variation_indices, 153 plan->normalized_coords, 154 false, /* no need to calculate delta for COLR during planning */ 155 plan->all_axes_pinned, 156 plan->colrv1_variation_idx_delta_map); 157 158 if (colr.has_delta_set_index_map ()) 159 remap_colrv1_delta_set_index_indices (colr.get_delta_set_index_map (), 160 delta_set_indices, 161 plan->colrv1_variation_idx_delta_map, 162 plan->colrv1_new_deltaset_idx_varidx_map); 163 } 164 #endif 165 } 166 167 static inline void 168 _math_closure (hb_subset_plan_t *plan, 169 hb_set_t *glyphset) 170 { 171 hb_blob_ptr_t<OT::MATH> math = plan->source_table<OT::MATH> (); 172 if (math->has_data ()) 173 math->closure_glyphs (glyphset); 174 math.destroy (); 175 } 176 177 static inline void 178 _remove_invalid_gids (hb_set_t *glyphs, 179 unsigned int num_glyphs) 180 { 181 glyphs->del_range (num_glyphs, HB_SET_VALUE_INVALID); 182 } 183 184 template<bool GID_ALWAYS_EXISTS = false, typename I, typename F, typename G, hb_requires (hb_is_iterator (I))> 185 static void 186 _fill_unicode_and_glyph_map(hb_subset_plan_t *plan, 187 I unicode_iterator, 188 F unicode_to_gid_for_iterator, 189 G unicode_to_gid_general) 190 { 191 for (hb_codepoint_t cp : unicode_iterator) 192 { 193 hb_codepoint_t gid = unicode_to_gid_for_iterator(cp); 194 if (!GID_ALWAYS_EXISTS && gid == HB_MAP_VALUE_INVALID) 195 { 196 DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp); 197 continue; 198 } 199 200 plan->codepoint_to_glyph->set (cp, gid); 201 plan->unicode_to_new_gid_list.push (hb_pair (cp, gid)); 202 } 203 } 204 205 template<bool GID_ALWAYS_EXISTS = false, typename I, typename F, hb_requires (hb_is_iterator (I))> 206 static void 207 _fill_unicode_and_glyph_map(hb_subset_plan_t *plan, 208 I unicode_iterator, 209 F unicode_to_gid_for_iterator) 210 { 211 _fill_unicode_and_glyph_map(plan, unicode_iterator, unicode_to_gid_for_iterator, unicode_to_gid_for_iterator); 212 } 213 214 /* 215 * Finds additional unicode codepoints which are reachable from the input unicode set. 216 * Currently this adds in mirrored variants (needed for bidi) of any input unicodes. 217 */ 218 static hb_set_t 219 _unicode_closure (const hb_set_t* unicodes, bool bidi_closure) { 220 // TODO: we may want to also consider pulling in reachable unicode composition and decompositions. 221 // see: https://github.com/harfbuzz/harfbuzz/issues/2283 222 hb_set_t out = *unicodes; 223 if (!bidi_closure) return out; 224 225 if (out.is_inverted()) { 226 // don't closure inverted sets, they are asking to specifically exclude certain codepoints. 227 // otherwise everything is already included. 228 return out; 229 } 230 231 auto unicode_funcs = hb_unicode_funcs_get_default (); 232 for (hb_codepoint_t cp : *unicodes) { 233 hb_codepoint_t mirror = hb_unicode_mirroring(unicode_funcs, cp); 234 if (unlikely (mirror != cp)) { 235 out.add(mirror); 236 } 237 } 238 239 return out; 240 } 241 242 static void 243 _populate_unicodes_to_retain (const hb_set_t *unicodes_in, 244 const hb_set_t *glyphs, 245 hb_subset_plan_t *plan) 246 { 247 hb_set_t unicodes = _unicode_closure(unicodes_in, 248 !(plan->flags & HB_SUBSET_FLAGS_NO_BIDI_CLOSURE)); 249 250 OT::cmap::accelerator_t cmap (plan->source); 251 unsigned size_threshold = plan->source->get_num_glyphs (); 252 253 if (glyphs->is_empty () && unicodes.get_population () < size_threshold) 254 { 255 256 const hb_map_t* unicode_to_gid = nullptr; 257 if (plan->accelerator) 258 unicode_to_gid = &plan->accelerator->unicode_to_gid; 259 260 // This is approach to collection is faster, but can only be used if glyphs 261 // are not being explicitly added to the subset and the input unicodes set is 262 // not excessively large (eg. an inverted set). 263 plan->unicode_to_new_gid_list.alloc (unicodes.get_population ()); 264 if (!unicode_to_gid) { 265 _fill_unicode_and_glyph_map(plan, unicodes.iter(), [&] (hb_codepoint_t cp) { 266 hb_codepoint_t gid; 267 if (!cmap.get_nominal_glyph (cp, &gid)) { 268 return HB_MAP_VALUE_INVALID; 269 } 270 return gid; 271 }); 272 } else { 273 // Use in memory unicode to gid map it's faster then looking up from 274 // the map. This code is mostly duplicated from above to avoid doing 275 // conditionals on the presence of the unicode_to_gid map each 276 // iteration. 277 _fill_unicode_and_glyph_map(plan, unicodes.iter(), [&] (hb_codepoint_t cp) { 278 return unicode_to_gid->get (cp); 279 }); 280 } 281 } 282 else 283 { 284 // This approach is slower, but can handle adding in glyphs to the subset and will match 285 // them with cmap entries. 286 287 hb_map_t unicode_glyphid_map_storage; 288 hb_set_t cmap_unicodes_storage; 289 const hb_map_t* unicode_glyphid_map = &unicode_glyphid_map_storage; 290 const hb_set_t* cmap_unicodes = &cmap_unicodes_storage; 291 292 if (!plan->accelerator) { 293 cmap.collect_mapping (&cmap_unicodes_storage, &unicode_glyphid_map_storage); 294 plan->unicode_to_new_gid_list.alloc (hb_min(unicodes.get_population () 295 + glyphs->get_population (), 296 cmap_unicodes->get_population ())); 297 } else { 298 unicode_glyphid_map = &plan->accelerator->unicode_to_gid; 299 cmap_unicodes = &plan->accelerator->unicodes; 300 } 301 302 if (plan->accelerator && 303 unicodes.get_population () < cmap_unicodes->get_population () && 304 glyphs->get_population () < cmap_unicodes->get_population ()) 305 { 306 plan->codepoint_to_glyph->alloc (unicodes.get_population () + glyphs->get_population ()); 307 308 auto &gid_to_unicodes = plan->accelerator->gid_to_unicodes; 309 310 for (hb_codepoint_t gid : *glyphs) 311 { 312 auto unicodes = gid_to_unicodes.get (gid); 313 _fill_unicode_and_glyph_map<true>(plan, unicodes, [&] (hb_codepoint_t cp) { 314 return gid; 315 }, 316 [&] (hb_codepoint_t cp) { 317 return unicode_glyphid_map->get(cp); 318 }); 319 } 320 321 _fill_unicode_and_glyph_map(plan, unicodes.iter(), [&] (hb_codepoint_t cp) { 322 /* Don't double-add entry. */ 323 if (plan->codepoint_to_glyph->has (cp)) 324 return HB_MAP_VALUE_INVALID; 325 326 return unicode_glyphid_map->get(cp); 327 }, 328 [&] (hb_codepoint_t cp) { 329 return unicode_glyphid_map->get(cp); 330 }); 331 332 plan->unicode_to_new_gid_list.qsort (); 333 } 334 else 335 { 336 plan->codepoint_to_glyph->alloc (cmap_unicodes->get_population ()); 337 hb_codepoint_t first = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID; 338 for (; cmap_unicodes->next_range (&first, &last); ) 339 { 340 _fill_unicode_and_glyph_map(plan, hb_range(first, last + 1), [&] (hb_codepoint_t cp) { 341 hb_codepoint_t gid = (*unicode_glyphid_map)[cp]; 342 if (!unicodes.has (cp) && !glyphs->has (gid)) 343 return HB_MAP_VALUE_INVALID; 344 return gid; 345 }, 346 [&] (hb_codepoint_t cp) { 347 return unicode_glyphid_map->get(cp); 348 }); 349 } 350 } 351 352 /* Add gids which where requested, but not mapped in cmap */ 353 unsigned num_glyphs = plan->source->get_num_glyphs (); 354 hb_codepoint_t first = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID; 355 for (; glyphs->next_range (&first, &last); ) 356 { 357 if (first >= num_glyphs) 358 break; 359 if (last >= num_glyphs) 360 last = num_glyphs - 1; 361 plan->_glyphset_gsub.add_range (first, last); 362 } 363 } 364 365 auto &arr = plan->unicode_to_new_gid_list; 366 if (arr.length) 367 { 368 plan->unicodes.add_sorted_array (&arr.arrayZ->first, arr.length, sizeof (*arr.arrayZ)); 369 plan->_glyphset_gsub.add_array (&arr.arrayZ->second, arr.length, sizeof (*arr.arrayZ)); 370 } 371 372 // Variation selectors don't have glyphs associated with them in the cmap so they will have been filtered out above 373 // but should still be retained. Add them back here. 374 375 // However, the min and max codepoints for OS/2 should be calculated without considering variation selectors, 376 // so record those first. 377 plan->os2_info.min_cmap_codepoint = plan->unicodes.get_min(); 378 plan->os2_info.max_cmap_codepoint = plan->unicodes.get_max(); 379 380 hb_set_t variation_selectors_to_retain; 381 cmap.collect_variation_selectors(&variation_selectors_to_retain); 382 + variation_selectors_to_retain.iter() 383 | hb_filter(unicodes) 384 | hb_sink(&plan->unicodes) 385 ; 386 } 387 388 static unsigned 389 _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf, 390 hb_codepoint_t gid, 391 hb_set_t *gids_to_retain, 392 int operation_count, 393 unsigned depth = 0) 394 { 395 /* Check if is already visited */ 396 if (gids_to_retain->has (gid)) return operation_count; 397 398 gids_to_retain->add (gid); 399 400 if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count; 401 if (unlikely (--operation_count < 0)) return operation_count; 402 403 auto glyph = glyf.glyph_for_gid (gid); 404 405 for (auto &item : glyph.get_composite_iterator ()) 406 operation_count = 407 _glyf_add_gid_and_children (glyf, 408 item.get_gid (), 409 gids_to_retain, 410 operation_count, 411 depth); 412 413 return operation_count; 414 } 415 416 static void 417 _nameid_closure (hb_subset_plan_t* plan, 418 hb_set_t* drop_tables) 419 { 420 #ifndef HB_NO_STYLE 421 if (!drop_tables->has (HB_OT_TAG_STAT)) 422 plan->source->table.STAT->collect_name_ids (&plan->user_axes_location, &plan->name_ids); 423 #endif 424 #ifndef HB_NO_VAR 425 if (!plan->all_axes_pinned) 426 plan->source->table.fvar->collect_name_ids (&plan->user_axes_location, &plan->axes_old_index_tag_map, &plan->name_ids); 427 #endif 428 #ifndef HB_NO_COLOR 429 if (!drop_tables->has (HB_OT_TAG_CPAL)) 430 plan->source->table.CPAL->collect_name_ids (&plan->colr_palettes, &plan->name_ids); 431 #endif 432 433 #ifndef HB_NO_SUBSET_LAYOUT 434 layout_nameid_closure(plan, drop_tables); 435 #endif 436 } 437 438 static void 439 _populate_gids_to_retain (hb_subset_plan_t* plan, 440 hb_set_t* drop_tables) 441 { 442 OT::glyf_accelerator_t glyf (plan->source); 443 #ifndef HB_NO_SUBSET_CFF 444 // Note: we cannot use inprogress_accelerator here, since it has not been 445 // created yet. So in case of preprocessed-face (and otherwise), we do an 446 // extra sanitize pass here, which is not ideal. 447 OT::cff1::accelerator_subset_t stack_cff (plan->accelerator ? nullptr : plan->source); 448 const OT::cff1::accelerator_subset_t *cff (plan->accelerator ? plan->accelerator->cff1_accel.get () : &stack_cff); 449 #endif 450 451 plan->_glyphset_gsub.add (0); // Not-def 452 453 _cmap_closure (plan->source, &plan->unicodes, &plan->_glyphset_gsub); 454 455 #ifndef HB_NO_SUBSET_LAYOUT 456 layout_populate_gids_to_retain(plan, drop_tables); 457 #endif 458 459 _remove_invalid_gids (&plan->_glyphset_gsub, plan->source->get_num_glyphs ()); 460 461 plan->_glyphset_mathed = plan->_glyphset_gsub; 462 if (!drop_tables->has (HB_OT_TAG_MATH)) 463 { 464 _math_closure (plan, &plan->_glyphset_mathed); 465 _remove_invalid_gids (&plan->_glyphset_mathed, plan->source->get_num_glyphs ()); 466 } 467 468 hb_set_t cur_glyphset = plan->_glyphset_mathed; 469 if (!drop_tables->has (HB_OT_TAG_COLR)) 470 { 471 _colr_closure (plan, &cur_glyphset); 472 _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ()); 473 } 474 475 plan->_glyphset_colred = cur_glyphset; 476 477 // XXX TODO VARC closure / subset 478 479 _nameid_closure (plan, drop_tables); 480 /* Populate a full set of glyphs to retain by adding all referenced 481 * composite glyphs. */ 482 if (glyf.has_data ()) 483 for (hb_codepoint_t gid : cur_glyphset) 484 _glyf_add_gid_and_children (glyf, gid, &plan->_glyphset, 485 cur_glyphset.get_population () * HB_MAX_COMPOSITE_OPERATIONS_PER_GLYPH); 486 else 487 plan->_glyphset.union_ (cur_glyphset); 488 #ifndef HB_NO_SUBSET_CFF 489 if (!plan->accelerator || plan->accelerator->has_seac) 490 { 491 bool has_seac = false; 492 if (cff->is_valid ()) 493 for (hb_codepoint_t gid : cur_glyphset) 494 if (_add_cff_seac_components (*cff, gid, &plan->_glyphset)) 495 has_seac = true; 496 plan->has_seac = has_seac; 497 } 498 #endif 499 500 _remove_invalid_gids (&plan->_glyphset, plan->source->get_num_glyphs ()); 501 502 #ifndef HB_NO_VAR 503 #ifndef HB_NO_SUBSET_LAYOUT 504 if (!drop_tables->has (HB_OT_TAG_GDEF)) 505 collect_layout_variation_indices (plan); 506 #endif 507 #endif 508 } 509 510 static void 511 _create_glyph_map_gsub (const hb_set_t* glyph_set_gsub, 512 const hb_map_t* glyph_map, 513 hb_map_t* out) 514 { 515 out->alloc (glyph_set_gsub->get_population ()); 516 + hb_iter (glyph_set_gsub) 517 | hb_map ([&] (hb_codepoint_t gid) { 518 return hb_codepoint_pair_t (gid, glyph_map->get (gid)); 519 }) 520 | hb_sink (out) 521 ; 522 } 523 524 static bool 525 _create_old_gid_to_new_gid_map (const hb_face_t *face, 526 bool retain_gids, 527 const hb_set_t *all_gids_to_retain, 528 const hb_map_t *requested_glyph_map, 529 hb_map_t *glyph_map, /* OUT */ 530 hb_map_t *reverse_glyph_map, /* OUT */ 531 hb_sorted_vector_t<hb_codepoint_pair_t> *new_to_old_gid_list /* OUT */, 532 unsigned int *num_glyphs /* OUT */) 533 { 534 unsigned pop = all_gids_to_retain->get_population (); 535 reverse_glyph_map->alloc (pop); 536 glyph_map->alloc (pop); 537 new_to_old_gid_list->alloc (pop); 538 539 if (*requested_glyph_map) 540 { 541 hb_set_t new_gids(requested_glyph_map->values()); 542 if (new_gids.get_population() != requested_glyph_map->get_population()) 543 { 544 DEBUG_MSG (SUBSET, nullptr, "The provided custom glyph mapping is not unique."); 545 return false; 546 } 547 548 if (retain_gids) 549 { 550 DEBUG_MSG (SUBSET, nullptr, 551 "HB_SUBSET_FLAGS_RETAIN_GIDS cannot be set if " 552 "a custom glyph mapping has been provided."); 553 return false; 554 } 555 556 hb_codepoint_t max_glyph = 0; 557 hb_set_t remaining; 558 for (auto old_gid : all_gids_to_retain->iter ()) 559 { 560 if (old_gid == 0) { 561 new_to_old_gid_list->push (hb_pair<hb_codepoint_t, hb_codepoint_t> (0u, 0u)); 562 continue; 563 } 564 565 hb_codepoint_t* new_gid; 566 if (!requested_glyph_map->has (old_gid, &new_gid)) 567 { 568 remaining.add(old_gid); 569 continue; 570 } 571 572 if (*new_gid > max_glyph) 573 max_glyph = *new_gid; 574 new_to_old_gid_list->push (hb_pair (*new_gid, old_gid)); 575 } 576 new_to_old_gid_list->qsort (); 577 578 // Anything that wasn't mapped by the requested mapping should 579 // be placed after the requested mapping. 580 for (auto old_gid : remaining) 581 new_to_old_gid_list->push (hb_pair (++max_glyph, old_gid)); 582 583 *num_glyphs = max_glyph + 1; 584 } 585 else if (!retain_gids) 586 { 587 + hb_enumerate (hb_iter (all_gids_to_retain), (hb_codepoint_t) 0) 588 | hb_sink (new_to_old_gid_list) 589 ; 590 *num_glyphs = new_to_old_gid_list->length; 591 } 592 else 593 { 594 + hb_iter (all_gids_to_retain) 595 | hb_map ([] (hb_codepoint_t _) { 596 return hb_codepoint_pair_t (_, _); 597 }) 598 | hb_sink (new_to_old_gid_list) 599 ; 600 601 hb_codepoint_t max_glyph = HB_SET_VALUE_INVALID; 602 hb_set_previous (all_gids_to_retain, &max_glyph); 603 604 *num_glyphs = max_glyph + 1; 605 } 606 607 reverse_glyph_map->alloc (reverse_glyph_map->get_population () + new_to_old_gid_list->length); 608 + hb_iter (new_to_old_gid_list) 609 | hb_sink (reverse_glyph_map) 610 ; 611 glyph_map->alloc (glyph_map->get_population () + new_to_old_gid_list->length); 612 + hb_iter (new_to_old_gid_list) 613 | hb_map (&hb_codepoint_pair_t::reverse) 614 | hb_sink (glyph_map) 615 ; 616 617 return true; 618 } 619 620 hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, 621 const hb_subset_input_t *input) 622 { 623 successful = true; 624 flags = input->flags; 625 626 unicode_to_new_gid_list.init (); 627 628 name_ids = *input->sets.name_ids; 629 name_languages = *input->sets.name_languages; 630 layout_features = *input->sets.layout_features; 631 layout_scripts = *input->sets.layout_scripts; 632 glyphs_requested = *input->sets.glyphs; 633 drop_tables = *input->sets.drop_tables; 634 no_subset_tables = *input->sets.no_subset_tables; 635 source = hb_face_reference (face); 636 dest = hb_face_builder_create (); 637 638 codepoint_to_glyph = hb_map_create (); 639 glyph_map = hb_map_create (); 640 reverse_glyph_map = hb_map_create (); 641 642 gsub_insert_catch_all_feature_variation_rec = false; 643 gpos_insert_catch_all_feature_variation_rec = false; 644 gdef_varstore_inner_maps.init (); 645 646 user_axes_location = input->axes_location; 647 all_axes_pinned = false; 648 pinned_at_default = true; 649 has_gdef_varstore = false; 650 651 #ifdef HB_EXPERIMENTAL_API 652 for (auto _ : input->name_table_overrides) 653 { 654 hb_bytes_t name_bytes = _.second; 655 unsigned len = name_bytes.length; 656 char *name_str = (char *) hb_malloc (len); 657 if (unlikely (!check_success (name_str))) 658 break; 659 660 hb_memcpy (name_str, name_bytes.arrayZ, len); 661 name_table_overrides.set (_.first, hb_bytes_t (name_str, len)); 662 } 663 #endif 664 665 void* accel = hb_face_get_user_data(face, hb_subset_accelerator_t::user_data_key()); 666 667 attach_accelerator_data = input->attach_accelerator_data; 668 force_long_loca = input->force_long_loca; 669 #ifdef HB_EXPERIMENTAL_API 670 force_long_loca = force_long_loca || (flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS); 671 #endif 672 673 if (accel) 674 accelerator = (hb_subset_accelerator_t*) accel; 675 676 if (unlikely (in_error ())) 677 return; 678 679 #ifndef HB_NO_VAR 680 if (!check_success (normalize_axes_location (face, this))) 681 return; 682 #endif 683 684 _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, this); 685 686 _populate_gids_to_retain (this, input->sets.drop_tables); 687 if (unlikely (in_error ())) 688 return; 689 690 if (!check_success(_create_old_gid_to_new_gid_map( 691 face, 692 input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS, 693 &_glyphset, 694 &input->glyph_map, 695 glyph_map, 696 reverse_glyph_map, 697 &new_to_old_gid_list, 698 &_num_output_glyphs))) { 699 return; 700 } 701 702 #ifdef HB_EXPERIMENTAL_API 703 if ((input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS) && 704 (input->flags & HB_SUBSET_FLAGS_RETAIN_NUM_GLYPHS)) { 705 // We've been requested to maintain the num glyphs count from the 706 // input face. 707 _num_output_glyphs = source->get_num_glyphs (); 708 } 709 #endif 710 711 _create_glyph_map_gsub ( 712 &_glyphset_gsub, 713 glyph_map, 714 &glyph_map_gsub); 715 716 // Now that we have old to new gid map update the unicode to new gid list. 717 for (unsigned i = 0; i < unicode_to_new_gid_list.length; i++) 718 { 719 // Use raw array access for performance. 720 unicode_to_new_gid_list.arrayZ[i].second = 721 glyph_map->get(unicode_to_new_gid_list.arrayZ[i].second); 722 } 723 724 bounds_width_vec.resize_dirty (_num_output_glyphs); 725 for (auto &v : bounds_width_vec) 726 v = 0xFFFFFFFF; 727 bounds_height_vec.resize_dirty (_num_output_glyphs); 728 for (auto &v : bounds_height_vec) 729 v = 0xFFFFFFFF; 730 731 #ifndef HB_NO_SUBSET_LAYOUT 732 if (!drop_tables.has (HB_OT_TAG_GDEF)) 733 remap_used_mark_sets (this, used_mark_sets_map); 734 #endif 735 736 #ifndef HB_NO_VAR 737 #ifndef HB_NO_BASE 738 if (!drop_tables.has (HB_OT_TAG_BASE)) 739 collect_base_variation_indices (this); 740 #endif 741 #endif 742 743 if (unlikely (in_error ())) 744 return; 745 746 #ifndef HB_NO_VAR 747 update_instance_metrics_map_from_cff2 (this); 748 if (!check_success (get_instance_glyphs_contour_points (this))) 749 return; 750 #endif 751 752 if (attach_accelerator_data) 753 { 754 inprogress_accelerator = 755 hb_subset_accelerator_t::create (source, 756 *codepoint_to_glyph, 757 unicodes, 758 has_seac); 759 760 check_success (inprogress_accelerator); 761 } 762 763 #define HB_SUBSET_PLAN_MEMBER(Type, Name) check_success (!Name.in_error ()); 764 #include "hb-subset-plan-member-list.hh" 765 #undef HB_SUBSET_PLAN_MEMBER 766 } 767 768 hb_subset_plan_t::~hb_subset_plan_t() 769 { 770 hb_face_destroy (dest); 771 772 hb_map_destroy (codepoint_to_glyph); 773 hb_map_destroy (glyph_map); 774 hb_map_destroy (reverse_glyph_map); 775 #ifndef HB_NO_SUBSET_CFF 776 cff1_accel.fini (); 777 cff2_accel.fini (); 778 #endif 779 hb_face_destroy (source); 780 781 #ifdef HB_EXPERIMENTAL_API 782 for (auto _ : name_table_overrides.iter_ref ()) 783 _.second.fini (); 784 #endif 785 786 if (inprogress_accelerator) 787 hb_subset_accelerator_t::destroy ((void*) inprogress_accelerator); 788 } 789 790 791 /** 792 * hb_subset_plan_create_or_fail: 793 * @face: font face to create the plan for. 794 * @input: a #hb_subset_input_t input. 795 * 796 * Computes a plan for subsetting the supplied face according 797 * to a provided input. The plan describes 798 * which tables and glyphs should be retained. 799 * 800 * Return value: (transfer full): New subset plan. Destroy with 801 * hb_subset_plan_destroy(). If there is a failure creating the plan 802 * nullptr will be returned. 803 * 804 * Since: 4.0.0 805 **/ 806 hb_subset_plan_t * 807 hb_subset_plan_create_or_fail (hb_face_t *face, 808 const hb_subset_input_t *input) 809 { 810 hb_subset_plan_t *plan; 811 if (unlikely (!(plan = hb_object_create<hb_subset_plan_t> (face, input)))) 812 return nullptr; 813 814 if (unlikely (plan->in_error ())) 815 { 816 hb_subset_plan_destroy (plan); 817 return nullptr; 818 } 819 820 return plan; 821 } 822 823 /** 824 * hb_subset_plan_destroy: 825 * @plan: a #hb_subset_plan_t 826 * 827 * Decreases the reference count on @plan, and if it reaches zero, destroys 828 * @plan, freeing all memory. 829 * 830 * Since: 4.0.0 831 **/ 832 void 833 hb_subset_plan_destroy (hb_subset_plan_t *plan) 834 { 835 if (!hb_object_destroy (plan)) return; 836 837 hb_free (plan); 838 } 839 840 /** 841 * hb_subset_plan_old_to_new_glyph_mapping: 842 * @plan: a subsetting plan. 843 * 844 * Returns the mapping between glyphs in the original font to glyphs in the 845 * subset that will be produced by @plan 846 * 847 * Return value: (transfer none): 848 * A pointer to the #hb_map_t of the mapping. 849 * 850 * Since: 4.0.0 851 **/ 852 hb_map_t * 853 hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan) 854 { 855 return plan->glyph_map; 856 } 857 858 /** 859 * hb_subset_plan_new_to_old_glyph_mapping: 860 * @plan: a subsetting plan. 861 * 862 * Returns the mapping between glyphs in the subset that will be produced by 863 * @plan and the glyph in the original font. 864 * 865 * Return value: (transfer none): 866 * A pointer to the #hb_map_t of the mapping. 867 * 868 * Since: 4.0.0 869 **/ 870 hb_map_t * 871 hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan) 872 { 873 return plan->reverse_glyph_map; 874 } 875 876 /** 877 * hb_subset_plan_unicode_to_old_glyph_mapping: 878 * @plan: a subsetting plan. 879 * 880 * Returns the mapping between codepoints in the original font and the 881 * associated glyph id in the original font. 882 * 883 * Return value: (transfer none): 884 * A pointer to the #hb_map_t of the mapping. 885 * 886 * Since: 4.0.0 887 **/ 888 hb_map_t * 889 hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan) 890 { 891 return plan->codepoint_to_glyph; 892 } 893 894 /** 895 * hb_subset_plan_reference: (skip) 896 * @plan: a #hb_subset_plan_t object. 897 * 898 * Increases the reference count on @plan. 899 * 900 * Return value: @plan. 901 * 902 * Since: 4.0.0 903 **/ 904 hb_subset_plan_t * 905 hb_subset_plan_reference (hb_subset_plan_t *plan) 906 { 907 return hb_object_reference (plan); 908 } 909 910 /** 911 * hb_subset_plan_set_user_data: (skip) 912 * @plan: a #hb_subset_plan_t object. 913 * @key: The user-data key to set 914 * @data: A pointer to the user data 915 * @destroy: (nullable): A callback to call when @data is not needed anymore 916 * @replace: Whether to replace an existing data with the same key 917 * 918 * Attaches a user-data key/data pair to the given subset plan object. 919 * 920 * Return value: `true` if success, `false` otherwise 921 * 922 * Since: 4.0.0 923 **/ 924 hb_bool_t 925 hb_subset_plan_set_user_data (hb_subset_plan_t *plan, 926 hb_user_data_key_t *key, 927 void *data, 928 hb_destroy_func_t destroy, 929 hb_bool_t replace) 930 { 931 return hb_object_set_user_data (plan, key, data, destroy, replace); 932 } 933 934 /** 935 * hb_subset_plan_get_user_data: (skip) 936 * @plan: a #hb_subset_plan_t object. 937 * @key: The user-data key to query 938 * 939 * Fetches the user data associated with the specified key, 940 * attached to the specified subset plan object. 941 * 942 * Return value: (transfer none): A pointer to the user data 943 * 944 * Since: 4.0.0 945 **/ 946 void * 947 hb_subset_plan_get_user_data (const hb_subset_plan_t *plan, 948 hb_user_data_key_t *key) 949 { 950 return hb_object_get_user_data (plan, key); 951 }