Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 #include <map> | |
| 20 #include <set> | |
| 21 | |
| 22 #include "subsetter_impl.h" | |
|
brettw
2011/07/19 21:00:33
Ditto on the include paths. And this include shoul
arthurhsu
2011/07/20 01:14:19
Done.
| |
| 23 | |
| 24 #include "sfntly/glyph_table.h" | |
| 25 #include "sfntly/loca_table.h" | |
| 26 #include "sfntly/name_table.h" | |
| 27 #include "sfntly/tag.h" | |
| 28 #include "sfntly/data/memory_byte_array.h" | |
| 29 #include "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; | |
| 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 | |
| OLD | NEW |