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