Chromium Code Reviews| Index: third_party/sfntly/src/subsetter/subsetter_impl.cc |
| diff --git a/third_party/sfntly/src/subsetter/subsetter_impl.cc b/third_party/sfntly/src/subsetter/subsetter_impl.cc |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..1b3d1919e266f01ee90cd36ff0441e41597d2303 |
| --- /dev/null |
| +++ b/third_party/sfntly/src/subsetter/subsetter_impl.cc |
| @@ -0,0 +1,296 @@ |
| +/* |
| + * Copyright 2011 Google Inc. All Rights Reserved. |
| + * |
| + * Licensed under the Apache License, Version 2.0 (the "License"); |
| + * you may not use this file except in compliance with the License. |
| + * You may obtain a copy of the License at |
| + * |
| + * http://www.apache.org/licenses/LICENSE-2.0 |
| + * |
| + * Unless required by applicable law or agreed to in writing, software |
| + * distributed under the License is distributed on an "AS IS" BASIS, |
| + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| + * See the License for the specific language governing permissions and |
| + * limitations under the License. |
| + */ |
| + |
| +#include <string.h> |
| + |
| +// Must include this file before unistr.h to avoid compilation issue in VS2008. |
| +#include "sfntly/port/type.h" |
| + |
| +#include <unicode/ustring.h> |
| +#include <unicode/unistr.h> |
| + |
| +#include <map> |
| +#include <set> |
| + |
| +#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.
|
| + |
| +#include "sfntly/glyph_table.h" |
| +#include "sfntly/loca_table.h" |
| +#include "sfntly/name_table.h" |
| +#include "sfntly/tag.h" |
| +#include "sfntly/data/memory_byte_array.h" |
| +#include "sfntly/port/memory_output_stream.h" |
| + |
| +#if defined U_USING_ICU_NAMESPACE |
| + U_NAMESPACE_USE |
| +#endif |
| + |
| +namespace sfntly { |
| + |
| +void constructName(UChar* name_part, UnicodeString* name, int32_t name_id) { |
| + switch(name_id) { |
| + case NameId::kFullFontName: |
| + *name = name_part; |
| + break; |
| + case NameId::kFontFamilyName: |
| + case NameId::kPreferredFamily: |
| + case NameId::kWWSFamilyName: { |
| + UnicodeString original = *name; |
| + *name = name_part; |
| + *name += original; |
| + } |
| + break; |
| + case NameId::kFontSubfamilyName: |
| + case NameId::kPreferredSubfamily: |
| + case NameId::kWWSSubfamilyName: |
| + *name += name_part; |
| + break; |
| + default: |
| + break; |
| + } |
| +} |
| + |
| +int32_t hashCode(int32_t platform_id, int32_t encoding_id, int32_t language_id, |
| + int32_t name_id) { |
| + int32_t result = platform_id << 24 | encoding_id << 16 | language_id << 8; |
| + if (name_id == NameId::kFullFontName) { |
| + result |= 0xff; |
| + } else if (name_id == NameId::kPreferredFamily || |
| + name_id == NameId::kPreferredSubfamily) { |
| + result |= 0xf; |
| + } else if (name_id == NameId::kWWSFamilyName || |
| + name_id == NameId::kWWSSubfamilyName) { |
| + result |= 1; |
| + } |
| + return result; |
| +} |
| + |
| +SubsetterImpl::SubsetterImpl() { |
| +} |
| + |
| +SubsetterImpl::~SubsetterImpl() { |
| +} |
| + |
| +bool SubsetterImpl::loadFont(const char* font_name, |
| + const unsigned char* original_font, |
| + const size_t font_size) { |
| + ByteArrayPtr raw_font = |
| + new MemoryByteArray((byte_t*)original_font, font_size); |
| + if (factory_ == NULL) { |
| + factory_.attach(FontFactory::getInstance()); |
| + } |
| + |
| + FontArray font_array; |
| + factory_->loadFonts(raw_font, &font_array); |
| + font_ = findFont(font_name, font_array); |
| + if (font_ == NULL) { |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +int SubsetterImpl::subsetFont(const unsigned int* glyph_ids, |
| + const size_t glyph_count, |
| + unsigned char** output_buffer) { |
| + if (factory_ == NULL || font_ == NULL) { |
| + return -1; |
| + } |
| + |
| + FontPtr new_font; |
| + new_font.attach(subset(glyph_ids, glyph_count)); |
| + if (new_font == NULL) { |
| + return 0; |
| + } |
| + |
| + MemoryOutputStream output_stream; |
| + factory_->serializeFont(new_font, &output_stream); |
| + int length = (int)output_stream.size(); |
| + if (length > 0) { |
| + *output_buffer = new unsigned char[length]; |
| + memcpy(*output_buffer, output_stream.get(), length); |
| + } |
| + |
| + return length; |
| +} |
| + |
| +Font* SubsetterImpl::findFont(const char* font_name, FontArray& font_array) { |
| + if (font_array.empty() || font_array[0] == NULL) { |
| + return NULL; |
| + } |
| + |
| + if (font_name && strlen(font_name)) { |
| + for (FontArray::iterator b = font_array.begin(), e = font_array.end(); |
| + b != e; ++b) { |
| + if (hasName(font_name, (*b).p_)) { |
| + return (*b).p_; |
| + } |
| + } |
| + } |
| + |
| + return font_array[0].p_; |
| +} |
| + |
| +bool SubsetterImpl::hasName(const char* font_name, Font* font) { |
| + UnicodeString font_string = UnicodeString::fromUTF8(font_name); |
| + if (font_string.isEmpty()) |
| + return false; |
| + UnicodeString regular_suffix = UnicodeString::fromUTF8(" Regular"); |
| + UnicodeString alt_font_string = font_string; |
| + alt_font_string += regular_suffix; |
| + |
| + typedef std::map<int32_t, UnicodeString> NameMap; |
| + NameMap names; |
| + NameTablePtr name_table = down_cast<NameTable*>(font->table(Tag::name)); |
| + |
| + for (int32_t i = 0; i < name_table->nameCount(); ++i) { |
| + switch(name_table->nameId(i)) { |
| + case NameId::kFontFamilyName: |
| + case NameId::kFontSubfamilyName: |
| + case NameId::kFullFontName: |
| + case NameId::kPreferredFamily: |
| + case NameId::kPreferredSubfamily: |
| + case NameId::kWWSFamilyName: |
| + case NameId::kWWSSubfamilyName: { |
| + int32_t hash_code = hashCode(name_table->platformId(i), |
| + name_table->encodingId(i), |
| + name_table->languageId(i), |
| + name_table->nameId(i)); |
| + UChar* name_part = name_table->name(i); |
| + constructName(name_part, &(names[hash_code]), name_table->nameId(i)); |
| + } |
| + break; |
| + default: |
| + break; |
| + } |
| + } |
| + |
| + if (!names.empty()) { |
| + for (NameMap::iterator b = names.begin(), e = names.end(); b != e; ++b) { |
| + if (b->second.caseCompare(font_string, 0) == 0 || |
| + b->second.caseCompare(alt_font_string, 0) == 0) { |
| + return true; |
| + } |
| + } |
| + } |
| + return false; |
| +} |
| + |
| +CALLER_ATTACH Font* SubsetterImpl::subset(const unsigned int* glyph_ids, |
| + const size_t glyph_count) { |
| + if (glyph_ids == NULL || glyph_count == 0) { |
| + return NULL; |
| + } |
| + |
| + // Find glyf and loca table. |
| + GlyphTablePtr glyph_table = down_cast<GlyphTable*>(font_->table(Tag::glyf)); |
| + LocaTablePtr loca_table = down_cast<LocaTable*>(font_->table(Tag::loca)); |
| + if (glyph_table == NULL || loca_table == NULL) { |
| + // The font is invalid. |
| + return NULL; |
| + } |
| + |
| + // Setup font builders we need. |
| + FontBuilderPtr font_builder; |
| + font_builder.attach(factory_->newFontBuilder()); |
| + |
| + GlyphTableBuilderPtr glyph_table_builder; |
| + glyph_table_builder.attach(down_cast<GlyphTable::Builder*>( |
| + font_builder->newTableBuilder(Tag::glyf))); |
| + LocaTableBuilderPtr loca_table_builder; |
| + loca_table_builder.attach(down_cast<LocaTable::Builder*>( |
| + font_builder->newTableBuilder(Tag::loca))); |
| + if (glyph_table_builder == NULL || loca_table_builder == NULL) { |
| + // Out of memory. |
| + return NULL; |
| + } |
| + |
| + // Sort and uniquify glyph ids. |
| + IntegerSet glyph_id_set; |
| + glyph_id_set.insert(0); // always include glyph id 0 |
| + for (size_t i = 0; i < glyph_count; ++i) { |
| + glyph_id_set.insert(glyph_ids[i]); |
| + } |
| + |
| + // Extract glyphs and setup loca list. |
| + IntegerList loca_list; |
| + loca_list.resize(loca_table->numLocas()); |
| + loca_list.push_back(0); |
| + int32_t last_glyph_id = 0; |
| + int32_t last_offset = 0; |
| + GlyphTable::GlyphBuilderList* glyph_builders = |
| + glyph_table_builder->glyphBuilders(); |
| + for (IntegerSet::iterator i = glyph_id_set.begin(), e = glyph_id_set.end(); |
| + i != e; ++i) { |
| + if (*i < 0 || *i >= loca_table->numGlyphs()) { |
| + // Invalid glyph id, ignore. |
| + continue; |
| + } |
| + |
| + int32_t length = loca_table->glyphLength(*i); |
| + if (length == 0) { |
| + // Empty glyph, ignore. |
| + continue; |
| + } |
| + int32_t offset = loca_table->glyphOffset(*i); |
| + |
| + GlyphPtr glyph; |
| + glyph.attach(glyph_table->glyph(offset, length)); |
| + if (glyph == NULL) { |
| + // Error finding glyph, ignore. |
| + continue; |
| + } |
| + |
| + // Add glyph to new glyf table. |
| + ReadableFontDataPtr data = glyph->readFontData(); |
| + WritableFontDataPtr copy_data; |
| + copy_data.attach(font_builder->getNewData(data->length())); |
| + data->copyTo(copy_data); |
| + GlyphBuilderPtr glyph_builder; |
| + glyph_builder.attach(glyph_table_builder->glyphBuilder(copy_data)); |
| + glyph_builders->push_back(glyph_builder); |
| + |
| + // Configure loca list. |
| + for (int32_t j = last_glyph_id + 1; j <= *i; ++j) { |
| + loca_list[j] = last_offset; |
| + } |
| + last_offset = offset; |
| + loca_list[*i + 1] = offset; |
| + last_glyph_id = *i; |
| + } |
| + for (int32_t j = last_glyph_id + 1; j <= loca_table->numGlyphs(); ++j) { |
| + loca_list[j] = last_offset; |
| + } |
| + loca_table_builder->setLocaList(&loca_list); |
| + |
| + // Setup remaining builders. |
| + for (TableMap::iterator i = font_->tables()->begin(), |
| + e = font_->tables()->end(); i != e; ++i) { |
| + // We already build the builder for glyph and loca. |
| + if (i->first != Tag::glyf && i->first != Tag::loca) { |
| + // The newTableBuilder() call will alter internal state of font_builder |
| + // AND the reference count of returned object. Therefore we need to |
| + // dereference it. |
| + TableBuilderPtr dereference; |
| + dereference.attach( |
| + font_builder->newTableBuilder(i->first, i->second->readFontData())); |
| + } |
| + } |
| + |
| + return font_builder->build(); |
| +} |
| + |
| +} // namespace sfntly |