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

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

Issue 7381004: Add sfntly library for font subsetting used in print preview. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Created 9 years, 5 months 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
OLDNEW
(Empty)
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 <string.h>
18
19 // Must include this file before unistr.h to avoid compilation issue in VS2008.
20 #include "sfntly/port/type.h"
21
22 #include <unicode/ustring.h>
23 #include <unicode/unistr.h>
24
25 #include <map>
26 #include <set>
27
28 #include "subsetter_impl.h"
Sheridan Rawlins 2011/07/14 22:35:51 This should be first. See http://google-styleguid
arthurhsu 2011/07/14 23:52:35 standard order is C library, C++ library, other li
Sheridan Rawlins 2011/07/15 01:19:07 Standard order starts with the header for this imp
arthurhsu 2011/07/20 01:14:19 Done.
29
30 #include "sfntly/glyph_table.h"
31 #include "sfntly/loca_table.h"
32 #include "sfntly/name_table.h"
33 #include "sfntly/tag.h"
34 #include "sfntly/data/memory_byte_array.h"
35 #include "sfntly/port/memory_output_stream.h"
36
37 #if defined U_USING_ICU_NAMESPACE
38 U_NAMESPACE_USE
39 #endif
40
41 namespace sfntly {
42
43 void constructName(UChar* name_part, UnicodeString* name, int32_t name_id) {
44 switch(name_id) {
45 case NameId::kFullFontName:
46 *name = name_part;
47 break;
48 case NameId::kFontFamilyName:
49 case NameId::kPreferredFamily:
50 case NameId::kWWSFamilyName: {
51 UnicodeString original = *name;
52 *name = name_part;
53 *name += original;
54 }
55 break;
56 case NameId::kFontSubfamilyName:
57 case NameId::kPreferredSubfamily:
58 case NameId::kWWSSubfamilyName:
59 *name += name_part;
60 break;
61 default:
62 break;
63 }
64 }
65
66 int32_t hashCode(int32_t platform_id, int32_t encoding_id, int32_t language_id,
67 int32_t name_id) {
68 int32_t result = platform_id << 24 | encoding_id << 16 | language_id << 8;
69 if (name_id == NameId::kFullFontName) {
70 result |= 0xff;
71 } else if (name_id == NameId::kPreferredFamily ||
72 name_id == NameId::kPreferredSubfamily) {
73 result |= 0xf;
74 } else if (name_id == NameId::kWWSFamilyName ||
75 name_id == NameId::kWWSSubfamilyName) {
76 result |= 1;
77 }
78 return result;
79 }
80
81 SubsetterImpl::SubsetterImpl() {
82 }
83
84 SubsetterImpl::~SubsetterImpl() {
85 }
86
87 bool SubsetterImpl::loadFont(const char* font_name,
88 const unsigned char* original_font,
89 const size_t font_size) {
90 ByteArrayPtr raw_font =
91 new MemoryByteArray((byte_t*)original_font, font_size);
92 if (factory_ == NULL) {
93 factory_.attach(FontFactory::getInstance());
94 }
95
96 FontArray font_array;
97 factory_->loadFonts(raw_font, &font_array);
98 font_ = findFont(font_name, font_array);
99 if (font_ == NULL) {
100 return false;
101 }
102
103 return true;
104 }
105
106 int SubsetterImpl::subsetFont(const unsigned int* glyph_ids,
107 const size_t glyph_count,
108 unsigned char** output_buffer) {
109 if (factory_ == NULL || font_ == NULL) {
110 return -1;
111 }
112
113 FontPtr new_font;
114 new_font.attach(subset(glyph_ids, glyph_count));
115 if (new_font == NULL) {
116 return 0;
117 }
118
119 MemoryOutputStream output_stream;
120 factory_->serializeFont(new_font, &output_stream);
121 int length = (int)output_stream.size();
122 if (length > 0) {
123 *output_buffer = new unsigned char[length];
124 memcpy(*output_buffer, output_stream.get(), length);
125 }
126
127 return length;
128 }
129
130 Font* SubsetterImpl::findFont(const char* font_name, 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::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);
149 if (font_string.isEmpty())
150 return false;
151 UnicodeString regular_suffix = UnicodeString::fromUTF8(" Regular");
152 UnicodeString alt_font_string = font_string;
153 alt_font_string += regular_suffix;
154
155 typedef std::map<int32_t, UnicodeString> NameMap;
156 NameMap names;
157 NameTablePtr name_table = down_cast<NameTable*>(font->table(Tag::name));
158
159 for (int32_t i = 0; i < name_table->nameCount(); ++i) {
160 switch(name_table->nameId(i)) {
161 case NameId::kFontFamilyName:
162 case NameId::kFontSubfamilyName:
163 case NameId::kFullFontName:
164 case NameId::kPreferredFamily:
165 case NameId::kPreferredSubfamily:
166 case NameId::kWWSFamilyName:
167 case NameId::kWWSSubfamilyName: {
168 int32_t hash_code = hashCode(name_table->platformId(i),
169 name_table->encodingId(i),
170 name_table->languageId(i),
171 name_table->nameId(i));
172 UChar* name_part = name_table->name(i);
173 constructName(name_part, &(names[hash_code]), name_table->nameId(i));
174 }
175 break;
176 default:
177 break;
178 }
179 }
180
181 if (!names.empty()) {
182 for (NameMap::iterator b = names.begin(), e = names.end(); b != e; ++b) {
183 if (b->second.caseCompare(font_string, 0) == 0 ||
184 b->second.caseCompare(alt_font_string, 0) == 0) {
185 return true;
186 }
187 }
188 }
189 return false;
190 }
191
192 CALLER_ATTACH Font* SubsetterImpl::subset(const unsigned int* glyph_ids,
193 const size_t glyph_count) {
194 if (glyph_ids == NULL || glyph_count == 0) {
195 return NULL;
196 }
197
198 // Find glyf and loca table.
199 GlyphTablePtr glyph_table = down_cast<GlyphTable*>(font_->table(Tag::glyf));
200 LocaTablePtr loca_table = down_cast<LocaTable*>(font_->table(Tag::loca));
201 if (glyph_table == NULL || loca_table == NULL) {
202 // The font is invalid.
203 return NULL;
204 }
205
206 // Setup font builders we need.
207 FontBuilderPtr font_builder;
208 font_builder.attach(factory_->newFontBuilder());
209
210 GlyphTableBuilderPtr glyph_table_builder;
211 glyph_table_builder.attach(down_cast<GlyphTable::Builder*>(
212 font_builder->newTableBuilder(Tag::glyf)));
213 LocaTableBuilderPtr loca_table_builder;
214 loca_table_builder.attach(down_cast<LocaTable::Builder*>(
215 font_builder->newTableBuilder(Tag::loca)));
216 if (glyph_table_builder == NULL || loca_table_builder == NULL) {
217 // Out of memory.
218 return NULL;
219 }
220
221 // Sort and uniquify glyph ids.
222 IntegerSet glyph_id_set;
223 glyph_id_set.insert(0); // always include glyph id 0
224 for (size_t i = 0; i < glyph_count; ++i) {
225 glyph_id_set.insert(glyph_ids[i]);
226 }
227
228 // Extract glyphs and setup loca list.
229 IntegerList loca_list;
230 loca_list.resize(loca_table->numLocas());
231 loca_list.push_back(0);
232 int32_t last_glyph_id = 0;
233 int32_t last_offset = 0;
234 GlyphTable::GlyphBuilderList* glyph_builders =
235 glyph_table_builder->glyphBuilders();
236 for (IntegerSet::iterator i = glyph_id_set.begin(), e = glyph_id_set.end();
237 i != e; ++i) {
238 if (*i < 0 || *i >= loca_table->numGlyphs()) {
239 // Invalid glyph id, ignore.
240 continue;
241 }
242
243 int32_t length = loca_table->glyphLength(*i);
244 if (length == 0) {
245 // Empty glyph, ignore.
246 continue;
247 }
248 int32_t offset = loca_table->glyphOffset(*i);
249
250 GlyphPtr glyph;
251 glyph.attach(glyph_table->glyph(offset, length));
252 if (glyph == NULL) {
253 // Error finding glyph, ignore.
254 continue;
255 }
256
257 // Add glyph to new glyf table.
258 ReadableFontDataPtr data = glyph->readFontData();
259 WritableFontDataPtr copy_data;
260 copy_data.attach(font_builder->getNewData(data->length()));
261 data->copyTo(copy_data);
262 GlyphBuilderPtr glyph_builder;
263 glyph_builder.attach(glyph_table_builder->glyphBuilder(copy_data));
264 glyph_builders->push_back(glyph_builder);
265
266 // Configure loca list.
267 for (int32_t j = last_glyph_id + 1; j <= *i; ++j) {
268 loca_list[j] = last_offset;
269 }
270 last_offset = offset;
271 loca_list[*i + 1] = offset;
272 last_glyph_id = *i;
273 }
274 for (int32_t j = last_glyph_id + 1; j <= loca_table->numGlyphs(); ++j) {
275 loca_list[j] = last_offset;
276 }
277 loca_table_builder->setLocaList(&loca_list);
278
279 // Setup remaining builders.
280 for (TableMap::iterator i = font_->tables()->begin(),
281 e = font_->tables()->end(); i != e; ++i) {
282 // We already build the builder for glyph and loca.
283 if (i->first != Tag::glyf && i->first != Tag::loca) {
284 // The newTableBuilder() call will alter internal state of font_builder
285 // AND the reference count of returned object. Therefore we need to
286 // dereference it.
287 TableBuilderPtr dereference;
288 dereference.attach(
289 font_builder->newTableBuilder(i->first, i->second->readFontData()));
290 }
291 }
292
293 return font_builder->build();
294 }
295
296 } // namespace sfntly
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698