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

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: Update per code review 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 "third_party/sfntly/src/subsetter/subsetter_impl.h"
18
19 #include <string.h>
20
21 #include <map>
22 #include <set>
23
24 #include "third_party/sfntly/src/sfntly/glyph_table.h"
25 #include "third_party/sfntly/src/sfntly/loca_table.h"
26 #include "third_party/sfntly/src/sfntly/name_table.h"
27 #include "third_party/sfntly/src/sfntly/tag.h"
28 #include "third_party/sfntly/src/sfntly/data/memory_byte_array.h"
29 #include "third_party/sfntly/src/sfntly/port/memory_output_stream.h"
30
31 namespace sfntly {
32
33 void ConstructName(UChar* name_part, UnicodeString* name, int32_t name_id) {
34 switch(name_id) {
35 case NameId::kFullFontName:
36 *name = name_part;
37 break;
38 case NameId::kFontFamilyName:
39 case NameId::kPreferredFamily:
40 case NameId::kWWSFamilyName: {
41 UnicodeString original = *name;
42 *name = name_part;
43 *name += original;
44 break;
45 }
46 case NameId::kFontSubfamilyName:
47 case NameId::kPreferredSubfamily:
48 case NameId::kWWSSubfamilyName:
49 *name += name_part;
50 break;
51 default:
52 break;
Sheridan Rawlins 2011/07/20 01:48:00 nit: should have NOTREACHED();
arthurhsu 2011/07/20 02:07:06 Can't do that. The dependency is chrome->skia->sf
Sheridan Rawlins 2011/07/20 14:40:53 Got it - external code. Then please revert to goo
Sheridan Rawlins 2011/07/20 14:42:16 assert(false) that is :) http://google-styleguide
vandebo (ex-Chrome) 2011/07/20 16:29:59 This code get compiled into the sfntly library? I
arthurhsu 2011/07/20 16:57:07 Actually, this is a valid case since font carries
53 }
54 }
55
56 int32_t HashCode(int32_t platform_id, int32_t encoding_id, int32_t language_id,
57 int32_t name_id) {
58 int32_t result = platform_id << 24 | encoding_id << 16 | language_id << 8;
59 if (name_id == NameId::kFullFontName) {
60 result |= 0xff;
61 } else if (name_id == NameId::kPreferredFamily ||
62 name_id == NameId::kPreferredSubfamily) {
63 result |= 0xf;
64 } else if (name_id == NameId::kWWSFamilyName ||
65 name_id == NameId::kWWSSubfamilyName) {
66 result |= 1;
67 }
68 return result;
69 }
70
71 SubsetterImpl::SubsetterImpl() {
72 }
73
74 SubsetterImpl::~SubsetterImpl() {
75 }
76
77 bool SubsetterImpl::LoadFont(const char* font_name,
78 const unsigned char* original_font,
79 size_t font_size) {
80 ByteArrayPtr raw_font =
81 new MemoryByteArray((byte_t*)original_font, font_size);
82 if (factory_ == NULL) {
83 factory_.attach(FontFactory::getInstance());
84 }
85
86 FontArray font_array;
87 factory_->loadFonts(raw_font, &font_array);
88 font_ = FindFont(font_name, font_array);
89 if (font_ == NULL) {
90 return false;
91 }
92
93 return true;
94 }
95
96 int SubsetterImpl::SubsetFont(const unsigned int* glyph_ids,
97 size_t glyph_count,
98 unsigned char** output_buffer) {
99 if (factory_ == NULL || font_ == NULL) {
100 return -1;
101 }
102
103 FontPtr new_font;
104 new_font.attach(Subset(glyph_ids, glyph_count));
105 if (new_font == NULL) {
106 return 0;
107 }
108
109 MemoryOutputStream output_stream;
110 factory_->serializeFont(new_font, &output_stream);
111 int length = static_cast<int>(output_stream.size());
112 if (length > 0) {
113 *output_buffer = new unsigned char[length];
114 memcpy(*output_buffer, output_stream.get(), length);
115 }
116
117 return length;
118 }
119
120 Font* SubsetterImpl::FindFont(const char* font_name,
121 const FontArray& font_array) {
122 if (font_array.empty() || font_array[0] == NULL) {
123 return NULL;
124 }
125
126 if (font_name && strlen(font_name)) {
127 for (FontArray::const_iterator b = font_array.begin(), e = font_array.end();
128 b != e; ++b) {
129 if (HasName(font_name, (*b).p_)) {
130 return (*b).p_;
131 }
132 }
133 }
134
135 return font_array[0].p_;
136 }
137
138 bool SubsetterImpl::HasName(const char* font_name, Font* font) {
139 UnicodeString font_string = UnicodeString::fromUTF8(font_name);
140 if (font_string.isEmpty())
141 return false;
142 UnicodeString regular_suffix = UnicodeString::fromUTF8(" Regular");
143 UnicodeString alt_font_string = font_string;
144 alt_font_string += regular_suffix;
145
146 typedef std::map<int32_t, UnicodeString> NameMap;
147 NameMap names;
148 NameTablePtr name_table = down_cast<NameTable*>(font->table(Tag::name));
149
150 for (int32_t i = 0; i < name_table->nameCount(); ++i) {
151 switch(name_table->nameId(i)) {
152 case NameId::kFontFamilyName:
153 case NameId::kFontSubfamilyName:
154 case NameId::kFullFontName:
155 case NameId::kPreferredFamily:
156 case NameId::kPreferredSubfamily:
157 case NameId::kWWSFamilyName:
158 case NameId::kWWSSubfamilyName: {
159 int32_t hash_code = HashCode(name_table->platformId(i),
160 name_table->encodingId(i),
161 name_table->languageId(i),
162 name_table->nameId(i));
163 UChar* name_part = name_table->name(i);
164 ConstructName(name_part, &(names[hash_code]), name_table->nameId(i));
165 break;
166 }
167 default:
168 break;
169 }
170 }
171
172 if (!names.empty()) {
173 for (NameMap::iterator b = names.begin(), e = names.end(); b != e; ++b) {
174 if (b->second.caseCompare(font_string, 0) == 0 ||
175 b->second.caseCompare(alt_font_string, 0) == 0) {
176 return true;
177 }
178 }
179 }
180 return false;
181 }
182
183 CALLER_ATTACH Font* SubsetterImpl::Subset(const unsigned int* glyph_ids,
184 size_t glyph_count) {
185 if (glyph_ids == NULL || glyph_count == 0) {
186 return NULL;
187 }
188
189 // Find glyf and loca table.
190 GlyphTablePtr glyph_table = down_cast<GlyphTable*>(font_->table(Tag::glyf));
191 LocaTablePtr loca_table = down_cast<LocaTable*>(font_->table(Tag::loca));
192 if (glyph_table == NULL || loca_table == NULL) {
193 // The font is invalid.
194 return NULL;
195 }
196
197 // Setup font builders we need.
198 FontBuilderPtr font_builder;
199 font_builder.attach(factory_->newFontBuilder());
200
201 GlyphTableBuilderPtr glyph_table_builder;
202 glyph_table_builder.attach(down_cast<GlyphTable::Builder*>(
203 font_builder->newTableBuilder(Tag::glyf)));
204 LocaTableBuilderPtr loca_table_builder;
205 loca_table_builder.attach(down_cast<LocaTable::Builder*>(
206 font_builder->newTableBuilder(Tag::loca)));
207 if (glyph_table_builder == NULL || loca_table_builder == NULL) {
208 // Out of memory.
209 return NULL;
210 }
211
212 // Sort and uniquify glyph ids.
213 IntegerSet glyph_id_set;
214 glyph_id_set.insert(0); // Always include glyph id 0.
215 for (size_t i = 0; i < glyph_count; ++i) {
216 glyph_id_set.insert(glyph_ids[i]);
217 }
218
219 // Extract glyphs and setup loca list.
220 IntegerList loca_list;
221 loca_list.resize(loca_table->numGlyphs());
222 loca_list.push_back(0);
223 int32_t last_glyph_id = 0;
224 int32_t last_offset = 0;
225 GlyphTable::GlyphBuilderList* glyph_builders =
226 glyph_table_builder->glyphBuilders();
227 for (IntegerSet::iterator i = glyph_id_set.begin(), e = glyph_id_set.end();
228 i != e; ++i) {
229 if (*i < 0 || *i >= loca_table->numGlyphs()) {
230 // Invalid glyph id, ignore.
231 continue;
232 }
233
234 int32_t length = loca_table->glyphLength(*i);
235 if (length == 0) {
236 // Empty glyph, ignore.
237 continue;
238 }
239 int32_t offset = loca_table->glyphOffset(*i);
240
241 GlyphPtr glyph;
242 glyph.attach(glyph_table->glyph(offset, length));
243 if (glyph == NULL) {
244 // Error finding glyph, ignore.
245 continue;
246 }
247
248 // Add glyph to new glyf table.
249 ReadableFontDataPtr data = glyph->readFontData();
250 WritableFontDataPtr copy_data;
251 copy_data.attach(font_builder->getNewData(data->length()));
252 data->copyTo(copy_data);
253 GlyphBuilderPtr glyph_builder;
254 glyph_builder.attach(glyph_table_builder->glyphBuilder(copy_data));
255 glyph_builders->push_back(glyph_builder);
256
257 // Configure loca list.
258 for (int32_t j = last_glyph_id + 1; j <= *i; ++j) {
259 loca_list[j] = last_offset;
260 }
261 last_offset += length;
262 loca_list[*i + 1] = last_offset;
263 last_glyph_id = *i;
264 }
265 for (int32_t j = last_glyph_id + 1; j <= loca_table->numGlyphs(); ++j) {
266 loca_list[j] = last_offset;
267 }
268 loca_table_builder->setLocaList(&loca_list);
269
270 // Setup remaining builders.
271 for (TableMap::iterator i = font_->tables()->begin(),
272 e = font_->tables()->end(); i != e; ++i) {
273 // We already build the builder for glyph and loca.
274 if (i->first != Tag::glyf && i->first != Tag::loca) {
275 // The newTableBuilder() call will alter internal state of font_builder
276 // AND the reference count of returned object. Therefore we need to
277 // dereference it.
278 TableBuilderPtr dereference;
279 dereference.attach(
280 font_builder->newTableBuilder(i->first, i->second->readFontData()));
281 }
282 }
283
284 return font_builder->build();
285 }
286
287 } // namespace sfntly
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698