LCOV - code coverage report
Current view: top level - gfx/sfntly/cpp/src/sample/chromium - subsetter_impl.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 373 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13