Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(549)

Side by Side Diff: third_party/sfntly/src/subsetter/subsetter_impl.cc

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

Powered by Google App Engine
This is Rietveld 408576698