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