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