1 /* 2 * Copyright 2011 Google Inc. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "subsetter_impl.h" 18 19 #include <string.h> 20 21 #include <algorithm> 22 #include <iterator> 23 #include <map> 24 #include <set> 25 26 #include "sfntly/table/bitmap/eblc_table.h" 27 #include "sfntly/table/bitmap/ebdt_table.h" 28 #include "sfntly/table/bitmap/index_sub_table.h" 29 #include "sfntly/table/bitmap/index_sub_table_format1.h" 30 #include "sfntly/table/bitmap/index_sub_table_format2.h" 31 #include "sfntly/table/bitmap/index_sub_table_format3.h" 32 #include "sfntly/table/bitmap/index_sub_table_format4.h" 33 #include "sfntly/table/bitmap/index_sub_table_format5.h" 34 #include "sfntly/table/core/name_table.h" 35 #include "sfntly/tag.h" 36 #include "sfntly/data/memory_byte_array.h" 37 #include "sfntly/port/memory_input_stream.h" 38 #include "sfntly/port/memory_output_stream.h" 39 40 #if defined U_USING_ICU_NAMESPACE 41 U_NAMESPACE_USE 42 #endif 43 44 namespace { 45 46 using namespace sfntly; 47 48 // The bitmap tables must be greater than 16KB to trigger bitmap subsetter. 49 static const int BITMAP_SIZE_THRESHOLD = 16384; 50 51 void ConstructName(UChar* name_part, UnicodeString* name, int32_t name_id) { 52 switch (name_id) { 53 case NameId::kFullFontName: 54 *name = name_part; 55 break; 56 case NameId::kFontFamilyName: 57 case NameId::kPreferredFamily: 58 case NameId::kWWSFamilyName: { 59 UnicodeString original = *name; 60 *name = name_part; 61 *name += original; 62 break; 63 } 64 case NameId::kFontSubfamilyName: 65 case NameId::kPreferredSubfamily: 66 case NameId::kWWSSubfamilyName: 67 *name += name_part; 68 break; 69 default: 70 // This name part is not used to construct font name (e.g. copyright). 71 // Simply ignore it. 72 break; 73 } 74 } 75 76 int32_t HashCode(int32_t platform_id, int32_t encoding_id, int32_t language_id, 77 int32_t name_id) { 78 int32_t result = platform_id << 24 | encoding_id << 16 | language_id << 8; 79 if (name_id == NameId::kFullFontName) { 80 result |= 0xff; 81 } else if (name_id == NameId::kPreferredFamily || 82 name_id == NameId::kPreferredSubfamily) { 83 result |= 0xf; 84 } else if (name_id == NameId::kWWSFamilyName || 85 name_id == NameId::kWWSSubfamilyName) { 86 result |= 1; 87 } 88 return result; 89 } 90 91 bool HasName(const char* font_name, Font* font) { 92 UnicodeString font_string = UnicodeString::fromUTF8(font_name); 93 if (font_string.isEmpty()) 94 return false; 95 UnicodeString regular_suffix = UnicodeString::fromUTF8(" Regular"); 96 UnicodeString alt_font_string = font_string; 97 alt_font_string += regular_suffix; 98 99 typedef std::map<int32_t, UnicodeString> NameMap; 100 NameMap names; 101 NameTablePtr name_table = down_cast<NameTable*>(font->GetTable(Tag::name)); 102 if (name_table == NULL) { 103 return false; 104 } 105 106 for (int32_t i = 0; i < name_table->NameCount(); ++i) { 107 switch (name_table->NameId(i)) { 108 case NameId::kFontFamilyName: 109 case NameId::kFontSubfamilyName: 110 case NameId::kFullFontName: 111 case NameId::kPreferredFamily: 112 case NameId::kPreferredSubfamily: 113 case NameId::kWWSFamilyName: 114 case NameId::kWWSSubfamilyName: { 115 UChar* name_part = name_table->Name(i); 116 if (name_part == NULL) { 117 continue; 118 } 119 int32_t hash_code = HashCode(name_table->PlatformId(i), 120 name_table->EncodingId(i), 121 name_table->LanguageId(i), 122 name_table->NameId(i)); 123 ConstructName(name_part, &(names[hash_code]), name_table->NameId(i)); 124 delete[] name_part; 125 break; 126 } 127 default: 128 break; 129 } 130 } 131 132 if (!names.empty()) { 133 for (NameMap::iterator i = names.begin(), e = names.end(); i != e; ++i) { 134 if (i->second.caseCompare(font_string, 0) == 0 || 135 i->second.caseCompare(alt_font_string, 0) == 0) { 136 return true; 137 } 138 } 139 } 140 return false; 141 } 142 143 Font* FindFont(const char* font_name, const FontArray& font_array) { 144 if (font_array.empty() || font_array[0] == NULL) { 145 return NULL; 146 } 147 148 if (font_name && strlen(font_name)) { 149 for (FontArray::const_iterator i = font_array.begin(), e = font_array.end(); 150 i != e; ++i) { 151 if (HasName(font_name, i->p_)) { 152 return i->p_; 153 } 154 } 155 } 156 157 return font_array[0].p_; 158 } 159 160 bool ResolveCompositeGlyphs(GlyphTable* glyph_table, 161 LocaTable* loca_table, 162 const unsigned int* glyph_ids, 163 size_t glyph_count, 164 IntegerSet* glyph_id_processed) { 165 if (glyph_table == NULL || loca_table == NULL || 166 glyph_ids == NULL || glyph_count == 0 || glyph_id_processed == NULL) { 167 return false; 168 } 169 170 // Sort and uniquify glyph ids. 171 IntegerSet glyph_id_remaining; 172 glyph_id_remaining.insert(0); // Always include glyph id 0. 173 for (size_t i = 0; i < glyph_count; ++i) { 174 glyph_id_remaining.insert(glyph_ids[i]); 175 } 176 177 // Identify if any given glyph id maps to a composite glyph. If so, include 178 // the glyphs referenced by that composite glyph. 179 while (!glyph_id_remaining.empty()) { 180 IntegerSet comp_glyph_id; 181 for (IntegerSet::iterator i = glyph_id_remaining.begin(), 182 e = glyph_id_remaining.end(); i != e; ++i) { 183 if (*i < 0 || *i >= loca_table->num_glyphs()) { 184 // Invalid glyph id, ignore. 185 continue; 186 } 187 188 int32_t length = loca_table->GlyphLength(*i); 189 if (length == 0) { 190 // Empty glyph, ignore. 191 continue; 192 } 193 int32_t offset = loca_table->GlyphOffset(*i); 194 195 GlyphPtr glyph; 196 glyph.Attach(glyph_table->GetGlyph(offset, length)); 197 if (glyph == NULL) { 198 // Error finding glyph, ignore. 199 continue; 200 } 201 202 if (glyph->GlyphType() == GlyphType::kComposite) { 203 Ptr<GlyphTable::CompositeGlyph> comp_glyph = 204 down_cast<GlyphTable::CompositeGlyph*>(glyph.p_); 205 for (int32_t j = 0; j < comp_glyph->NumGlyphs(); ++j) { 206 int32_t glyph_id = comp_glyph->GlyphIndex(j); 207 if (glyph_id_processed->find(glyph_id) == glyph_id_processed->end() && 208 glyph_id_remaining.find(glyph_id) == glyph_id_remaining.end()) { 209 comp_glyph_id.insert(comp_glyph->GlyphIndex(j)); 210 } 211 } 212 } 213 214 glyph_id_processed->insert(*i); 215 } 216 217 glyph_id_remaining.clear(); 218 glyph_id_remaining = comp_glyph_id; 219 } 220 221 return true; 222 } 223 224 bool SetupGlyfBuilders(Font::Builder* font_builder, 225 GlyphTable* glyph_table, 226 LocaTable* loca_table, 227 const IntegerSet& glyph_ids) { 228 if (!font_builder || !glyph_table || !loca_table) { 229 return false; 230 } 231 232 GlyphTableBuilderPtr glyph_table_builder = 233 down_cast<GlyphTable::Builder*>(font_builder->NewTableBuilder(Tag::glyf)); 234 LocaTableBuilderPtr loca_table_builder = 235 down_cast<LocaTable::Builder*>(font_builder->NewTableBuilder(Tag::loca)); 236 if (glyph_table_builder == NULL || loca_table_builder == NULL) { 237 // Out of memory. 238 return false; 239 } 240 241 // Extract glyphs and setup loca list. 242 IntegerList loca_list; 243 loca_list.resize(loca_table->num_glyphs()); 244 loca_list.push_back(0); 245 int32_t last_glyph_id = 0; 246 int32_t last_offset = 0; 247 GlyphTable::GlyphBuilderList* glyph_builders = 248 glyph_table_builder->GlyphBuilders(); 249 for (IntegerSet::const_iterator i = glyph_ids.begin(), e = glyph_ids.end(); 250 i != e; ++i) { 251 int32_t length = loca_table->GlyphLength(*i); 252 int32_t offset = loca_table->GlyphOffset(*i); 253 254 GlyphPtr glyph; 255 glyph.Attach(glyph_table->GetGlyph(offset, length)); 256 257 // Add glyph to new glyf table. 258 ReadableFontDataPtr data = glyph->ReadFontData(); 259 WritableFontDataPtr copy_data; 260 copy_data.Attach(WritableFontData::CreateWritableFontData(data->Length())); 261 data->CopyTo(copy_data); 262 GlyphBuilderPtr glyph_builder; 263 glyph_builder.Attach(glyph_table_builder->GlyphBuilder(copy_data)); 264 glyph_builders->push_back(glyph_builder); 265 266 // Configure loca list. 267 for (int32_t j = last_glyph_id + 1; j <= *i; ++j) { 268 loca_list[j] = last_offset; 269 } 270 last_offset += length; 271 loca_list[*i + 1] = last_offset; 272 last_glyph_id = *i; 273 } 274 for (int32_t j = last_glyph_id + 1; j <= loca_table->num_glyphs(); ++j) { 275 loca_list[j] = last_offset; 276 } 277 loca_table_builder->SetLocaList(&loca_list); 278 279 return true; 280 } 281 282 bool HasOverlap(int32_t range_begin, int32_t range_end, 283 const IntegerSet& glyph_ids) { 284 if (range_begin == range_end) { 285 return glyph_ids.find(range_begin) != glyph_ids.end(); 286 } else if (range_end > range_begin) { 287 IntegerSet::const_iterator left = glyph_ids.lower_bound(range_begin); 288 IntegerSet::const_iterator right = glyph_ids.lower_bound(range_end); 289 return right != left; 290 } 291 return false; 292 } 293 294 // Initialize builder, returns false if glyph_id subset is not covered. 295 // Not thread-safe, caller to ensure object life-time. 296 bool InitializeBitmapBuilder(EbdtTable::Builder* ebdt, EblcTable::Builder* eblc, 297 const IntegerSet& glyph_ids) { 298 BitmapLocaList loca_list; 299 BitmapSizeTableBuilderList* strikes = eblc->BitmapSizeBuilders(); 300 301 // Note: Do not call eblc_builder->GenerateLocaList(&loca_list) and then 302 // ebdt_builder->SetLoca(loca_list). For fonts like SimSun, there are 303 // >28K glyphs inside, where a typical usage will be <1K glyphs. Doing 304 // the calls improperly will result in creation of >100K objects that 305 // will be destroyed immediately, inducing significant slowness. 306 IntegerList removed_strikes; 307 for (size_t i = 0; i < strikes->size(); i++) { 308 if (!HasOverlap((*strikes)[i]->StartGlyphIndex(), 309 (*strikes)[i]->EndGlyphIndex(), glyph_ids)) { 310 removed_strikes.push_back(i); 311 continue; 312 } 313 314 IndexSubTableBuilderList* index_builders = 315 (*strikes)[i]->IndexSubTableBuilders(); 316 IntegerList removed_indexes; 317 BitmapGlyphInfoMap info_map; 318 for (size_t j = 0; j < index_builders->size(); ++j) { 319 if ((*index_builders)[j] == NULL) { 320 // Subtable is malformed, let's just skip it. 321 removed_indexes.push_back(j); 322 continue; 323 } 324 int32_t first_glyph_id = (*index_builders)[j]->first_glyph_index(); 325 int32_t last_glyph_id = (*index_builders)[j]->last_glyph_index(); 326 if (!HasOverlap(first_glyph_id, last_glyph_id, glyph_ids)) { 327 removed_indexes.push_back(j); 328 continue; 329 } 330 for (IntegerSet::const_iterator gid = glyph_ids.begin(), 331 gid_end = glyph_ids.end(); 332 gid != gid_end; gid++) { 333 if (*gid < first_glyph_id) { 334 continue; 335 } 336 if (*gid > last_glyph_id) { 337 break; 338 } 339 BitmapGlyphInfoPtr info; 340 info.Attach((*index_builders)[j]->GlyphInfo(*gid)); 341 if (info && info->length()) { // Do not include gid without bitmap 342 info_map[*gid] = info; 343 } 344 } 345 } 346 if (!info_map.empty()) { 347 loca_list.push_back(info_map); 348 } else { 349 removed_strikes.push_back(i); // Detected null entries. 350 } 351 352 // Remove unused index sub tables 353 for (IntegerList::reverse_iterator j = removed_indexes.rbegin(), 354 e = removed_indexes.rend(); 355 j != e; j++) { 356 index_builders->erase(index_builders->begin() + *j); 357 } 358 } 359 if (removed_strikes.size() == strikes->size() || loca_list.empty()) { 360 return false; 361 } 362 363 for (IntegerList::reverse_iterator i = removed_strikes.rbegin(), 364 e = removed_strikes.rend(); i != e; i++) { 365 strikes->erase(strikes->begin() + *i); 366 } 367 368 if (strikes->empty()) { // no glyph covered, can safely drop the builders. 369 return false; 370 } 371 372 ebdt->SetLoca(&loca_list); 373 ebdt->GlyphBuilders(); // Initialize the builder. 374 return true; 375 } 376 377 void CopyBigGlyphMetrics(BigGlyphMetrics::Builder* source, 378 BigGlyphMetrics::Builder* target) { 379 target->SetHeight(static_cast<byte_t>(source->Height())); 380 target->SetWidth(static_cast<byte_t>(source->Width())); 381 target->SetHoriBearingX(static_cast<byte_t>(source->HoriBearingX())); 382 target->SetHoriBearingY(static_cast<byte_t>(source->HoriBearingY())); 383 target->SetHoriAdvance(static_cast<byte_t>(source->HoriAdvance())); 384 target->SetVertBearingX(static_cast<byte_t>(source->VertBearingX())); 385 target->SetVertBearingY(static_cast<byte_t>(source->VertBearingY())); 386 target->SetVertAdvance(static_cast<byte_t>(source->VertAdvance())); 387 } 388 389 CALLER_ATTACH IndexSubTable::Builder* 390 ConstructIndexFormat4(IndexSubTable::Builder* b, const BitmapGlyphInfoMap& loca, 391 int32_t* image_data_offset) { 392 IndexSubTableFormat4BuilderPtr builder4; 393 builder4.Attach(IndexSubTableFormat4::Builder::CreateBuilder()); 394 CodeOffsetPairBuilderList offset_pairs; 395 396 size_t offset = 0; 397 int32_t lower_bound = b->first_glyph_index(); 398 int32_t upper_bound = b->last_glyph_index(); 399 int32_t last_gid = -1; 400 BitmapGlyphInfoMap::const_iterator i = loca.lower_bound(lower_bound); 401 BitmapGlyphInfoMap::const_iterator end = loca.end(); 402 if (i != end) { 403 last_gid = i->first; 404 builder4->set_first_glyph_index(last_gid); 405 builder4->set_image_format(b->image_format()); 406 builder4->set_image_data_offset(*image_data_offset); 407 } 408 for (; i != end; i++) { 409 int32_t gid = i->first; 410 if (gid > upper_bound) { 411 break; 412 } 413 offset_pairs.push_back( 414 IndexSubTableFormat4::CodeOffsetPairBuilder(gid, offset)); 415 offset += i->second->length(); 416 last_gid = gid; 417 } 418 offset_pairs.push_back( 419 IndexSubTableFormat4::CodeOffsetPairBuilder(-1, offset)); 420 builder4->set_last_glyph_index(last_gid); 421 *image_data_offset += offset; 422 builder4->SetOffsetArray(offset_pairs); 423 424 return builder4.Detach(); 425 } 426 427 CALLER_ATTACH IndexSubTable::Builder* 428 ConstructIndexFormat5(IndexSubTable::Builder* b, const BitmapGlyphInfoMap& loca, 429 int32_t* image_data_offset) { 430 IndexSubTableFormat5BuilderPtr new_builder; 431 new_builder.Attach(IndexSubTableFormat5::Builder::CreateBuilder()); 432 433 // Copy BigMetrics 434 int32_t image_size = 0; 435 if (b->index_format() == IndexSubTable::Format::FORMAT_2) { 436 IndexSubTableFormat2BuilderPtr builder2 = 437 down_cast<IndexSubTableFormat2::Builder*>(b); 438 CopyBigGlyphMetrics(builder2->BigMetrics(), new_builder->BigMetrics()); 439 image_size = builder2->ImageSize(); 440 } else { 441 IndexSubTableFormat5BuilderPtr builder5 = 442 down_cast<IndexSubTableFormat5::Builder*>(b); 443 BigGlyphMetricsBuilderPtr metrics_builder; 444 CopyBigGlyphMetrics(builder5->BigMetrics(), new_builder->BigMetrics()); 445 image_size = builder5->ImageSize(); 446 } 447 448 IntegerList* glyph_array = new_builder->GlyphArray(); 449 size_t offset = 0; 450 int32_t lower_bound = b->first_glyph_index(); 451 int32_t upper_bound = b->last_glyph_index(); 452 int32_t last_gid = -1; 453 BitmapGlyphInfoMap::const_iterator i = loca.lower_bound(lower_bound); 454 BitmapGlyphInfoMap::const_iterator end = loca.end(); 455 if (i != end) { 456 last_gid = i->first; 457 new_builder->set_first_glyph_index(last_gid); 458 new_builder->set_image_format(b->image_format()); 459 new_builder->set_image_data_offset(*image_data_offset); 460 new_builder->SetImageSize(image_size); 461 } 462 for (; i != end; i++) { 463 int32_t gid = i->first; 464 if (gid > upper_bound) { 465 break; 466 } 467 glyph_array->push_back(gid); 468 offset += i->second->length(); 469 last_gid = gid; 470 } 471 new_builder->set_last_glyph_index(last_gid); 472 *image_data_offset += offset; 473 return new_builder.Detach(); 474 } 475 476 CALLER_ATTACH IndexSubTable::Builder* 477 SubsetIndexSubTable(IndexSubTable::Builder* builder, 478 const BitmapGlyphInfoMap& loca, 479 int32_t* image_data_offset) { 480 switch (builder->index_format()) { 481 case IndexSubTable::Format::FORMAT_1: 482 case IndexSubTable::Format::FORMAT_3: 483 case IndexSubTable::Format::FORMAT_4: 484 return ConstructIndexFormat4(builder, loca, image_data_offset); 485 case IndexSubTable::Format::FORMAT_2: 486 case IndexSubTable::Format::FORMAT_5: 487 return ConstructIndexFormat5(builder, loca, image_data_offset); 488 default: 489 assert(false); 490 break; 491 } 492 return NULL; 493 } 494 495 } 496 497 namespace sfntly { 498 499 // Not thread-safe, caller to ensure object life-time. 500 void SubsetEBLC(EblcTable::Builder* eblc, const BitmapLocaList& new_loca) { 501 BitmapSizeTableBuilderList* size_builders = eblc->BitmapSizeBuilders(); 502 if (size_builders == NULL) { 503 return; 504 } 505 506 int32_t image_data_offset = EbdtTable::Offset::kHeaderLength; 507 for (size_t strike = 0; strike < size_builders->size(); ++strike) { 508 IndexSubTableBuilderList* index_builders = 509 (*size_builders)[strike]->IndexSubTableBuilders(); 510 for (size_t index = 0; index < index_builders->size(); ++index) { 511 IndexSubTable::Builder* new_builder_raw = 512 SubsetIndexSubTable((*index_builders)[index], new_loca[strike], 513 &image_data_offset); 514 if (NULL != new_builder_raw) { 515 (*index_builders)[index].Attach(new_builder_raw); 516 } 517 } 518 } 519 } 520 521 // EBLC structure (from stuartg) 522 // header 523 // bitmapSizeTable[] 524 // one per strike 525 // holds strike metrics - sbitLineMetrics 526 // holds info about indexSubTableArray 527 // indexSubTableArray[][] 528 // one per strike and then one per indexSubTable for that strike 529 // holds info about the indexSubTable 530 // the indexSubTable entries pointed to can be of different formats 531 // indexSubTable 532 // one per indexSubTableArray entry 533 // tells how to get the glyphs 534 // may hold the glyph metrics if they are uniform for all the glyphs in range 535 // Please note that the structure can also be 536 // {indexSubTableArray[], indexSubTables[]}[] 537 // This way is also legal and in fact how Microsoft fonts are laid out. 538 // 539 // There is nothing that says that the indexSubTableArray entries and/or the 540 // indexSubTable items need to be unique. They may be shared between strikes. 541 // 542 // EBDT structure: 543 // header 544 // glyphs 545 // amorphous blob of data 546 // different glyphs that are only able to be figured out from the EBLC table 547 // may hold metrics - depends on the EBLC entry that pointed to them 548 549 // Subsetting EBLC table (from arthurhsu) 550 // Most pages use only a fraction (hundreds or less) glyphs out of a given font 551 // (which can have >20K glyphs for CJK). It's safe to assume that the subset 552 // font will have sparse bitmap glyphs. So we reconstruct the EBLC table as 553 // format 4 or 5 here. 554 555 enum BuildersToRemove { 556 kRemoveNone, 557 kRemoveBDAT, 558 kRemoveBDATAndEBDT, 559 kRemoveEBDT 560 }; 561 562 int SetupBitmapBuilders(Font* font, Font::Builder* font_builder, 563 const IntegerSet& glyph_ids) { 564 if (!font || !font_builder) { 565 return false; 566 } 567 568 // Check if bitmap table exists. 569 EbdtTablePtr ebdt_table = down_cast<EbdtTable*>(font->GetTable(Tag::EBDT)); 570 EblcTablePtr eblc_table = down_cast<EblcTable*>(font->GetTable(Tag::EBLC)); 571 bool use_ebdt = (ebdt_table != NULL && eblc_table != NULL); 572 if (!use_ebdt) { 573 ebdt_table = down_cast<EbdtTable*>(font->GetTable(Tag::bdat)); 574 eblc_table = down_cast<EblcTable*>(font->GetTable(Tag::bloc)); 575 if (ebdt_table == NULL || eblc_table == NULL) { 576 return kRemoveNone; 577 } 578 } 579 580 // If the bitmap table's size is too small, skip subsetting. 581 if (ebdt_table->DataLength() + eblc_table->DataLength() < 582 BITMAP_SIZE_THRESHOLD) { 583 return use_ebdt ? kRemoveBDAT : kRemoveNone; 584 } 585 586 // Get the builders. 587 EbdtTableBuilderPtr ebdt_table_builder = down_cast<EbdtTable::Builder*>( 588 font_builder->NewTableBuilder(use_ebdt ? Tag::EBDT : Tag::bdat, 589 ebdt_table->ReadFontData())); 590 EblcTableBuilderPtr eblc_table_builder = down_cast<EblcTable::Builder*>( 591 font_builder->NewTableBuilder(use_ebdt ? Tag::EBLC : Tag::bloc, 592 eblc_table->ReadFontData())); 593 if (ebdt_table_builder == NULL || eblc_table_builder == NULL) { 594 // Out of memory. 595 return use_ebdt ? kRemoveBDAT : kRemoveNone; 596 } 597 598 if (!InitializeBitmapBuilder(ebdt_table_builder, eblc_table_builder, 599 glyph_ids)) { 600 // Bitmap tables do not cover the glyphs in our subset. 601 font_builder->RemoveTableBuilder(use_ebdt ? Tag::EBLC : Tag::bloc); 602 font_builder->RemoveTableBuilder(use_ebdt ? Tag::EBDT : Tag::bdat); 603 return use_ebdt ? kRemoveBDATAndEBDT : kRemoveEBDT; 604 } 605 606 BitmapLocaList new_loca; 607 ebdt_table_builder->GenerateLocaList(&new_loca); 608 SubsetEBLC(eblc_table_builder, new_loca); 609 610 return use_ebdt ? kRemoveBDAT : kRemoveNone; 611 } 612 613 SubsetterImpl::SubsetterImpl() { 614 } 615 616 SubsetterImpl::~SubsetterImpl() { 617 } 618 619 bool SubsetterImpl::LoadFont(const char* font_name, 620 const unsigned char* original_font, 621 size_t font_size) { 622 MemoryInputStream mis; 623 mis.Attach(original_font, font_size); 624 if (factory_ == NULL) { 625 factory_.Attach(FontFactory::GetInstance()); 626 } 627 628 FontArray font_array; 629 factory_->LoadFonts(&mis, &font_array); 630 font_ = FindFont(font_name, font_array); 631 if (font_ == NULL) { 632 return false; 633 } 634 635 return true; 636 } 637 638 int SubsetterImpl::SubsetFont(const unsigned int* glyph_ids, 639 size_t glyph_count, 640 unsigned char** output_buffer) { 641 if (factory_ == NULL || font_ == NULL) { 642 return -1; 643 } 644 645 // Find glyf and loca table. 646 GlyphTablePtr glyph_table = 647 down_cast<GlyphTable*>(font_->GetTable(Tag::glyf)); 648 LocaTablePtr loca_table = down_cast<LocaTable*>(font_->GetTable(Tag::loca)); 649 if (glyph_table == NULL || loca_table == NULL) { 650 // We are not able to subset the font. 651 return 0; 652 } 653 654 IntegerSet glyph_id_processed; 655 if (!ResolveCompositeGlyphs(glyph_table, loca_table, 656 glyph_ids, glyph_count, &glyph_id_processed) || 657 glyph_id_processed.empty()) { 658 return 0; 659 } 660 661 FontPtr new_font; 662 new_font.Attach(Subset(glyph_id_processed, glyph_table, loca_table)); 663 if (new_font == NULL) { 664 return 0; 665 } 666 667 MemoryOutputStream output_stream; 668 factory_->SerializeFont(new_font, &output_stream); 669 int length = static_cast<int>(output_stream.Size()); 670 if (length > 0) { 671 *output_buffer = new unsigned char[length]; 672 memcpy(*output_buffer, output_stream.Get(), length); 673 } 674 675 return length; 676 } 677 678 // Long comments regarding TTF tables and PDF (from stuartg) 679 // 680 // According to PDF spec 1.4 (section 5.8), the following tables must be 681 // present: 682 // head, hhea, loca, maxp, cvt, prep, glyf, hmtx, fpgm 683 // cmap if font is used with a simple font dict and not a CIDFont dict 684 // 685 // Other tables we need to keep for PDF rendering to support zoom in/out: 686 // bdat, bloc, ebdt, eblc, ebsc, gasp 687 // 688 // Special table: 689 // CFF - if you have this table then you shouldn't have a glyf table and this 690 // is the table with all the glyphs. Shall skip subsetting completely 691 // since sfntly is not capable of subsetting it for now. 692 // post - extra info here for printing on PostScript printers but maybe not 693 // enough to outweigh the space taken by the names 694 // 695 // Tables to break apart: 696 // name - could throw away all but one language and one platform strings/ might 697 // throw away some of the name entries 698 // cmap - could strip out non-needed cmap subtables 699 // - format 4 subtable can be subsetted as well using sfntly 700 // 701 // Graphite tables: 702 // silf, glat, gloc, feat - should be okay to strip out 703 // 704 // Tables that can be discarded: 705 // OS/2 - everything here is for layout and description of the font that is 706 // elsewhere (some in the PDF objects) 707 // BASE, GDEF, GSUB, GPOS, JSTF - all used for layout 708 // kern - old style layout 709 // DSIG - this will be invalid after subsetting 710 // hdmx - layout 711 // PCLT - metadata that's not needed 712 // vmtx - layout 713 // vhea - layout 714 // VDMX 715 // VORG - not used by TT/OT - used by CFF 716 // hsty - would be surprised to see one of these - used on the Newton 717 // AAT tables - mort, morx, feat, acnt, bsin, just, lcar, fdsc, fmtx, prop, 718 // Zapf, opbd, trak, fvar, gvar, avar, cvar 719 // - these are all layout tables and once layout happens are not 720 // needed anymore 721 // LTSH - layout 722 723 CALLER_ATTACH 724 Font* SubsetterImpl::Subset(const IntegerSet& glyph_ids, GlyphTable* glyf, 725 LocaTable* loca) { 726 // The const is initialized here to workaround VC bug of rendering all Tag::* 727 // as 0. These tags represents the TTF tables that we will embed in subset 728 // font. 729 const int32_t TABLES_IN_SUBSET[] = { 730 Tag::head, Tag::hhea, Tag::loca, Tag::maxp, Tag::cvt, 731 Tag::prep, Tag::glyf, Tag::hmtx, Tag::fpgm, Tag::EBDT, 732 Tag::EBLC, Tag::EBSC, Tag::bdat, Tag::bloc, Tag::bhed, 733 Tag::cmap, // Keep here for future tagged PDF development. 734 Tag::name, // Keep here due to legal concerns: copyright info inside. 735 }; 736 737 // Setup font builders we need. 738 FontBuilderPtr font_builder; 739 font_builder.Attach(factory_->NewFontBuilder()); 740 IntegerSet remove_tags; 741 742 if (SetupGlyfBuilders(font_builder, glyf, loca, glyph_ids)) { 743 remove_tags.insert(Tag::glyf); 744 remove_tags.insert(Tag::loca); 745 } 746 747 // For old Apple bitmap fonts, they have only bdats and bhed is identical 748 // to head. As a result, we can't remove bdat tables for those fonts. 749 int setup_result = SetupBitmapBuilders(font_, font_builder, glyph_ids); 750 if (setup_result == kRemoveBDATAndEBDT || setup_result == kRemoveEBDT) { 751 remove_tags.insert(Tag::EBDT); 752 remove_tags.insert(Tag::EBLC); 753 remove_tags.insert(Tag::EBSC); 754 } 755 756 if (setup_result == kRemoveBDAT || setup_result == kRemoveBDATAndEBDT) { 757 remove_tags.insert(Tag::bdat); 758 remove_tags.insert(Tag::bloc); 759 remove_tags.insert(Tag::bhed); 760 } 761 762 IntegerSet allowed_tags; 763 for (size_t i = 0; i < sizeof(TABLES_IN_SUBSET) / sizeof(int32_t); ++i) { 764 allowed_tags.insert(TABLES_IN_SUBSET[i]); 765 } 766 767 IntegerSet result; 768 std::set_difference(allowed_tags.begin(), allowed_tags.end(), 769 remove_tags.begin(), remove_tags.end(), 770 std::inserter(result, result.end())); 771 allowed_tags = result; 772 773 // Setup remaining builders. 774 for (IntegerSet::iterator i = allowed_tags.begin(), e = allowed_tags.end(); 775 i != e; ++i) { 776 Table* table = font_->GetTable(*i); 777 if (table) { 778 font_builder->NewTableBuilder(*i, table->ReadFontData()); 779 } 780 } 781 782 return font_builder->Build(); 783 } 784 785 } // namespace sfntly 786