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