diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /gfx/sfntly | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/sfntly')
190 files changed, 33759 insertions, 0 deletions
diff --git a/gfx/sfntly/README.mozilla b/gfx/sfntly/README.mozilla new file mode 100644 index 0000000000..3698f2d9fe --- /dev/null +++ b/gfx/sfntly/README.mozilla @@ -0,0 +1,5 @@ +This directory contains the C++ port of SFNTLY, +from https://github.com/googlei18n/sfntly/tree/master/cpp. + +SFNTLY is distributed under the Apache license v2.0 +(see cpp/COPYING.txt). diff --git a/gfx/sfntly/cpp/src/moz.build b/gfx/sfntly/cpp/src/moz.build new file mode 100644 index 0000000000..e0a4a0f3bc --- /dev/null +++ b/gfx/sfntly/cpp/src/moz.build @@ -0,0 +1,73 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +EXPORTS += [ + 'sample/chromium/font_subsetter.h', +] + +UNIFIED_SOURCES += [ + 'sample/chromium/font_subsetter.cc', + 'sample/chromium/subsetter_impl.cc', + 'sfntly/data/byte_array.cc', + 'sfntly/data/font_data.cc', + 'sfntly/data/font_input_stream.cc', + 'sfntly/data/font_output_stream.cc', + 'sfntly/data/growable_memory_byte_array.cc', + 'sfntly/data/memory_byte_array.cc', + 'sfntly/data/readable_font_data.cc', + 'sfntly/data/writable_font_data.cc', + 'sfntly/font.cc', + 'sfntly/font_factory.cc', + 'sfntly/port/file_input_stream.cc', + 'sfntly/port/lock.cc', + 'sfntly/port/memory_input_stream.cc', + 'sfntly/port/memory_output_stream.cc', + 'sfntly/table/bitmap/big_glyph_metrics.cc', + 'sfntly/table/bitmap/bitmap_glyph.cc', + 'sfntly/table/bitmap/bitmap_glyph_info.cc', + 'sfntly/table/bitmap/bitmap_size_table.cc', + 'sfntly/table/bitmap/composite_bitmap_glyph.cc', + 'sfntly/table/bitmap/ebdt_table.cc', + 'sfntly/table/bitmap/eblc_table.cc', + 'sfntly/table/bitmap/ebsc_table.cc', + 'sfntly/table/bitmap/glyph_metrics.cc', + 'sfntly/table/bitmap/index_sub_table.cc', + 'sfntly/table/bitmap/index_sub_table_format1.cc', + 'sfntly/table/bitmap/index_sub_table_format2.cc', + 'sfntly/table/bitmap/index_sub_table_format3.cc', + 'sfntly/table/bitmap/index_sub_table_format4.cc', + 'sfntly/table/bitmap/index_sub_table_format5.cc', + 'sfntly/table/bitmap/simple_bitmap_glyph.cc', + 'sfntly/table/bitmap/small_glyph_metrics.cc', + 'sfntly/table/byte_array_table_builder.cc', + 'sfntly/table/core/cmap_table.cc', + 'sfntly/table/core/font_header_table.cc', + 'sfntly/table/core/horizontal_device_metrics_table.cc', + 'sfntly/table/core/horizontal_header_table.cc', + 'sfntly/table/core/horizontal_metrics_table.cc', + 'sfntly/table/core/maximum_profile_table.cc', + 'sfntly/table/core/name_table.cc', + 'sfntly/table/core/os2_table.cc', + 'sfntly/table/font_data_table.cc', + 'sfntly/table/generic_table_builder.cc', + 'sfntly/table/header.cc', + 'sfntly/table/subtable.cc', + 'sfntly/table/table.cc', + 'sfntly/table/table_based_table_builder.cc', + 'sfntly/table/truetype/glyph_table.cc', + 'sfntly/table/truetype/loca_table.cc', + 'sfntly/tag.cc', + 'sfntly/tools/subsetter/glyph_table_subsetter.cc', + 'sfntly/tools/subsetter/subsetter.cc', + 'sfntly/tools/subsetter/table_subsetter_impl.cc', +] + +# We allow warnings for third-party code that can be updated from upstream. +AllowCompilerWarnings() + +FINAL_LIBRARY = 'gkmedias' + +DEFINES['SFNTLY_NO_EXCEPTION'] = 1 diff --git a/gfx/sfntly/cpp/src/sample/chromium/chrome_subsetter.cc b/gfx/sfntly/cpp/src/sample/chromium/chrome_subsetter.cc new file mode 100644 index 0000000000..df15c182b7 --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/chromium/chrome_subsetter.cc @@ -0,0 +1,131 @@ +/* + * 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 <stdio.h> + +#include <vector> +#include <string> +#include <sstream> + +#include "sfntly/port/type.h" +#include "font_subsetter.h" + +template <typename T> +class HexTo { + public: + explicit HexTo(const char* in) { + std::stringstream ss; + ss << std::hex << in; + ss >> value_; + } + operator T() const { return value_; } + + private: + T value_; +}; + +bool LoadFile(const char* input_file_path, sfntly::ByteVector* input_buffer) { + assert(input_file_path); + assert(input_buffer); + + FILE* input_file = NULL; +#if defined WIN32 + fopen_s(&input_file, input_file_path, "rb"); +#else + input_file = fopen(input_file_path, "rb"); +#endif + if (input_file == NULL) { + return false; + } + fseek(input_file, 0, SEEK_END); + size_t file_size = ftell(input_file); + fseek(input_file, 0, SEEK_SET); + input_buffer->resize(file_size); + size_t bytes_read = fread(&((*input_buffer)[0]), 1, file_size, input_file); + fclose(input_file); + return bytes_read == file_size; +} + +bool SaveFile(const char* output_file_path, const unsigned char* output_buffer, + int buffer_length) { + int byte_count = 0; + if (buffer_length > 0) { + FILE* output_file = NULL; +#if defined WIN32 + fopen_s(&output_file, output_file_path, "wb"); +#else + output_file = fopen(output_file_path, "wb"); +#endif + if (output_file) { + byte_count = fwrite(output_buffer, 1, buffer_length, output_file); + fflush(output_file); + fclose(output_file); + } + return buffer_length == byte_count; + } + return false; +} + +bool StringToGlyphId(const char* input, std::vector<unsigned int>* glyph_ids) { + assert(input); + std::string hex_csv = input; + size_t start = 0; + size_t end = hex_csv.find_first_of(","); + while (end != std::string::npos) { + glyph_ids->push_back( + HexTo<unsigned int>(hex_csv.substr(start, end - start).c_str())); + start = end + 1; + end = hex_csv.find_first_of(",", start); + } + glyph_ids->push_back(HexTo<unsigned int>(hex_csv.substr(start).c_str())); + return glyph_ids->size() > 0; +} + +int main(int argc, char** argv) { + if (argc < 5) { + fprintf(stderr, + "Usage: %s <input path> <output path> <font name> <glyph ids>\n", + argv[0]); + fprintf(stderr, "\tGlyph ids are comma separated hex values\n"); + fprintf(stderr, "\te.g. 20,1a,3b,4f\n"); + return 0; + } + + sfntly::ByteVector input_buffer; + if (!LoadFile(argv[1], &input_buffer)) { + fprintf(stderr, "ERROR: unable to load font file %s\n", argv[1]); + return 0; + } + + std::vector<unsigned int> glyph_ids; + if (!StringToGlyphId(argv[4], &glyph_ids)) { + fprintf(stderr, "ERROR: unable to parse input glyph id\n"); + return 0; + } + + unsigned char* output_buffer = NULL; + int output_length = + SfntlyWrapper::SubsetFont(argv[3], + &(input_buffer[0]), + input_buffer.size(), + &(glyph_ids[0]), + glyph_ids.size(), + &output_buffer); + + int result = SaveFile(argv[2], output_buffer, output_length) ? 1 : 0; + delete[] output_buffer; + return result; +} diff --git a/gfx/sfntly/cpp/src/sample/chromium/font_subsetter.cc b/gfx/sfntly/cpp/src/sample/chromium/font_subsetter.cc new file mode 100644 index 0000000000..0f9bc1341d --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/chromium/font_subsetter.cc @@ -0,0 +1,60 @@ +/* + * 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 "font_subsetter.h" + +#include "subsetter_impl.h" + +int SfntlyWrapper::SubsetFont(const char* font_name, + const unsigned char* original_font, + size_t font_size, + const unsigned int* glyph_ids, + size_t glyph_count, + unsigned char** output_buffer) { + if (output_buffer == NULL || + original_font == NULL || font_size == 0 || + glyph_ids == NULL || glyph_count == 0) { + return 0; + } + + sfntly::SubsetterImpl subsetter; + if (!subsetter.LoadFont(font_name, original_font, font_size)) { + return -1; // Load error or font not found. + } + + return subsetter.SubsetFont(glyph_ids, glyph_count, output_buffer); +} + +int SfntlyWrapper::SubsetFont(int font_index, + const unsigned char* original_font, + size_t font_size, + const unsigned int* glyph_ids, + size_t glyph_count, + unsigned char** output_buffer) { + if (output_buffer == NULL || + original_font == NULL || font_size == 0 || + glyph_ids == NULL || glyph_count == 0) { + return 0; + } + + sfntly::SubsetterImpl subsetter; + if (!subsetter.LoadFont(font_index, original_font, font_size)) { + return -1; // Load error or font not found. + } + + return subsetter.SubsetFont(glyph_ids, glyph_count, output_buffer); +} + diff --git a/gfx/sfntly/cpp/src/sample/chromium/font_subsetter.h b/gfx/sfntly/cpp/src/sample/chromium/font_subsetter.h new file mode 100644 index 0000000000..c8e65e227d --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/chromium/font_subsetter.h @@ -0,0 +1,75 @@ +/* + * 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. + */ +// File is originally from Chromium third_party/sfntly/src/subsetter. +// Use as test case in sfntly so that problems can be caught in upstream early. +#ifndef SFNTLY_CPP_SRC_TEST_FONT_SUBSETTER_H_ +#define SFNTLY_CPP_SRC_TEST_FONT_SUBSETTER_H_ + +#include <stddef.h> + +class SfntlyWrapper { + public: + + // Font subsetting API + // + // Input TTF/TTC/OTF fonts, specify the glyph IDs to subset, and the subset + // font is returned in |output_buffer| (caller to delete[]). Return value is + // the length of output_buffer allocated. + // + // If subsetting fails, a negative value is returned. If none of the glyph + // IDs specified is found, the function will return 0. + // + // |font_name| Font name, required for TTC files. If specified NULL, + // the first available font is selected. + // |original_font| Original font file contents. + // |font_size| Size of |original_font| in bytes. + // |glyph_ids| Glyph IDs to subset. If the specified glyph ID is not + // found in the font file, it will be ignored silently. + // |glyph_count| Number of glyph IDs in |glyph_ids| + // |output_buffer| Generated subset font. Caller to delete[]. + static int SubsetFont(const char* font_name, + const unsigned char* original_font, + size_t font_size, + const unsigned int* glyph_ids, + size_t glyph_count, + unsigned char** output_buffer); + + + // Font subsetting API + // + // Input TTF/TTC/OTF fonts, specify the glyph IDs to subset, and the subset + // font is returned in |output_buffer| (caller to delete[]). Return value is + // the length of output_buffer allocated. + // + // If subsetting fails, a negative value is returned. If none of the glyph + // IDs specified is found, the function will return 0. + // + // |font_name| Font index, ignored for non-TTC files, 0-indexed. + // |original_font| Original font file contents. + // |font_size| Size of |original_font| in bytes. + // |glyph_ids| Glyph IDs to subset. If the specified glyph ID is not + // found in the font file, it will be ignored silently. + // |glyph_count| Number of glyph IDs in |glyph_ids| + // |output_buffer| Generated subset font. Caller to delete[]. + static int SubsetFont(int font_index, + const unsigned char* original_font, + size_t font_size, + const unsigned int* glyph_ids, + size_t glyph_count, + unsigned char** output_buffer); +}; + +#endif // SFNTLY_CPP_SRC_TEST_FONT_SUBSETTER_H_ diff --git a/gfx/sfntly/cpp/src/sample/chromium/subsetter_impl.cc b/gfx/sfntly/cpp/src/sample/chromium/subsetter_impl.cc new file mode 100644 index 0000000000..5910591b20 --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/chromium/subsetter_impl.cc @@ -0,0 +1,848 @@ +/* + * 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 "subsetter_impl.h" + +#include <string.h> + +#include <algorithm> +#include <iterator> +#include <limits> +#include <map> +#include <set> +#include <string> + +#include <unicode/ustring.h> +#include <unicode/uversion.h> + +#include "sfntly/table/bitmap/eblc_table.h" +#include "sfntly/table/bitmap/ebdt_table.h" +#include "sfntly/table/bitmap/index_sub_table.h" +#include "sfntly/table/bitmap/index_sub_table_format1.h" +#include "sfntly/table/bitmap/index_sub_table_format2.h" +#include "sfntly/table/bitmap/index_sub_table_format3.h" +#include "sfntly/table/bitmap/index_sub_table_format4.h" +#include "sfntly/table/bitmap/index_sub_table_format5.h" +#include "sfntly/table/core/name_table.h" +#include "sfntly/tag.h" +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/port/memory_input_stream.h" +#include "sfntly/port/memory_output_stream.h" + +namespace { + +using namespace sfntly; + +/** + * std::u16string and icu::UnicodeString can't be used here. + * UChar is not always char16_t in some platforms. std::u16string is avoided. + * icu::UnicodeString C++ API is also avoided to make it more portable across + * platforms due to C++ ABI compatility issue. + */ +typedef std::basic_string<UChar> UCharString; + +// The bitmap tables must be greater than 16KB to trigger bitmap subsetter. +static const int BITMAP_SIZE_THRESHOLD = 16384; + +void ConstructName(UChar* name_part, UCharString* name, int32_t name_id) { + switch (name_id) { + case NameId::kFullFontName: + *name = name_part; + break; + case NameId::kFontFamilyName: + case NameId::kPreferredFamily: + case NameId::kWWSFamilyName: { + UCharString original = *name; + *name = name_part; + *name += original; + break; + } + case NameId::kFontSubfamilyName: + case NameId::kPreferredSubfamily: + case NameId::kWWSSubfamilyName: + *name += name_part; + break; + default: + // This name part is not used to construct font name (e.g. copyright). + // Simply ignore it. + break; + } +} + +// Convert UTF-8 string into UTF-16 string. +// +// Ill-formed input is replaced with U+FFFD. +// Otherwise, return empty string if other error occurs during the conversion. +UCharString ConvertFromUtf8(const char* src) { + int32_t srcLength = strlen(src); + int32_t destCapacity = srcLength + 1; + UChar* buffer = new UChar[destCapacity]; + UCharString dest; + if (buffer == NULL) { + return dest; + } + int32_t destLength; + UErrorCode errorCode = U_ZERO_ERROR; + u_strFromUTF8WithSub(buffer, destCapacity, &destLength, src, srcLength, + 0xfffd, // Unicode replacement character + NULL, + &errorCode); + if (U_SUCCESS(errorCode)) { + dest.append(buffer, destLength); + } + delete[] buffer; + return dest; +} + +int32_t CaseCompareUtf16(const UCharString& str1, + const UCharString& str2, uint32_t option) { + UErrorCode errorCode = U_ZERO_ERROR; + return u_strCaseCompare(str1.c_str(), str1.length(), str2.c_str(), + str2.length(), option, &errorCode); +} + +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; +} + +bool HasName(const char* font_name, Font* font) { + UCharString font_string = ConvertFromUtf8(font_name); + if (font_string.empty()) + return false; + UCharString regular_suffix = ConvertFromUtf8(" Regular"); + UCharString alt_font_string = font_string; + alt_font_string += regular_suffix; + + typedef std::map<int32_t, UCharString> NameMap; + NameMap names; + NameTablePtr name_table = down_cast<NameTable*>(font->GetTable(Tag::name)); + if (name_table == NULL) { + return false; + } + + 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: { + UChar* name_part = name_table->Name(i); + if (name_part == NULL) { + continue; + } + int32_t hash_code = HashCode(name_table->PlatformId(i), + name_table->EncodingId(i), + name_table->LanguageId(i), + name_table->NameId(i)); + ConstructName(name_part, &(names[hash_code]), name_table->NameId(i)); + delete[] name_part; + break; + } + default: + break; + } + } + + if (!names.empty()) { + for (NameMap::iterator i = names.begin(), e = names.end(); i != e; ++i) { + if (CaseCompareUtf16(i->second, font_string, 0) == 0 || + CaseCompareUtf16(i->second, alt_font_string, 0) == 0) { + return true; + } + } + } + return false; +} + +Font* FindFont(const char* font_name, const FontArray& font_array) { + if (font_array.empty() || font_array[0] == NULL) { + return NULL; + } + + if (font_name && strlen(font_name)) { + for (FontArray::const_iterator i = font_array.begin(), e = font_array.end(); + i != e; ++i) { + if (HasName(font_name, i->p_)) { + return i->p_; + } + } + } + + return font_array[0].p_; +} + +bool ResolveCompositeGlyphs(GlyphTable* glyph_table, + LocaTable* loca_table, + const unsigned int* glyph_ids, + size_t glyph_count, + IntegerSet* glyph_id_processed) { + if (glyph_table == NULL || loca_table == NULL || + glyph_ids == NULL || glyph_count == 0 || glyph_id_processed == NULL) { + return false; + } + + // Sort and uniquify glyph ids. + IntegerSet glyph_id_remaining; + glyph_id_remaining.insert(0); // Always include glyph id 0. + for (size_t i = 0; i < glyph_count; ++i) { + glyph_id_remaining.insert(glyph_ids[i]); + } + + // Identify if any given glyph id maps to a composite glyph. If so, include + // the glyphs referenced by that composite glyph. + while (!glyph_id_remaining.empty()) { + IntegerSet comp_glyph_id; + for (IntegerSet::iterator i = glyph_id_remaining.begin(), + e = glyph_id_remaining.end(); i != e; ++i) { + if (*i < 0 || *i >= loca_table->num_glyphs()) { + // 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->GetGlyph(offset, length)); + if (glyph == NULL) { + // Error finding glyph, ignore. + continue; + } + + if (glyph->GlyphType() == GlyphType::kComposite) { + Ptr<GlyphTable::CompositeGlyph> comp_glyph = + down_cast<GlyphTable::CompositeGlyph*>(glyph.p_); + for (int32_t j = 0; j < comp_glyph->NumGlyphs(); ++j) { + int32_t glyph_id = comp_glyph->GlyphIndex(j); + if (glyph_id_processed->find(glyph_id) == glyph_id_processed->end() && + glyph_id_remaining.find(glyph_id) == glyph_id_remaining.end()) { + comp_glyph_id.insert(comp_glyph->GlyphIndex(j)); + } + } + } + + glyph_id_processed->insert(*i); + } + + glyph_id_remaining.clear(); + glyph_id_remaining = comp_glyph_id; + } + + return true; +} + +bool SetupGlyfBuilders(Font::Builder* font_builder, + GlyphTable* glyph_table, + LocaTable* loca_table, + const IntegerSet& glyph_ids) { + if (!font_builder || !glyph_table || !loca_table) { + return false; + } + + GlyphTableBuilderPtr glyph_table_builder = + down_cast<GlyphTable::Builder*>(font_builder->NewTableBuilder(Tag::glyf)); + LocaTableBuilderPtr loca_table_builder = + down_cast<LocaTable::Builder*>(font_builder->NewTableBuilder(Tag::loca)); + if (glyph_table_builder == NULL || loca_table_builder == NULL) { + // Out of memory. + return false; + } + + // Extract glyphs and setup loca list. + IntegerList loca_list; + loca_list.resize(loca_table->num_glyphs()); + 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::const_iterator i = glyph_ids.begin(), e = glyph_ids.end(); + i != e; ++i) { + int32_t length = loca_table->GlyphLength(*i); + int32_t offset = loca_table->GlyphOffset(*i); + + GlyphPtr glyph; + glyph.Attach(glyph_table->GetGlyph(offset, length)); + + // Add glyph to new glyf table. + ReadableFontDataPtr data = glyph->ReadFontData(); + WritableFontDataPtr copy_data; + copy_data.Attach(WritableFontData::CreateWritableFontData(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; + } + + if (last_offset > std::numeric_limits<int32_t>::max() - length) + return false; + + last_offset += length; + loca_list[*i + 1] = last_offset; + last_glyph_id = *i; + } + for (int32_t j = last_glyph_id + 1; j <= loca_table->num_glyphs(); ++j) { + loca_list[j] = last_offset; + } + loca_table_builder->SetLocaList(&loca_list); + + return true; +} + +bool HasOverlap(int32_t range_begin, int32_t range_end, + const IntegerSet& glyph_ids) { + if (range_begin == range_end) + return glyph_ids.find(range_begin) != glyph_ids.end(); + + if (range_begin >= range_end) + return false; + + IntegerSet::const_iterator left = glyph_ids.lower_bound(range_begin); + IntegerSet::const_iterator right = glyph_ids.lower_bound(range_end); + return left != right; +} + +// Initialize builder, returns false if glyph_id subset is not covered. +// Not thread-safe, caller to ensure object life-time. +bool InitializeBitmapBuilder(EbdtTable::Builder* ebdt, EblcTable::Builder* eblc, + const IntegerSet& glyph_ids) { + BitmapLocaList loca_list; + BitmapSizeTableBuilderList* strikes = eblc->BitmapSizeBuilders(); + + // Note: Do not call eblc_builder->GenerateLocaList(&loca_list) and then + // ebdt_builder->SetLoca(loca_list). For fonts like SimSun, there are + // >28K glyphs inside, where a typical usage will be <1K glyphs. Doing + // the calls improperly will result in creation of >100K objects that + // will be destroyed immediately, inducing significant slowness. + IntegerList removed_strikes; + for (size_t i = 0; i < strikes->size(); i++) { + if (!HasOverlap((*strikes)[i]->StartGlyphIndex(), + (*strikes)[i]->EndGlyphIndex(), glyph_ids)) { + removed_strikes.push_back(i); + continue; + } + + IndexSubTableBuilderList* index_builders = + (*strikes)[i]->IndexSubTableBuilders(); + IntegerList removed_indexes; + BitmapGlyphInfoMap info_map; + for (size_t j = 0; j < index_builders->size(); ++j) { + if ((*index_builders)[j] == NULL) { + // Subtable is malformed, let's just skip it. + removed_indexes.push_back(j); + continue; + } + int32_t first_glyph_id = (*index_builders)[j]->first_glyph_index(); + int32_t last_glyph_id = (*index_builders)[j]->last_glyph_index(); + if (!HasOverlap(first_glyph_id, last_glyph_id, glyph_ids)) { + removed_indexes.push_back(j); + continue; + } + for (IntegerSet::const_iterator gid = glyph_ids.begin(), + gid_end = glyph_ids.end(); + gid != gid_end; gid++) { + if (*gid < first_glyph_id) { + continue; + } + if (*gid > last_glyph_id) { + break; + } + BitmapGlyphInfoPtr info; + info.Attach((*index_builders)[j]->GlyphInfo(*gid)); + if (info && info->length()) { // Do not include gid without bitmap + info_map[*gid] = info; + } + } + } + if (!info_map.empty()) { + loca_list.push_back(info_map); + } else { + removed_strikes.push_back(i); // Detected null entries. + } + + // Remove unused index sub tables + for (IntegerList::reverse_iterator j = removed_indexes.rbegin(), + e = removed_indexes.rend(); + j != e; j++) { + index_builders->erase(index_builders->begin() + *j); + } + } + if (removed_strikes.size() == strikes->size() || loca_list.empty()) { + return false; + } + + for (IntegerList::reverse_iterator i = removed_strikes.rbegin(), + e = removed_strikes.rend(); i != e; i++) { + strikes->erase(strikes->begin() + *i); + } + + if (strikes->empty()) { // no glyph covered, can safely drop the builders. + return false; + } + + ebdt->SetLoca(&loca_list); + ebdt->GlyphBuilders(); // Initialize the builder. + return true; +} + +void CopyBigGlyphMetrics(BigGlyphMetrics::Builder* source, + BigGlyphMetrics::Builder* target) { + target->SetHeight(static_cast<uint8_t>(source->Height())); + target->SetWidth(static_cast<uint8_t>(source->Width())); + target->SetHoriBearingX(static_cast<uint8_t>(source->HoriBearingX())); + target->SetHoriBearingY(static_cast<uint8_t>(source->HoriBearingY())); + target->SetHoriAdvance(static_cast<uint8_t>(source->HoriAdvance())); + target->SetVertBearingX(static_cast<uint8_t>(source->VertBearingX())); + target->SetVertBearingY(static_cast<uint8_t>(source->VertBearingY())); + target->SetVertAdvance(static_cast<uint8_t>(source->VertAdvance())); +} + +CALLER_ATTACH IndexSubTable::Builder* +ConstructIndexFormat4(IndexSubTable::Builder* b, const BitmapGlyphInfoMap& loca, + int32_t* image_data_offset) { + IndexSubTableFormat4BuilderPtr builder4; + builder4.Attach(IndexSubTableFormat4::Builder::CreateBuilder()); + CodeOffsetPairBuilderList offset_pairs; + + size_t offset = 0; + int32_t lower_bound = b->first_glyph_index(); + int32_t upper_bound = b->last_glyph_index(); + int32_t last_gid = -1; + BitmapGlyphInfoMap::const_iterator i = loca.lower_bound(lower_bound); + BitmapGlyphInfoMap::const_iterator end = loca.end(); + if (i != end) { + last_gid = i->first; + builder4->set_first_glyph_index(last_gid); + builder4->set_image_format(b->image_format()); + builder4->set_image_data_offset(*image_data_offset); + } + for (; i != end; i++) { + int32_t gid = i->first; + if (gid > upper_bound) { + break; + } + offset_pairs.push_back( + IndexSubTableFormat4::CodeOffsetPairBuilder(gid, offset)); + offset += i->second->length(); + last_gid = gid; + } + offset_pairs.push_back( + IndexSubTableFormat4::CodeOffsetPairBuilder(-1, offset)); + builder4->set_last_glyph_index(last_gid); + *image_data_offset += offset; + builder4->SetOffsetArray(offset_pairs); + + return builder4.Detach(); +} + +CALLER_ATTACH IndexSubTable::Builder* +ConstructIndexFormat5(IndexSubTable::Builder* b, const BitmapGlyphInfoMap& loca, + int32_t* image_data_offset) { + IndexSubTableFormat5BuilderPtr new_builder; + new_builder.Attach(IndexSubTableFormat5::Builder::CreateBuilder()); + + // Copy BigMetrics + int32_t image_size = 0; + if (b->index_format() == IndexSubTable::Format::FORMAT_2) { + IndexSubTableFormat2BuilderPtr builder2 = + down_cast<IndexSubTableFormat2::Builder*>(b); + CopyBigGlyphMetrics(builder2->BigMetrics(), new_builder->BigMetrics()); + image_size = builder2->ImageSize(); + } else { + IndexSubTableFormat5BuilderPtr builder5 = + down_cast<IndexSubTableFormat5::Builder*>(b); + BigGlyphMetricsBuilderPtr metrics_builder; + CopyBigGlyphMetrics(builder5->BigMetrics(), new_builder->BigMetrics()); + image_size = builder5->ImageSize(); + } + + IntegerList* glyph_array = new_builder->GlyphArray(); + size_t offset = 0; + int32_t lower_bound = b->first_glyph_index(); + int32_t upper_bound = b->last_glyph_index(); + int32_t last_gid = -1; + BitmapGlyphInfoMap::const_iterator i = loca.lower_bound(lower_bound); + BitmapGlyphInfoMap::const_iterator end = loca.end(); + if (i != end) { + last_gid = i->first; + new_builder->set_first_glyph_index(last_gid); + new_builder->set_image_format(b->image_format()); + new_builder->set_image_data_offset(*image_data_offset); + new_builder->SetImageSize(image_size); + } + for (; i != end; i++) { + int32_t gid = i->first; + if (gid > upper_bound) { + break; + } + glyph_array->push_back(gid); + offset += i->second->length(); + last_gid = gid; + } + new_builder->set_last_glyph_index(last_gid); + *image_data_offset += offset; + return new_builder.Detach(); +} + +CALLER_ATTACH IndexSubTable::Builder* +SubsetIndexSubTable(IndexSubTable::Builder* builder, + const BitmapGlyphInfoMap& loca, + int32_t* image_data_offset) { + switch (builder->index_format()) { + case IndexSubTable::Format::FORMAT_1: + case IndexSubTable::Format::FORMAT_3: + case IndexSubTable::Format::FORMAT_4: + return ConstructIndexFormat4(builder, loca, image_data_offset); + case IndexSubTable::Format::FORMAT_2: + case IndexSubTable::Format::FORMAT_5: + return ConstructIndexFormat5(builder, loca, image_data_offset); + default: + assert(false); + break; + } + return NULL; +} + +} + +namespace sfntly { + +// Not thread-safe, caller to ensure object life-time. +void SubsetEBLC(EblcTable::Builder* eblc, const BitmapLocaList& new_loca) { + BitmapSizeTableBuilderList* size_builders = eblc->BitmapSizeBuilders(); + if (size_builders == NULL) { + return; + } + + int32_t image_data_offset = EbdtTable::Offset::kHeaderLength; + for (size_t strike = 0; strike < size_builders->size(); ++strike) { + IndexSubTableBuilderList* index_builders = + (*size_builders)[strike]->IndexSubTableBuilders(); + for (size_t index = 0; index < index_builders->size(); ++index) { + IndexSubTable::Builder* new_builder_raw = + SubsetIndexSubTable((*index_builders)[index], new_loca[strike], + &image_data_offset); + if (NULL != new_builder_raw) { + (*index_builders)[index].Attach(new_builder_raw); + } + } + } +} + +// EBLC structure (from stuartg) +// header +// bitmapSizeTable[] +// one per strike +// holds strike metrics - sbitLineMetrics +// holds info about indexSubTableArray +// indexSubTableArray[][] +// one per strike and then one per indexSubTable for that strike +// holds info about the indexSubTable +// the indexSubTable entries pointed to can be of different formats +// indexSubTable +// one per indexSubTableArray entry +// tells how to get the glyphs +// may hold the glyph metrics if they are uniform for all the glyphs in range +// Please note that the structure can also be +// {indexSubTableArray[], indexSubTables[]}[] +// This way is also legal and in fact how Microsoft fonts are laid out. +// +// There is nothing that says that the indexSubTableArray entries and/or the +// indexSubTable items need to be unique. They may be shared between strikes. +// +// EBDT structure: +// header +// glyphs +// amorphous blob of data +// different glyphs that are only able to be figured out from the EBLC table +// may hold metrics - depends on the EBLC entry that pointed to them + +// Subsetting EBLC table (from arthurhsu) +// Most pages use only a fraction (hundreds or less) glyphs out of a given font +// (which can have >20K glyphs for CJK). It's safe to assume that the subset +// font will have sparse bitmap glyphs. So we reconstruct the EBLC table as +// format 4 or 5 here. + +enum BuildersToRemove { + kRemoveNone, + kRemoveBDAT, + kRemoveBDATAndEBDT, + kRemoveEBDT +}; + +int SetupBitmapBuilders(Font* font, Font::Builder* font_builder, + const IntegerSet& glyph_ids) { + if (!font || !font_builder) { + return false; + } + + // Check if bitmap table exists. + EbdtTablePtr ebdt_table = down_cast<EbdtTable*>(font->GetTable(Tag::EBDT)); + EblcTablePtr eblc_table = down_cast<EblcTable*>(font->GetTable(Tag::EBLC)); + bool use_ebdt = (ebdt_table != NULL && eblc_table != NULL); + if (!use_ebdt) { + ebdt_table = down_cast<EbdtTable*>(font->GetTable(Tag::bdat)); + eblc_table = down_cast<EblcTable*>(font->GetTable(Tag::bloc)); + if (ebdt_table == NULL || eblc_table == NULL) { + return kRemoveNone; + } + } + + // If the bitmap table's size is too small, skip subsetting. + if (ebdt_table->DataLength() + eblc_table->DataLength() < + BITMAP_SIZE_THRESHOLD) { + return use_ebdt ? kRemoveBDAT : kRemoveNone; + } + + // Get the builders. + EbdtTableBuilderPtr ebdt_table_builder = down_cast<EbdtTable::Builder*>( + font_builder->NewTableBuilder(use_ebdt ? Tag::EBDT : Tag::bdat, + ebdt_table->ReadFontData())); + EblcTableBuilderPtr eblc_table_builder = down_cast<EblcTable::Builder*>( + font_builder->NewTableBuilder(use_ebdt ? Tag::EBLC : Tag::bloc, + eblc_table->ReadFontData())); + if (ebdt_table_builder == NULL || eblc_table_builder == NULL) { + // Out of memory. + return use_ebdt ? kRemoveBDAT : kRemoveNone; + } + + if (!InitializeBitmapBuilder(ebdt_table_builder, eblc_table_builder, + glyph_ids)) { + // Bitmap tables do not cover the glyphs in our subset. + font_builder->RemoveTableBuilder(use_ebdt ? Tag::EBLC : Tag::bloc); + font_builder->RemoveTableBuilder(use_ebdt ? Tag::EBDT : Tag::bdat); + return use_ebdt ? kRemoveBDATAndEBDT : kRemoveEBDT; + } + + BitmapLocaList new_loca; + ebdt_table_builder->GenerateLocaList(&new_loca); + SubsetEBLC(eblc_table_builder, new_loca); + + return use_ebdt ? kRemoveBDAT : kRemoveNone; +} + +SubsetterImpl::SubsetterImpl() { +} + +SubsetterImpl::~SubsetterImpl() { +} + +bool SubsetterImpl::LoadFont(int font_index, + const unsigned char* original_font, + size_t font_size) { + MemoryInputStream mis; + mis.Attach(original_font, font_size); + if (factory_ == NULL) { + factory_.Attach(FontFactory::GetInstance()); + } + + FontArray font_array; + factory_->LoadFonts(&mis, &font_array); + if (font_index < 0 || (size_t)font_index >= font_array.size()) { + return false; + } + font_ = font_array[font_index].p_; + return font_ != NULL; +} + +bool SubsetterImpl::LoadFont(const char* font_name, + const unsigned char* original_font, + size_t font_size) { + MemoryInputStream mis; + mis.Attach(original_font, font_size); + if (factory_ == NULL) { + factory_.Attach(FontFactory::GetInstance()); + } + + FontArray font_array; + factory_->LoadFonts(&mis, &font_array); + font_ = FindFont(font_name, font_array); + return font_ != NULL; +} + +int SubsetterImpl::SubsetFont(const unsigned int* glyph_ids, + size_t glyph_count, + unsigned char** output_buffer) { + if (factory_ == NULL || font_ == NULL) { + return -1; + } + + // Find glyf and loca table. + GlyphTablePtr glyph_table = + down_cast<GlyphTable*>(font_->GetTable(Tag::glyf)); + LocaTablePtr loca_table = down_cast<LocaTable*>(font_->GetTable(Tag::loca)); + if (glyph_table == NULL || loca_table == NULL) { + // We are not able to subset the font. + return 0; + } + + IntegerSet glyph_id_processed; + if (!ResolveCompositeGlyphs(glyph_table, loca_table, + glyph_ids, glyph_count, &glyph_id_processed) || + glyph_id_processed.empty()) { + return 0; + } + + FontPtr new_font; + new_font.Attach(Subset(glyph_id_processed, glyph_table, loca_table)); + if (new_font == NULL) { + return 0; + } + + MemoryOutputStream output_stream; + factory_->SerializeFont(new_font, &output_stream); + size_t length = output_stream.Size(); + if (length == 0 || + length > static_cast<size_t>(std::numeric_limits<int>::max())) { + return 0; + } + + *output_buffer = new unsigned char[length]; + memcpy(*output_buffer, output_stream.Get(), length); + return length; +} + +// Long comments regarding TTF tables and PDF (from stuartg) +// +// According to PDF spec 1.4 (section 5.8), the following tables must be +// present: +// head, hhea, loca, maxp, cvt, prep, glyf, hmtx, fpgm +// cmap if font is used with a simple font dict and not a CIDFont dict +// +// Other tables we need to keep for PDF rendering to support zoom in/out: +// bdat, bloc, ebdt, eblc, ebsc, gasp +// +// Special table: +// CFF - if you have this table then you shouldn't have a glyf table and this +// is the table with all the glyphs. Shall skip subsetting completely +// since sfntly is not capable of subsetting it for now. +// post - extra info here for printing on PostScript printers but maybe not +// enough to outweigh the space taken by the names +// +// Tables to break apart: +// name - could throw away all but one language and one platform strings/ might +// throw away some of the name entries +// cmap - could strip out non-needed cmap subtables +// - format 4 subtable can be subsetted as well using sfntly +// +// Graphite tables: +// silf, glat, gloc, feat - should be okay to strip out +// +// Tables that can be discarded: +// OS/2 - everything here is for layout and description of the font that is +// elsewhere (some in the PDF objects) +// BASE, GDEF, GSUB, GPOS, JSTF - all used for layout +// kern - old style layout +// DSIG - this will be invalid after subsetting +// hdmx - layout +// PCLT - metadata that's not needed +// vmtx - layout +// vhea - layout +// VDMX +// VORG - not used by TT/OT - used by CFF +// hsty - would be surprised to see one of these - used on the Newton +// AAT tables - mort, morx, feat, acnt, bsin, just, lcar, fdsc, fmtx, prop, +// Zapf, opbd, trak, fvar, gvar, avar, cvar +// - these are all layout tables and once layout happens are not +// needed anymore +// LTSH - layout + +CALLER_ATTACH +Font* SubsetterImpl::Subset(const IntegerSet& glyph_ids, GlyphTable* glyf, + LocaTable* loca) { + // The const is initialized here to workaround VC bug of rendering all Tag::* + // as 0. These tags represents the TTF tables that we will embed in subset + // font. + const int32_t TABLES_IN_SUBSET[] = { + Tag::head, Tag::hhea, Tag::loca, Tag::maxp, Tag::cvt, + Tag::prep, Tag::glyf, Tag::hmtx, Tag::fpgm, Tag::EBDT, + Tag::EBLC, Tag::EBSC, Tag::bdat, Tag::bloc, Tag::bhed, + Tag::cmap, // Keep here for future tagged PDF development. + Tag::name, // Keep here due to legal concerns: copyright info inside. + }; + const size_t kTablesInSubSetSize = + sizeof(TABLES_IN_SUBSET) / sizeof(TABLES_IN_SUBSET[0]); + + // Setup font builders we need. + FontBuilderPtr font_builder; + font_builder.Attach(factory_->NewFontBuilder()); + IntegerSet remove_tags; + + if (SetupGlyfBuilders(font_builder, glyf, loca, glyph_ids)) { + remove_tags.insert(Tag::glyf); + remove_tags.insert(Tag::loca); + } + + // For old Apple bitmap fonts, they have only bdats and bhed is identical + // to head. As a result, we can't remove bdat tables for those fonts. + int setup_result = SetupBitmapBuilders(font_, font_builder, glyph_ids); + if (setup_result == kRemoveBDATAndEBDT || setup_result == kRemoveEBDT) { + remove_tags.insert(Tag::EBDT); + remove_tags.insert(Tag::EBLC); + remove_tags.insert(Tag::EBSC); + } + + if (setup_result == kRemoveBDAT || setup_result == kRemoveBDATAndEBDT) { + remove_tags.insert(Tag::bdat); + remove_tags.insert(Tag::bloc); + remove_tags.insert(Tag::bhed); + } + + IntegerSet allowed_tags; + for (size_t i = 0; i < kTablesInSubSetSize; ++i) + allowed_tags.insert(TABLES_IN_SUBSET[i]); + + IntegerSet result; + std::set_difference(allowed_tags.begin(), allowed_tags.end(), + remove_tags.begin(), remove_tags.end(), + std::inserter(result, result.end())); + allowed_tags = result; + + // Setup remaining builders. + for (IntegerSet::const_iterator it = allowed_tags.begin(); + it != allowed_tags.end(); ++it) { + int32_t tag = *it; + Table* table = font_->GetTable(tag); + if (table) + font_builder->NewTableBuilder(tag, table->ReadFontData()); + } + + return font_builder->Build(); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sample/chromium/subsetter_impl.h b/gfx/sfntly/cpp/src/sample/chromium/subsetter_impl.h new file mode 100644 index 0000000000..738a8d4da8 --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/chromium/subsetter_impl.h @@ -0,0 +1,77 @@ +/* + * 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. + */ +// File is originally from Chromium third_party/sfntly/src/subsetter. +// Use as test case in sfntly so that problems can be caught in upstream early. + +#ifndef SFNTLY_CPP_SRC_TEST_SUBSETTER_IMPL_H_ +#define SFNTLY_CPP_SRC_TEST_SUBSETTER_IMPL_H_ + +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/table/truetype/glyph_table.h" +#include "sfntly/table/truetype/loca_table.h" +#include "sfntly/tag.h" + +namespace sfntly { + +// Smart pointer usage in sfntly: +// +// sfntly carries a smart pointer implementation like COM. Ref-countable object +// type inherits from RefCounted<>, which have AddRef and Release just like +// IUnknown (but no QueryInterface). Use a Ptr<> based smart pointer to hold +// the object so that the object ref count is handled correctly. +// +// class Foo : public RefCounted<Foo> { +// public: +// static Foo* CreateInstance() { +// Ptr<Foo> obj = new Foo(); // ref count = 1 +// return obj.detach(); +// } +// }; +// typedef Ptr<Foo> FooPtr; // common short-hand notation +// FooPtr obj; +// obj.attach(Foo::CreatedInstance()); // ref count = 1 +// { +// FooPtr obj2 = obj; // ref count = 2 +// } // ref count = 1, obj2 out of scope +// obj.release(); // ref count = 0, object destroyed + +class SubsetterImpl { + public: + SubsetterImpl(); + ~SubsetterImpl(); + + bool LoadFont(const char* font_name, + const unsigned char* original_font, + size_t font_size); + bool LoadFont(int font_index, + const unsigned char* original_font, + size_t font_size); + int SubsetFont(const unsigned int* glyph_ids, + size_t glyph_count, + unsigned char** output_buffer); + + private: + CALLER_ATTACH Font* Subset(const IntegerSet& glyph_ids, + GlyphTable* glyf, LocaTable* loca); + + FontFactoryPtr factory_; + FontPtr font_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_TEST_SUBSETTER_IMPL_H_ diff --git a/gfx/sfntly/cpp/src/sample/subsetter/main.cc b/gfx/sfntly/cpp/src/sample/subsetter/main.cc new file mode 100644 index 0000000000..19a3e0e23f --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subsetter/main.cc @@ -0,0 +1,44 @@ +/* + * 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 <stdio.h> +#if _MSC_VER > 12 + #define _CRTDBG_MAP_ALLOC + #include <stdlib.h> + #include <crtdbg.h> +#endif + +#include "sample/subsetter/subset_util.h" + +int main(int argc, char** argv) { +#ifdef _CRTDBG_MAP_ALLOC + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); +#endif + + if (argc < 3) { + printf("Usage: subsetter <font file> <output file>\n"); + return 0; + } + + sfntly::SubsetUtil subset_util; + subset_util.Subset(argv[1], argv[2]); + +#ifdef _CRTDBG_MAP_ALLOC + _CrtDumpMemoryLeaks(); +#endif + + return 0; +} diff --git a/gfx/sfntly/cpp/src/sample/subsetter/subset_util.cc b/gfx/sfntly/cpp/src/sample/subsetter/subset_util.cc new file mode 100644 index 0000000000..f35eb25cd6 --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subsetter/subset_util.cc @@ -0,0 +1,98 @@ +/* + * 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. + */ + +// Remove VC++ nag on fopen. +#define _CRT_SECURE_NO_WARNINGS + +#include "sample/subsetter/subset_util.h" + +#include <stdio.h> + +#include <vector> +#include <memory> + +#include "sfntly/font.h" +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/port/memory_output_stream.h" +#include "sfntly/port/type.h" +#include "sfntly/tag.h" +#include "sfntly/tools/subsetter/subsetter.h" + +namespace sfntly { + +SubsetUtil::SubsetUtil() { +} + +SubsetUtil::~SubsetUtil() { +} + +void SubsetUtil::Subset(const char *input_file_path, + const char *output_file_path) { + UNREFERENCED_PARAMETER(output_file_path); + ByteVector input_buffer; + FILE* input_file = fopen(input_file_path, "rb"); + if (input_file == NULL) { + fprintf(stderr, "file not found\n"); + return; + } + fseek(input_file, 0, SEEK_END); + size_t file_size = ftell(input_file); + fseek(input_file, 0, SEEK_SET); + input_buffer.resize(file_size); + size_t bytes_read = fread(&(input_buffer[0]), 1, file_size, input_file); + UNREFERENCED_PARAMETER(bytes_read); + fclose(input_file); + + FontFactoryPtr factory; + factory.Attach(FontFactory::GetInstance()); + + FontArray font_array; + factory->LoadFonts(&input_buffer, &font_array); + if (font_array.empty() || font_array[0] == NULL) + return; + + IntegerList glyphs; + for (int32_t i = 0; i < 10; i++) { + glyphs.push_back(i); + } + glyphs.push_back(11); + glyphs.push_back(10); + + Ptr<Subsetter> subsetter = new Subsetter(font_array[0], factory); + subsetter->SetGlyphs(&glyphs); + IntegerSet remove_tables; + remove_tables.insert(Tag::DSIG); + subsetter->SetRemoveTables(&remove_tables); + + FontBuilderPtr font_builder; + font_builder.Attach(subsetter->Subset()); + + FontPtr new_font; + new_font.Attach(font_builder->Build()); + + // TODO(arthurhsu): glyph renumbering/Loca table + // TODO(arthurhsu): alter CMaps + + MemoryOutputStream output_stream; + factory->SerializeFont(new_font, &output_stream); + + FILE* output_file = fopen(output_file_path, "wb"); + fwrite(output_stream.Get(), 1, output_stream.Size(), output_file); + fflush(output_file); + fclose(output_file); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sample/subsetter/subset_util.h b/gfx/sfntly/cpp/src/sample/subsetter/subset_util.h new file mode 100644 index 0000000000..5eb4fe4169 --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subsetter/subset_util.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SAMPLE_SUBSETTER_SUBSET_UTIL_H_ +#define SFNTLY_CPP_SRC_SAMPLE_SUBSETTER_SUBSET_UTIL_H_ + +namespace sfntly { + +class SubsetUtil { + public: + SubsetUtil(); + virtual ~SubsetUtil(); + + void Subset(const char* input_file_path, const char* output_file_path); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SAMPLE_SUBSETTER_SUBSET_UTIL_H_ diff --git a/gfx/sfntly/cpp/src/sample/subtly/character_predicate.cc b/gfx/sfntly/cpp/src/sample/subtly/character_predicate.cc new file mode 100644 index 0000000000..b9c6cc787b --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/character_predicate.cc @@ -0,0 +1,53 @@ +/* + * 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 "sfntly/port/refcount.h" +#include "subtly/character_predicate.h" + +namespace subtly { +using namespace sfntly; + +// AcceptRange predicate +AcceptRange::AcceptRange(int32_t start, int32_t end) + : start_(start), + end_(end) { +} + +AcceptRange::~AcceptRange() {} + +bool AcceptRange::operator()(int32_t character) const { + return start_ <= character && character <= end_; +} + +// AcceptSet predicate +AcceptSet::AcceptSet(IntegerSet* characters) + : characters_(characters) { +} + +AcceptSet::~AcceptSet() { + delete characters_; +} + +bool AcceptSet::operator()(int32_t character) const { + return characters_->find(character) != characters_->end(); +} + +// AcceptAll predicate +bool AcceptAll::operator()(int32_t character) const { + UNREFERENCED_PARAMETER(character); + return true; +} +} diff --git a/gfx/sfntly/cpp/src/sample/subtly/character_predicate.h b/gfx/sfntly/cpp/src/sample/subtly/character_predicate.h new file mode 100644 index 0000000000..a6e3ea360e --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/character_predicate.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_CHARACTER_PREDICATE_H_ +#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_CHARACTER_PREDICATE_H_ + +#include "sfntly/port/refcount.h" +#include "sfntly/port/type.h" + +namespace subtly { +class CharacterPredicate : virtual public sfntly::RefCount { + public: + CharacterPredicate() {} + virtual ~CharacterPredicate() {} + virtual bool operator()(int32_t character) const = 0; +}; + +// All characters except for those between [start, end] are rejected +class AcceptRange : public CharacterPredicate, + public sfntly::RefCounted<AcceptRange> { + public: + AcceptRange(int32_t start, int32_t end); + ~AcceptRange(); + virtual bool operator()(int32_t character) const; + + private: + int32_t start_; + int32_t end_; +}; + +// All characters in IntegerSet +// The set is OWNED by the predicate! Do not modify it. +// It will be freed when the predicate is destroyed. +class AcceptSet : public CharacterPredicate, + public sfntly::RefCounted<AcceptSet> { + public: + explicit AcceptSet(sfntly::IntegerSet* characters); + ~AcceptSet(); + virtual bool operator()(int32_t character) const; + + private: + sfntly::IntegerSet* characters_; +}; + +// All characters +class AcceptAll : public CharacterPredicate, + public sfntly::RefCounted<AcceptAll> { + public: + AcceptAll() {} + ~AcceptAll() {} + virtual bool operator()(int32_t character) const; +}; +} + +#endif // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_CHARACTER_PREDICATE_H_ diff --git a/gfx/sfntly/cpp/src/sample/subtly/debug_main.cc b/gfx/sfntly/cpp/src/sample/subtly/debug_main.cc new file mode 100644 index 0000000000..8324cde45c --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/debug_main.cc @@ -0,0 +1,64 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> + +#include <map> +#include <utility> + +#include "sfntly/font.h" +#include "sfntly/table/core/cmap_table.h" +#include "sfntly/tag.h" +#include "subtly/stats.h" +#include "subtly/subsetter.h" +#include "subtly/utils.h" + +using namespace subtly; + +void PrintUsage(const char* program_name) { + fprintf(stdout, "Usage: %s <input_font_file>\n", program_name); +} + +int main(int argc, const char** argv) { + const char* program_name = argv[0]; + if (argc < 2) { + PrintUsage(program_name); + exit(1); + } + + const char* input_font_path = argv[1]; + const char* output_font_path = argv[2]; + FontPtr font; + font.Attach(subtly::LoadFont(input_font_path)); + + int32_t original_size = TotalFontSize(font); + Ptr<Subsetter> subsetter = new Subsetter(font, NULL); + Ptr<Font> new_font; + new_font.Attach(subsetter->Subset()); + if (!new_font) { + fprintf(stdout, "Cannot create subset.\n"); + return 0; + } + + subtly::SerializeFont(output_font_path, new_font); + subtly::PrintComparison(stdout, font, new_font); + int32_t new_size = TotalFontSize(new_font); + fprintf(stdout, "Went from %d to %d: %lf%% of original\n", + original_size, new_size, + static_cast<double>(new_size) / original_size * 100); + return 0; +} diff --git a/gfx/sfntly/cpp/src/sample/subtly/font_assembler.cc b/gfx/sfntly/cpp/src/sample/subtly/font_assembler.cc new file mode 100644 index 0000000000..4717512a5c --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/font_assembler.cc @@ -0,0 +1,229 @@ +/* + * 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 "subtly/font_assembler.h" + +#include <stdio.h> + +#include <set> +#include <map> + +#include "sfntly/tag.h" +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/table/core/cmap_table.h" +#include "sfntly/table/truetype/loca_table.h" +#include "sfntly/table/truetype/glyph_table.h" +#include "sfntly/table/core/maximum_profile_table.h" +#include "sfntly/port/type.h" +#include "sfntly/port/refcount.h" +#include "subtly/font_info.h" + +namespace subtly { +using namespace sfntly; + +FontAssembler::FontAssembler(FontInfo* font_info, + IntegerSet* table_blacklist) + : table_blacklist_(table_blacklist) { + font_info_ = font_info; + Initialize(); +} + +FontAssembler::FontAssembler(FontInfo* font_info) + : table_blacklist_(NULL) { + font_info_ = font_info; + Initialize(); +} + +void FontAssembler::Initialize() { + font_factory_.Attach(sfntly::FontFactory::GetInstance()); + font_builder_.Attach(font_factory_->NewFontBuilder()); +} + +CALLER_ATTACH Font* FontAssembler::Assemble() { + // Assemble tables we can subset. + if (!AssembleCMapTable() || !AssembleGlyphAndLocaTables()) { + return NULL; + } + // For all other tables, either include them unmodified or don't at all. + const TableMap* common_table_map = + font_info_->GetTableMap(font_info_->fonts()->begin()->first); + for (TableMap::const_iterator it = common_table_map->begin(), + e = common_table_map->end(); it != e; ++it) { + if (table_blacklist_ + && table_blacklist_->find(it->first) != table_blacklist_->end()) { + continue; + } + font_builder_->NewTableBuilder(it->first, it->second->ReadFontData()); + } + return font_builder_->Build(); +} + +bool FontAssembler::AssembleCMapTable() { + // Creating the new CMapTable and the new format 4 CMap + Ptr<CMapTable::Builder> cmap_table_builder = + down_cast<CMapTable::Builder*> + (font_builder_->NewTableBuilder(Tag::cmap)); + if (!cmap_table_builder) + return false; + Ptr<CMapTable::CMapFormat4::Builder> cmap_builder = + down_cast<CMapTable::CMapFormat4::Builder*> + (cmap_table_builder->NewCMapBuilder(CMapFormat::kFormat4, + CMapTable::WINDOWS_BMP)); + if (!cmap_builder) + return false; + // Creating the segments and the glyph id array + CharacterMap* chars_to_glyph_ids = font_info_->chars_to_glyph_ids(); + SegmentList* segment_list = new SegmentList; + IntegerList* glyph_id_array = new IntegerList; + int32_t last_chararacter = -2; + int32_t last_offset = 0; + Ptr<CMapTable::CMapFormat4::Builder::Segment> current_segment; + + // For simplicity, we will have one segment per contiguous range. + // To test the algorithm, we've replaced the original CMap with the CMap + // generated by this code without removing any character. + // Tuffy.ttf: CMap went from 3146 to 3972 bytes (1.7% to 2.17% of file) + // AnonymousPro.ttf: CMap went from 1524 to 1900 bytes (0.96% to 1.2%) + for (CharacterMap::iterator it = chars_to_glyph_ids->begin(), + e = chars_to_glyph_ids->end(); it != e; ++it) { + int32_t character = it->first; + int32_t glyph_id = it->second.glyph_id(); + if (character != last_chararacter + 1) { // new segment + if (current_segment != NULL) { + current_segment->set_end_count(last_chararacter); + segment_list->push_back(current_segment); + } + // start_code = character + // end_code = -1 (unknown for now) + // id_delta = 0 (we don't use id_delta for this representation) + // id_range_offset = last_offset (offset into the glyph_id_array) + current_segment = + new CMapTable::CMapFormat4::Builder:: + Segment(character, -1, 0, last_offset); + } + glyph_id_array->push_back(glyph_id); + last_offset += DataSize::kSHORT; + last_chararacter = character; + } + // The last segment is still open. + current_segment->set_end_count(last_chararacter); + segment_list->push_back(current_segment); + // Updating the id_range_offset for every segment. + for (int32_t i = 0, num_segs = segment_list->size(); i < num_segs; ++i) { + Ptr<CMapTable::CMapFormat4::Builder::Segment> segment = segment_list->at(i); + segment->set_id_range_offset(segment->id_range_offset() + + (num_segs - i + 1) * DataSize::kSHORT); + } + // Adding the final, required segment. + current_segment = + new CMapTable::CMapFormat4::Builder::Segment(0xffff, 0xffff, 1, 0); + segment_list->push_back(current_segment); + // Writing the segments and glyph id array to the CMap + cmap_builder->set_segments(segment_list); + cmap_builder->set_glyph_id_array(glyph_id_array); + delete segment_list; + delete glyph_id_array; + return true; +} + +bool FontAssembler::AssembleGlyphAndLocaTables() { + Ptr<LocaTable::Builder> loca_table_builder = + down_cast<LocaTable::Builder*> + (font_builder_->NewTableBuilder(Tag::loca)); + Ptr<GlyphTable::Builder> glyph_table_builder = + down_cast<GlyphTable::Builder*> + (font_builder_->NewTableBuilder(Tag::glyf)); + + GlyphIdSet* resolved_glyph_ids = font_info_->resolved_glyph_ids(); + IntegerList loca_list; + // Basic sanity check: all LOCA tables are of the same size + // This is necessary but not suficient! + int32_t previous_size = -1; + for (FontIdMap::iterator it = font_info_->fonts()->begin(); + it != font_info_->fonts()->end(); ++it) { + Ptr<LocaTable> loca_table = + down_cast<LocaTable*>(font_info_->GetTable(it->first, Tag::loca)); + int32_t current_size = loca_table->header_length(); + if (previous_size != -1 && current_size != previous_size) { + return false; + } + previous_size = current_size; + } + + // Assuming all fonts referenced by the FontInfo are the subsets of the same + // font, their loca tables should all have the same sizes. + // We'll just get the size of the first font's LOCA table for simplicty. + Ptr<LocaTable> first_loca_table = + down_cast<LocaTable*> + (font_info_->GetTable(font_info_->fonts()->begin()->first, Tag::loca)); + int32_t num_loca_glyphs = first_loca_table->num_glyphs(); + loca_list.resize(num_loca_glyphs); + 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 (GlyphIdSet::iterator it = resolved_glyph_ids->begin(), + e = resolved_glyph_ids->end(); it != e; ++it) { + // Get the glyph for this resolved_glyph_id. + int32_t resolved_glyph_id = it->glyph_id(); + int32_t font_id = it->font_id(); + // Get the LOCA table for the current glyph id. + Ptr<LocaTable> loca_table = + down_cast<LocaTable*> + (font_info_->GetTable(font_id, Tag::loca)); + int32_t length = loca_table->GlyphLength(resolved_glyph_id); + int32_t offset = loca_table->GlyphOffset(resolved_glyph_id); + + // Get the GLYF table for the current glyph id. + Ptr<GlyphTable> glyph_table = + down_cast<GlyphTable*> + (font_info_->GetTable(font_id, Tag::glyf)); + GlyphPtr glyph; + glyph.Attach(glyph_table->GetGlyph(offset, length)); + + // The data reference by the glyph is copied into a new glyph and + // added to the glyph_builders belonging to the glyph_table_builder. + // When Build gets called, all the glyphs will be built. + Ptr<ReadableFontData> data = glyph->ReadFontData(); + Ptr<WritableFontData> copy_data; + copy_data.Attach(WritableFontData::CreateWritableFontData(data->Length())); + data->CopyTo(copy_data); + GlyphBuilderPtr glyph_builder; + glyph_builder.Attach(glyph_table_builder->GlyphBuilder(copy_data)); + glyph_builders->push_back(glyph_builder); + + // If there are missing glyphs between the last glyph_id and the + // current resolved_glyph_id, since the LOCA table needs to have the same + // size, the offset is kept the same. + loca_list.resize(std::max(loca_list.size(), + static_cast<size_t>(resolved_glyph_id + 2))); + for (int32_t i = last_glyph_id + 1; i <= resolved_glyph_id; ++i) + loca_list[i] = last_offset; + last_offset += length; + loca_list[resolved_glyph_id + 1] = last_offset; + last_glyph_id = resolved_glyph_id + 1; + } + // If there are missing glyph ids, their loca entries must all point + // to the same offset as the last valid glyph id making them all zero length. + for (int32_t i = last_glyph_id + 1; i <= num_loca_glyphs; ++i) + loca_list[i] = last_offset; + loca_table_builder->SetLocaList(&loca_list); + return true; +} +} diff --git a/gfx/sfntly/cpp/src/sample/subtly/font_assembler.h b/gfx/sfntly/cpp/src/sample/subtly/font_assembler.h new file mode 100644 index 0000000000..c53c21fd07 --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/font_assembler.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_ASSEMBLER_H_ +#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_ASSEMBLER_H_ + +#include <set> +#include <map> + +#include "subtly/font_info.h" + +#include "sfntly/tag.h" +#include "sfntly/font.h" +#include "sfntly/port/type.h" +#include "sfntly/port/refcount.h" +#include "sfntly/table/core/cmap_table.h" +#include "sfntly/table/truetype/glyph_table.h" +#include "sfntly/table/truetype/loca_table.h" + +namespace subtly { +// Assembles FontInfo into font builders. +// Does not take ownership of data passed to it. +class FontAssembler : public sfntly::RefCounted<FontAssembler> { + public: + // font_info is the FontInfo which will be used for the new font + // table_blacklist is used to decide which tables to exclude from the + // final font. + FontAssembler(FontInfo* font_info, sfntly::IntegerSet* table_blacklist); + explicit FontAssembler(FontInfo* font_info); + ~FontAssembler() { } + + // Assemble a new font from the font info object. + virtual CALLER_ATTACH sfntly::Font* Assemble(); + + sfntly::IntegerSet* table_blacklist() const { return table_blacklist_; } + void set_table_blacklist(sfntly::IntegerSet* table_blacklist) { + table_blacklist_ = table_blacklist; + } + + protected: + virtual bool AssembleCMapTable(); + virtual bool AssembleGlyphAndLocaTables(); + + virtual void Initialize(); + + private: + sfntly::Ptr<FontInfo> font_info_; + sfntly::Ptr<sfntly::FontFactory> font_factory_; + sfntly::Ptr<sfntly::Font::Builder> font_builder_; + sfntly::IntegerSet* table_blacklist_; +}; +} + +#endif // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_ASSEMBLER_H_ diff --git a/gfx/sfntly/cpp/src/sample/subtly/font_info.cc b/gfx/sfntly/cpp/src/sample/subtly/font_info.cc new file mode 100644 index 0000000000..6eb6a38070 --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/font_info.cc @@ -0,0 +1,256 @@ +/* + * 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 "subtly/font_info.h" + +#include <stdio.h> + +#include <set> +#include <map> + +#include "subtly/character_predicate.h" + +#include "sfntly/tag.h" +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/table/core/cmap_table.h" +#include "sfntly/table/truetype/loca_table.h" +#include "sfntly/table/truetype/glyph_table.h" +#include "sfntly/table/core/maximum_profile_table.h" +#include "sfntly/port/type.h" +#include "sfntly/port/refcount.h" + +namespace subtly { +using namespace sfntly; +/****************************************************************************** + * GlyphId class + ******************************************************************************/ +GlyphId::GlyphId(int32_t glyph_id, FontId font_id) + : glyph_id_(glyph_id), + font_id_(font_id) { +} + +bool GlyphId::operator==(const GlyphId& other) const { + return glyph_id_ == other.glyph_id(); +} + +bool GlyphId::operator<(const GlyphId& other) const { + return glyph_id_ < other.glyph_id(); +} + +/****************************************************************************** + * FontInfo class + ******************************************************************************/ +FontInfo::FontInfo() + : chars_to_glyph_ids_(new CharacterMap), + resolved_glyph_ids_(new GlyphIdSet), + fonts_(new FontIdMap) { +} + +FontInfo::FontInfo(CharacterMap* chars_to_glyph_ids, + GlyphIdSet* resolved_glyph_ids, + FontIdMap* fonts) { + chars_to_glyph_ids_ = new CharacterMap(chars_to_glyph_ids->begin(), + chars_to_glyph_ids->end()); + resolved_glyph_ids_ = new GlyphIdSet(resolved_glyph_ids->begin(), + resolved_glyph_ids->end()); + fonts_ = new FontIdMap(fonts->begin(), fonts->end()); +} + +FontInfo::~FontInfo() { + delete chars_to_glyph_ids_; + delete resolved_glyph_ids_; + delete fonts_; +} + +FontDataTable* FontInfo::GetTable(FontId font_id, int32_t tag) { + if (!fonts_) + return NULL; + FontIdMap::iterator it = fonts_->find(font_id); + if (it == fonts_->end()) + return NULL; + return it->second->GetTable(tag); +} + +const TableMap* FontInfo::GetTableMap(FontId font_id) { + if (!fonts_) + return NULL; + FontIdMap::iterator it = fonts_->find(font_id); + if (it == fonts_->end()) + return NULL; + return it->second->GetTableMap(); +} + +void FontInfo::set_chars_to_glyph_ids(CharacterMap* chars_to_glyph_ids) { + *chars_to_glyph_ids_ = *chars_to_glyph_ids; +} + +void FontInfo::set_resolved_glyph_ids(GlyphIdSet* resolved_glyph_ids) { + *resolved_glyph_ids_ = *resolved_glyph_ids; +} + +void FontInfo::set_fonts(FontIdMap* fonts) { + *fonts_ = *fonts; +} + +/****************************************************************************** + * FontSourcedInfoBuilder class + ******************************************************************************/ +FontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font, FontId font_id) + : font_(font), + font_id_(font_id), + predicate_(NULL) { + Initialize(); +} + +FontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font, + FontId font_id, + CharacterPredicate* predicate) + : font_(font), + font_id_(font_id), + predicate_(predicate) { + Initialize(); +} + +void FontSourcedInfoBuilder::Initialize() { + Ptr<CMapTable> cmap_table = down_cast<CMapTable*>(font_->GetTable(Tag::cmap)); + // We prefer Windows BMP format 4 cmaps. + cmap_.Attach(cmap_table->GetCMap(CMapTable::WINDOWS_BMP)); + // But if none is found, + if (!cmap_) { + return; + } + loca_table_ = down_cast<LocaTable*>(font_->GetTable(Tag::loca)); + glyph_table_ = down_cast<GlyphTable*>(font_->GetTable(Tag::glyf)); +} + +CALLER_ATTACH FontInfo* FontSourcedInfoBuilder::GetFontInfo() { + CharacterMap* chars_to_glyph_ids = new CharacterMap; + bool success = GetCharacterMap(chars_to_glyph_ids); + if (!success) { + delete chars_to_glyph_ids; +#if defined (SUBTLY_DEBUG) + fprintf(stderr, "Error creating character map.\n"); +#endif + return NULL; + } + GlyphIdSet* resolved_glyph_ids = new GlyphIdSet; + success = ResolveCompositeGlyphs(chars_to_glyph_ids, resolved_glyph_ids); + if (!success) { + delete chars_to_glyph_ids; + delete resolved_glyph_ids; +#if defined (SUBTLY_DEBUG) + fprintf(stderr, "Error resolving composite glyphs.\n"); +#endif + return NULL; + } + Ptr<FontInfo> font_info = new FontInfo; + font_info->set_chars_to_glyph_ids(chars_to_glyph_ids); + font_info->set_resolved_glyph_ids(resolved_glyph_ids); + FontIdMap* font_id_map = new FontIdMap; + font_id_map->insert(std::make_pair(font_id_, font_)); + font_info->set_fonts(font_id_map); + delete chars_to_glyph_ids; + delete resolved_glyph_ids; + delete font_id_map; + return font_info.Detach(); +} + +bool FontSourcedInfoBuilder::GetCharacterMap(CharacterMap* chars_to_glyph_ids) { + if (!cmap_ || !chars_to_glyph_ids) + return false; + chars_to_glyph_ids->clear(); + CMapTable::CMap::CharacterIterator* character_iterator = cmap_->Iterator(); + if (!character_iterator) + return false; + while (character_iterator->HasNext()) { + int32_t character = character_iterator->Next(); + if (!predicate_ || (*predicate_)(character)) { + chars_to_glyph_ids->insert + (std::make_pair(character, + GlyphId(cmap_->GlyphId(character), font_id_))); + } + } + delete character_iterator; + return true; +} + +bool +FontSourcedInfoBuilder::ResolveCompositeGlyphs(CharacterMap* chars_to_glyph_ids, + GlyphIdSet* resolved_glyph_ids) { + if (!chars_to_glyph_ids || !resolved_glyph_ids) + return false; + resolved_glyph_ids->clear(); + resolved_glyph_ids->insert(GlyphId(0, font_id_)); + IntegerSet* unresolved_glyph_ids = new IntegerSet; + // Since composite glyph elements might themselves be composite, we would need + // to recursively resolve the elements too. To avoid the recursion we + // create two sets, |unresolved_glyph_ids| for the unresolved glyphs, + // initially containing all the ids and |resolved_glyph_ids|, initially empty. + // We'll remove glyph ids from |unresolved_glyph_ids| until it is empty and, + // if the glyph is composite, add its elements to the unresolved set. + for (CharacterMap::iterator it = chars_to_glyph_ids->begin(), + e = chars_to_glyph_ids->end(); it != e; ++it) { + unresolved_glyph_ids->insert(it->second.glyph_id()); + } + // As long as there are unresolved glyph ids. + while (!unresolved_glyph_ids->empty()) { + // Get the corresponding glyph. + int32_t glyph_id = *(unresolved_glyph_ids->begin()); + unresolved_glyph_ids->erase(unresolved_glyph_ids->begin()); + if (glyph_id < 0 || glyph_id > loca_table_->num_glyphs()) { +#if defined (SUBTLY_DEBUG) + fprintf(stderr, "%d larger than %d or smaller than 0\n", glyph_id, + loca_table_->num_glyphs()); +#endif + continue; + } + int32_t length = loca_table_->GlyphLength(glyph_id); + if (length == 0) { +#if defined (SUBTLY_DEBUG) + fprintf(stderr, "Zero length glyph %d\n", glyph_id); +#endif + continue; + } + int32_t offset = loca_table_->GlyphOffset(glyph_id); + GlyphPtr glyph; + glyph.Attach(glyph_table_->GetGlyph(offset, length)); + if (glyph == NULL) { +#if defined (SUBTLY_DEBUG) + fprintf(stderr, "GetGlyph returned NULL for %d\n", glyph_id); +#endif + continue; + } + // Mark the glyph as resolved. + resolved_glyph_ids->insert(GlyphId(glyph_id, font_id_)); + // If it is composite, add all its components to the unresolved glyph set. + if (glyph->GlyphType() == GlyphType::kComposite) { + Ptr<GlyphTable::CompositeGlyph> composite_glyph = + down_cast<GlyphTable::CompositeGlyph*>(glyph.p_); + int32_t num_glyphs = composite_glyph->NumGlyphs(); + for (int32_t i = 0; i < num_glyphs; ++i) { + int32_t glyph_id = composite_glyph->GlyphIndex(i); + if (resolved_glyph_ids->find(GlyphId(glyph_id, -1)) + == resolved_glyph_ids->end()) { + unresolved_glyph_ids->insert(glyph_id); + } + } + } + } + delete unresolved_glyph_ids; + return true; +} +} diff --git a/gfx/sfntly/cpp/src/sample/subtly/font_info.h b/gfx/sfntly/cpp/src/sample/subtly/font_info.h new file mode 100644 index 0000000000..6f42d7314b --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/font_info.h @@ -0,0 +1,128 @@ +/* + * 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. + */ + +#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_INFO_H_ +#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_INFO_H_ + +#include <map> +#include <set> + +#include "sfntly/font.h" +#include "sfntly/port/type.h" +#include "sfntly/port/refcount.h" +#include "sfntly/table/core/cmap_table.h" +#include "sfntly/table/truetype/glyph_table.h" +#include "sfntly/table/truetype/loca_table.h" + +namespace subtly { +class CharacterPredicate; + +typedef int32_t FontId; +typedef std::map<FontId, sfntly::Ptr<sfntly::Font> > FontIdMap; + +// Glyph id pair that contains the loca table glyph id as well as the +// font id that has the glyph table this glyph belongs to. +class GlyphId { + public: + GlyphId(int32_t glyph_id, FontId font_id); + ~GlyphId() {} + + bool operator==(const GlyphId& other) const; + bool operator<(const GlyphId& other) const; + + int32_t glyph_id() const { return glyph_id_; } + void set_glyph_id(const int32_t glyph_id) { glyph_id_ = glyph_id; } + FontId font_id() const { return font_id_; } + void set_font_id(const FontId font_id) { font_id_ = font_id; } + + private: + int32_t glyph_id_; + FontId font_id_; +}; + +typedef std::map<int32_t, GlyphId> CharacterMap; +typedef std::set<GlyphId> GlyphIdSet; + +// Font information used for FontAssembler in the construction of a new font. +// Will make copies of character map, glyph id set and font id map. +class FontInfo : public sfntly::RefCounted<FontInfo> { + public: + // Empty FontInfo object. + FontInfo(); + // chars_to_glyph_ids maps characters to GlyphIds for CMap construction + // resolved_glyph_ids defines GlyphIds which should be in the final font + // fonts is a map of font ids to fonts to reference any needed table + FontInfo(CharacterMap* chars_to_glyph_ids, + GlyphIdSet* resolved_glyph_ids, + FontIdMap* fonts); + virtual ~FontInfo(); + + // Gets the table with the specified tag from the font corresponding to + // font_id or NULL if there is no such font/table. + // font_id is the id of the font that contains the table + // tag identifies the table to be obtained + virtual sfntly::FontDataTable* GetTable(FontId font_id, int32_t tag); + // Gets the table map of the font whose id is font_id + virtual const sfntly::TableMap* GetTableMap(FontId); + + CharacterMap* chars_to_glyph_ids() const { return chars_to_glyph_ids_; } + // Takes ownership of the chars_to_glyph_ids CharacterMap. + void set_chars_to_glyph_ids(CharacterMap* chars_to_glyph_ids); + GlyphIdSet* resolved_glyph_ids() const { return resolved_glyph_ids_; } + // Takes ownership of the glyph_ids GlyphIdSet. + void set_resolved_glyph_ids(GlyphIdSet* glyph_ids); + FontIdMap* fonts() const { return fonts_; } + // Takes ownership of the fonts FontIdMap. + void set_fonts(FontIdMap* fonts); + + private: + CharacterMap* chars_to_glyph_ids_; + GlyphIdSet* resolved_glyph_ids_; + FontIdMap* fonts_; +}; + +// FontSourcedInfoBuilder is used to create a FontInfo object from a Font +// optionally specifying a CharacterPredicate to filter out some of +// the font's characters. +// It does not take ownership or copy the values its constructor receives. +class FontSourcedInfoBuilder : + public sfntly::RefCounted<FontSourcedInfoBuilder> { + public: + FontSourcedInfoBuilder(sfntly::Font* font, FontId font_id); + FontSourcedInfoBuilder(sfntly::Font* font, + FontId font_id, + CharacterPredicate* predicate); + virtual ~FontSourcedInfoBuilder() { } + + virtual CALLER_ATTACH FontInfo* GetFontInfo(); + + protected: + bool GetCharacterMap(CharacterMap* chars_to_glyph_ids); + bool ResolveCompositeGlyphs(CharacterMap* chars_to_glyph_ids, + GlyphIdSet* resolved_glyph_ids); + void Initialize(); + + private: + sfntly::Ptr<sfntly::Font> font_; + FontId font_id_; + CharacterPredicate* predicate_; + + sfntly::Ptr<sfntly::CMapTable::CMap> cmap_; + sfntly::Ptr<sfntly::LocaTable> loca_table_; + sfntly::Ptr<sfntly::GlyphTable> glyph_table_; +}; +} +#endif // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_INFO_H_ diff --git a/gfx/sfntly/cpp/src/sample/subtly/merger.cc b/gfx/sfntly/cpp/src/sample/subtly/merger.cc new file mode 100644 index 0000000000..7875c2d6b9 --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/merger.cc @@ -0,0 +1,87 @@ +/* + * 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 "subtly/merger.h" + +#include <stdio.h> + +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "subtly/character_predicate.h" +#include "subtly/font_assembler.h" +#include "subtly/font_info.h" +#include "subtly/utils.h" + +namespace subtly { +using namespace sfntly; + +/****************************************************************************** + * Merger class + ******************************************************************************/ +Merger::Merger(FontArray* fonts) { + if (!fonts) { + return; + } + int32_t num_fonts = fonts->size(); + for (int32_t i = 0; i < num_fonts; ++i) { + fonts_.insert(std::make_pair(i, fonts->at(i))); + } +} + +CALLER_ATTACH Font* Merger::Merge() { + Ptr<FontInfo> merged_info; + merged_info.Attach(MergeFontInfos()); + if (!merged_info) { +#if defined (SUBTLY_DEBUG) + fprintf(stderr, "Could not create merged font info\n"); +#endif + return NULL; + } + Ptr<FontAssembler> font_assembler = new FontAssembler(merged_info); + return font_assembler->Assemble(); +} + +CALLER_ATTACH FontInfo* Merger::MergeFontInfos() { + Ptr<FontInfo> font_info = new FontInfo; + font_info->set_fonts(&fonts_); + for (FontIdMap::iterator it = fonts_.begin(), + e = fonts_.end(); it != e; ++it) { + Ptr<FontSourcedInfoBuilder> info_builder = + new FontSourcedInfoBuilder(it->second, it->first, NULL); + Ptr<FontInfo> current_font_info; + current_font_info.Attach(info_builder->GetFontInfo()); + if (!current_font_info) { +#if defined (SUBTLY_DEBUG) + fprintf(stderr, "Couldn't create font info. " + "No subset will be generated.\n"); +#endif + return NULL; + } + font_info->chars_to_glyph_ids()->insert( + current_font_info->chars_to_glyph_ids()->begin(), + current_font_info->chars_to_glyph_ids()->end()); + font_info->resolved_glyph_ids()->insert( + current_font_info->resolved_glyph_ids()->begin(), + current_font_info->resolved_glyph_ids()->end()); +#if defined (SUBTLY_DEBUG) + fprintf(stderr, "Counts: chars_to_glyph_ids: %d; resoved_glyph_ids: %d\n", + font_info->chars_to_glyph_ids()->size(), + font_info->resolved_glyph_ids()->size()); +#endif + } + return font_info.Detach(); +} +} diff --git a/gfx/sfntly/cpp/src/sample/subtly/merger.h b/gfx/sfntly/cpp/src/sample/subtly/merger.h new file mode 100644 index 0000000000..43764a8b6c --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/merger.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_MERGER_H_ +#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_MERGER_H_ + +#include "subtly/character_predicate.h" +#include "subtly/font_info.h" + +namespace sfntly { +class Font; +} + +namespace subtly { +// Merges the subsets in the font array into a single font. +class Merger : public sfntly::RefCounted<Merger> { + public: + explicit Merger(sfntly::FontArray* fonts); + virtual ~Merger() { } + + // Performs merging returning the subsetted font. + virtual CALLER_ATTACH sfntly::Font* Merge(); + + protected: + virtual CALLER_ATTACH FontInfo* MergeFontInfos(); + + private: + FontIdMap fonts_; +}; +} + +#endif // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_MERGER_H_ diff --git a/gfx/sfntly/cpp/src/sample/subtly/merger_main.cc b/gfx/sfntly/cpp/src/sample/subtly/merger_main.cc new file mode 100644 index 0000000000..a977aa75f8 --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/merger_main.cc @@ -0,0 +1,69 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> + +#include <map> +#include <utility> + +#include "sfntly/font.h" +#include "subtly/merger.h" +#include "subtly/stats.h" +#include "subtly/utils.h" + +using namespace subtly; + +void PrintUsage(const char* program_name) { + fprintf(stdout, "Usage: %s <input_font_file1> <input_font_file2> ..." + "<input_font_filen> <output_font_file>\n", + program_name); +} + +void CheckLoading(const char* font_path, Font* font) { + if (!font || font->num_tables() == 0) { + fprintf(stderr, "Could not load font %s. Terminating.\n", font_path); + exit(1); + } +} + +int main(int argc, const char** argv) { + if (argc < 3) { + PrintUsage(argv[0]); + exit(1); + } + + FontArray fonts; + for (int32_t i = 1; i < argc - 1; ++i) { + Ptr<Font> font; + font.Attach(LoadFont(argv[i])); + CheckLoading(argv[i], font); + fonts.push_back(font); + } + + Ptr<Merger> merger = new Merger(&fonts); + FontPtr new_font; + new_font.Attach(merger->Merge()); + + fprintf(stderr, "Serializing font to %s\n", argv[argc - 1]); + SerializeFont(argv[argc - 1], new_font); + if (!new_font) { + fprintf(stdout, "Cannot create merged font.\n"); + return 1; + } + + return 0; +} diff --git a/gfx/sfntly/cpp/src/sample/subtly/stats.cc b/gfx/sfntly/cpp/src/sample/subtly/stats.cc new file mode 100644 index 0000000000..769f691e06 --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/stats.cc @@ -0,0 +1,82 @@ +/* + * 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 <stdio.h> + +#include "sfntly/font.h" +#include "sfntly/table/table.h" +#include "sfntly/tag.h" +#include "subtly/stats.h" + +namespace subtly { +using namespace sfntly; + +int32_t TotalFontSize(Font* font) { + int32_t size = 0; + const TableMap* table_map = font->GetTableMap(); + for (TableMap::const_iterator it = table_map->begin(), + e = table_map->end(); it != e; ++it) { + size += it->second->DataLength(); + } + return size; +} + +double TableSizePercent(Font* font, int32_t tag) { + TablePtr table = font->GetTable(tag); + return static_cast<double>(table->DataLength()) / TotalFontSize(font) * 100; +} + +void PrintComparison(FILE* out, Font* font, Font* new_font) { + fprintf(out, "====== Table Comparison (original v. subset) ======\n"); + const TableMap* tables = font->GetTableMap(); + for (TableMap::const_iterator it = tables->begin(), + e = tables->end(); it != e; ++it) { + char *name = TagToString(it->first); + int32_t size = it->second->DataLength(); + fprintf(out, "-- %s: %d (%lf%%) ", name, size, + TableSizePercent(font, it->first)); + delete[] name; + + Ptr<FontDataTable> new_table = new_font->GetTable(it->first); + int32_t new_size = 0; + double size_percent = 0; + if (new_table) { + new_size = new_table->DataLength(); + size_percent = subtly::TableSizePercent(new_font, it->first); + } + + if (new_size == size) { + fprintf(out, "| same size\n"); + } else { + fprintf(out, "-> %d (%lf%%) | %lf%% of original\n", new_size, + size_percent, static_cast<double>(new_size) / size * 100); + } + } +} + +void PrintStats(FILE* out, Font* font) { + fprintf(out, "====== Table Stats ======\n"); + const TableMap* tables = font->GetTableMap(); + for (TableMap::const_iterator it = tables->begin(), + e = tables->end(); it != e; ++it) { + char *name = TagToString(it->first); + int32_t size = it->second->DataLength(); + fprintf(out, "-- %s: %d (%lf%%)\n", name, size, + TableSizePercent(font, it->first)); + delete[] name; + } +} +} diff --git a/gfx/sfntly/cpp/src/sample/subtly/stats.h b/gfx/sfntly/cpp/src/sample/subtly/stats.h new file mode 100644 index 0000000000..89ef2aee19 --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/stats.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_STATS_H_ +#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_STATS_H_ + +#include <stdio.h> + +#include "sfntly/port/type.h" + +namespace sfntly { +class Font; +} + +namespace subtly { +using namespace sfntly; + +int32_t TotalFontSize(Font* font); + +double TableSizePercent(Font* font, int32_t tag); + +void PrintComparison(FILE* out, Font* font, Font* new_font); + +void PrintStats(FILE* out, Font* font); +} + +#endif // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_STATS_H_ diff --git a/gfx/sfntly/cpp/src/sample/subtly/subsetter.cc b/gfx/sfntly/cpp/src/sample/subtly/subsetter.cc new file mode 100644 index 0000000000..d09627ca35 --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/subsetter.cc @@ -0,0 +1,67 @@ +/* + * 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 "subtly/subsetter.h" + +#include <stdio.h> + +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/tag.h" +#include "subtly/character_predicate.h" +#include "subtly/font_assembler.h" +#include "subtly/font_info.h" +#include "subtly/utils.h" + +namespace subtly { +using namespace sfntly; + +/****************************************************************************** + * Subsetter class + ******************************************************************************/ +Subsetter::Subsetter(Font* font, CharacterPredicate* predicate) + : font_(font), + predicate_(predicate) { +} + +Subsetter::Subsetter(const char* font_path, CharacterPredicate* predicate) + : predicate_(predicate) { + font_.Attach(LoadFont(font_path)); +} + +CALLER_ATTACH Font* Subsetter::Subset() { + Ptr<FontSourcedInfoBuilder> info_builder = + new FontSourcedInfoBuilder(font_, 0, predicate_); + + Ptr<FontInfo> font_info; + font_info.Attach(info_builder->GetFontInfo()); + if (!font_info) { +#if defined (SUBTLY_DEBUG) + fprintf(stderr, + "Couldn't create font info. No subset will be generated.\n"); +#endif + return NULL; + } + IntegerSet* table_blacklist = new IntegerSet; + table_blacklist->insert(Tag::DSIG); + Ptr<FontAssembler> font_assembler = new FontAssembler(font_info, + table_blacklist); + Ptr<Font> font_subset; + font_subset.Attach(font_assembler->Assemble()); + delete table_blacklist; + return font_subset.Detach(); +} +} diff --git a/gfx/sfntly/cpp/src/sample/subtly/subsetter.h b/gfx/sfntly/cpp/src/sample/subtly/subsetter.h new file mode 100644 index 0000000000..a93747fafa --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/subsetter.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_SUBSETTER_H_ +#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_SUBSETTER_H_ + +#include "sfntly/font.h" +// Cannot remove this header due to Ptr<T> instantiation issue +#include "subtly/character_predicate.h" + +namespace subtly { +// Subsets a given font using a character predicate. +class Subsetter : public sfntly::RefCounted<Subsetter> { + public: + Subsetter(sfntly::Font* font, CharacterPredicate* predicate); + Subsetter(const char* font_path, CharacterPredicate* predicate); + virtual ~Subsetter() { } + + // Performs subsetting returning the subsetted font. + virtual CALLER_ATTACH sfntly::Font* Subset(); + + private: + sfntly::Ptr<sfntly::Font> font_; + sfntly::Ptr<CharacterPredicate> predicate_; +}; +} + +#endif // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_SUBSETTER_H_ diff --git a/gfx/sfntly/cpp/src/sample/subtly/subsetter_main.cc b/gfx/sfntly/cpp/src/sample/subtly/subsetter_main.cc new file mode 100644 index 0000000000..d438148680 --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/subsetter_main.cc @@ -0,0 +1,82 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> + +#include <map> +#include <utility> + +#include "sfntly/font.h" +#include "subtly/character_predicate.h" +#include "subtly/stats.h" +#include "subtly/subsetter.h" +#include "subtly/utils.h" + +using namespace subtly; + +void PrintUsage(const char* program_name) { + fprintf(stdout, "Usage: %s <input_font_file> <output_font_file>" + "<start_char> <end_char>\n", program_name); +} + +int main(int argc, const char** argv) { + const char* program_name = argv[0]; + if (argc < 5) { + PrintUsage(program_name); + exit(1); + } + + const char* input_font_path = argv[1]; + const char* output_font_path = argv[2]; + FontPtr font; + font.Attach(subtly::LoadFont(input_font_path)); + if (font->num_tables() == 0) { + fprintf(stderr, "Could not load font %s.\n", input_font_path); + exit(1); + } + + const char* start_char = argv[3]; + const char* end_char = argv[4]; + if (start_char[1] != 0) { + fprintf(stderr, "Start character %c invalid.\n", start_char[0]); + exit(1); + } + if (end_char[1] != 0) { + fprintf(stderr, "Start character %c invalid.\n", end_char[0]); + exit(1); + } + int32_t original_size = TotalFontSize(font); + + + Ptr<CharacterPredicate> range_predicate = + new AcceptRange(start_char[0], end_char[0]); + Ptr<Subsetter> subsetter = new Subsetter(font, range_predicate); + Ptr<Font> new_font; + new_font.Attach(subsetter->Subset()); + if (!new_font) { + fprintf(stdout, "Cannot create subset.\n"); + return 0; + } + + subtly::SerializeFont(output_font_path, new_font); + subtly::PrintComparison(stdout, font, new_font); + int32_t new_size = TotalFontSize(new_font); + fprintf(stdout, "Went from %d to %d: %lf%% of original\n", + original_size, new_size, + static_cast<double>(new_size) / original_size * 100); + return 0; +} diff --git a/gfx/sfntly/cpp/src/sample/subtly/utils.cc b/gfx/sfntly/cpp/src/sample/subtly/utils.cc new file mode 100644 index 0000000000..15efb7a5d4 --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/utils.cc @@ -0,0 +1,91 @@ +/* + * 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 "subtly/utils.h" + +#include "sfntly/data/growable_memory_byte_array.h" +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/port/file_input_stream.h" +#include "sfntly/port/memory_output_stream.h" + +namespace subtly { +using namespace sfntly; + +CALLER_ATTACH Font* LoadFont(const char* font_path) { + Ptr<FontFactory> font_factory; + font_factory.Attach(FontFactory::GetInstance()); + FontArray fonts; + LoadFonts(font_path, font_factory, &fonts); + return fonts[0].Detach(); +} + +CALLER_ATTACH Font::Builder* LoadFontBuilder(const char* font_path) { + FontFactoryPtr font_factory; + font_factory.Attach(FontFactory::GetInstance()); + FontBuilderArray builders; + LoadFontBuilders(font_path, font_factory, &builders); + return builders[0].Detach(); +} + +void LoadFonts(const char* font_path, FontFactory* factory, FontArray* fonts) { + FileInputStream input_stream; + input_stream.Open(font_path); + factory->LoadFonts(&input_stream, fonts); + input_stream.Close(); +} + +void LoadFontBuilders(const char* font_path, + FontFactory* factory, + FontBuilderArray* builders) { + FileInputStream input_stream; + input_stream.Open(font_path); + factory->LoadFontsForBuilding(&input_stream, builders); + input_stream.Close(); +} + +bool SerializeFont(const char* font_path, Font* font) { + if (!font_path) + return false; + FontFactoryPtr font_factory; + font_factory.Attach(FontFactory::GetInstance()); + return SerializeFont(font_path, font_factory, font); +} + +bool SerializeFont(const char* font_path, FontFactory* factory, Font* font) { + if (!font_path || !factory || !font) + return false; + // Serializing the font to a stream. + MemoryOutputStream output_stream; + factory->SerializeFont(font, &output_stream); + // Serializing the stream to a file. + FILE* output_file = NULL; +#if defined WIN32 + fopen_s(&output_file, font_path, "wb"); +#else + output_file = fopen(font_path, "wb"); +#endif + if (output_file == static_cast<FILE*>(NULL)) + return false; + for (size_t i = 0; i < output_stream.Size(); ++i) { + fwrite(&(output_stream.Get()[i]), 1, 1, output_file); + } + fflush(output_file); + fclose(output_file); + return true; +} +}; diff --git a/gfx/sfntly/cpp/src/sample/subtly/utils.h b/gfx/sfntly/cpp/src/sample/subtly/utils.h new file mode 100644 index 0000000000..ba9f0d4d6a --- /dev/null +++ b/gfx/sfntly/cpp/src/sample/subtly/utils.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_UTILS_H_ +#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_UTILS_H_ + +#include "sfntly/font.h" +#include "sfntly/font_factory.h" + +namespace subtly { +CALLER_ATTACH sfntly::Font* LoadFont(const char* font_path); +CALLER_ATTACH sfntly::Font::Builder* LoadFontBuilder(const char* font_path); + +void LoadFonts(const char* font_path, sfntly::FontFactory* factory, + sfntly::FontArray* fonts); +void LoadFontBuilders(const char* font_path, + sfntly::FontFactory* factory, + sfntly::FontBuilderArray* builders); + +bool SerializeFont(const char* font_path, sfntly::Font* font); +bool SerializeFont(const char* font_path, sfntly::FontFactory* factory, + sfntly::Font* font); +} + +#endif // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_UTILS_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/data/byte_array.cc b/gfx/sfntly/cpp/src/sfntly/data/byte_array.cc new file mode 100644 index 0000000000..f51088182b --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/byte_array.cc @@ -0,0 +1,201 @@ +/* + * 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 "sfntly/data/byte_array.h" + +#include <algorithm> + +#include "sfntly/port/exception_type.h" + +namespace sfntly { + +const int32_t ByteArray::COPY_BUFFER_SIZE = 8192; + +ByteArray::~ByteArray() {} + +int32_t ByteArray::SetFilledLength(int32_t filled_length) { + filled_length_ = std::min<int32_t>(filled_length, storage_length_); + return filled_length_; +} + +int32_t ByteArray::Get(int32_t index) { + if (index < 0 || index >= Length()) + return -1; + return InternalGet(index) & 0xff; +} + +int32_t ByteArray::Get(int32_t index, std::vector<uint8_t>* b) { + assert(b); + return Get(index, &((*b)[0]), 0, b->size()); +} + +int32_t ByteArray::Get(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length) { + assert(b); + if (index < 0 || index >= filled_length_) + return 0; + + if (length <= 0) + return 0; + + int32_t actual_length = std::min<int32_t>(length, filled_length_ - index); + return InternalGet(index, b, offset, actual_length); +} + +void ByteArray::Put(int32_t index, uint8_t b) { + if (index < 0 || index >= Size()) { +#if defined (SFNTLY_NO_EXCEPTION) + return; +#else + throw IndexOutOfBoundException( + "Attempt to write outside the bounds of the data"); +#endif + } + InternalPut(index, b); + filled_length_ = std::max<int32_t>(filled_length_, index + 1); +} + +int32_t ByteArray::Put(int index, std::vector<uint8_t>* b) { + assert(b); + return Put(index, &((*b)[0]), 0, b->size()); +} + +int32_t ByteArray::Put(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length) { + assert(b); + if (index < 0 || index >= Size()) { +#if defined (SFNTLY_NO_EXCEPTION) + return 0; +#else + throw IndexOutOfBoundException( + "Attempt to write outside the bounds of the data"); +#endif + } + int32_t actual_length = std::min<int32_t>(length, Size() - index); + int32_t bytes_written = InternalPut(index, b, offset, actual_length); + filled_length_ = std::max<int32_t>(filled_length_, index + bytes_written); + return bytes_written; +} + +int32_t ByteArray::CopyTo(ByteArray* array) { + return CopyTo(array, 0, Length()); +} + +int32_t ByteArray::CopyTo(ByteArray* array, int32_t offset, int32_t length) { + return CopyTo(0, array, offset, length); +} + +int32_t ByteArray::CopyTo(int32_t dst_offset, ByteArray* array, + int32_t src_offset, int32_t length) { + assert(array); + if (array->Size() < dst_offset + length) { // insufficient space + return -1; + } + + std::vector<uint8_t> b(COPY_BUFFER_SIZE); + int32_t bytes_read = 0; + int32_t index = 0; + int32_t remaining_length = length; + int32_t buffer_length = std::min<int32_t>(COPY_BUFFER_SIZE, length); + while ((bytes_read = + Get(index + src_offset, &(b[0]), 0, buffer_length)) > 0) { + int bytes_written = array->Put(index + dst_offset, &(b[0]), 0, bytes_read); + UNREFERENCED_PARAMETER(bytes_written); + index += bytes_read; + remaining_length -= bytes_read; + buffer_length = std::min<int32_t>(b.size(), remaining_length); + } + return index; +} + +int32_t ByteArray::CopyTo(OutputStream* os) { + return CopyTo(os, 0, Length()); +} + +int32_t ByteArray::CopyTo(OutputStream* os, int32_t offset, int32_t length) { + std::vector<uint8_t> b(COPY_BUFFER_SIZE); + int32_t bytes_read = 0; + int32_t index = 0; + int32_t buffer_length = std::min<int32_t>(COPY_BUFFER_SIZE, length); + while ((bytes_read = Get(index + offset, &(b[0]), 0, buffer_length)) > 0) { + os->Write(&b, 0, bytes_read); + index += bytes_read; + buffer_length = std::min<int32_t>(b.size(), length - index); + } + return index; +} + +bool ByteArray::CopyFrom(InputStream* is, int32_t length) { + std::vector<uint8_t> b(COPY_BUFFER_SIZE); + int32_t bytes_read = 0; + int32_t index = 0; + int32_t buffer_length = std::min<int32_t>(COPY_BUFFER_SIZE, length); + while ((bytes_read = is->Read(&b, 0, buffer_length)) > 0) { + if (Put(index, &(b[0]), 0, bytes_read) != bytes_read) { +#if defined (SFNTLY_NO_EXCEPTION) + return 0; +#else + throw IOException("Error writing bytes."); +#endif + } + index += bytes_read; + length -= bytes_read; + buffer_length = std::min<int32_t>(b.size(), length); + } + return true; +} + +bool ByteArray::CopyFrom(InputStream* is) { + std::vector<uint8_t> b(COPY_BUFFER_SIZE); + int32_t bytes_read = 0; + int32_t index = 0; + int32_t buffer_length = COPY_BUFFER_SIZE; + while ((bytes_read = is->Read(&b, 0, buffer_length)) > 0) { + if (Put(index, &b[0], 0, bytes_read) != bytes_read) { +#if defined (SFNTLY_NO_EXCEPTION) + return 0; +#else + throw IOException("Error writing bytes."); +#endif + } + index += bytes_read; + } + return true; +} + +ByteArray::ByteArray(int32_t filled_length, + int32_t storage_length, + bool growable) { + Init(filled_length, storage_length, growable); +} + +ByteArray::ByteArray(int32_t filled_length, int32_t storage_length) { + Init(filled_length, storage_length, false); +} + +void ByteArray::Init(int32_t filled_length, + int32_t storage_length, + bool growable) { + storage_length_ = storage_length; + growable_ = growable; + SetFilledLength(filled_length); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/data/byte_array.h b/gfx/sfntly/cpp/src/sfntly/data/byte_array.h new file mode 100644 index 0000000000..c5e37881dc --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/byte_array.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2011 The sfntly Open Source Project + * + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_ + +#include "sfntly/port/refcount.h" +#include "sfntly/port/type.h" +#include "sfntly/port/input_stream.h" +#include "sfntly/port/output_stream.h" + +namespace sfntly { + +// An abstraction to a contiguous array of bytes. +// C++ port of this class assumes that the data are stored in a linear region +// like std::vector. +class ByteArray : virtual public RefCount { + public: + virtual ~ByteArray(); + + // Gets the current filled and readable length of the array. + int32_t Length() const { return filled_length_; } + + // Gets the maximum size of the array. This is the maximum number of bytes that + // the array can hold and all of it may not be filled with data or even fully + // allocated yet. + int32_t Size() const { return storage_length_; } + + // Determines whether or not this array is growable or of fixed size. + bool growable() const { return growable_; } + + int32_t SetFilledLength(int32_t filled_length); + + // Gets the byte from the given index. + // @param index the index into the byte array + // @return the byte or -1 if reading beyond the bounds of the data + virtual int32_t Get(int32_t index); + + // Gets the bytes from the given index and fill the buffer with them. As many + // bytes as will fit into the buffer are read unless that would go past the + // end of the array. + // @param index the index into the byte array + // @param b the buffer to put the bytes read into + // @return the number of bytes read from the buffer + virtual int32_t Get(int32_t index, std::vector<uint8_t>* b); + + // Gets the bytes from the given index and fill the buffer with them starting + // at the offset given. As many bytes as the specified length are read unless + // that would go past the end of the array. + // @param index the index into the byte array + // @param b the buffer to put the bytes read into + // @param offset the location in the buffer to start putting the bytes + // @param length the number of bytes to put into the buffer + // @return the number of bytes read from the buffer + virtual int32_t Get(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length); + + // Puts the specified byte into the array at the given index unless that would + // be beyond the length of the array and it isn't growable. + virtual void Put(int32_t index, uint8_t b); + + // Puts the specified bytes into the array at the given index. The entire + // buffer is put into the array unless that would extend beyond the length and + // the array isn't growable. + virtual int32_t Put(int32_t index, std::vector<uint8_t>* b); + + // Puts the specified bytes into the array at the given index. All of the bytes + // specified are put into the array unless that would extend beyond the length + // and the array isn't growable. The bytes to be put into the array are those + // in the buffer from the given offset and for the given length. + // @param index the index into the ByteArray + // @param b the bytes to put into the array + // @param offset the offset in the bytes to start copying from + // @param length the number of bytes to copy into the array + // @return the number of bytes actually written + virtual int32_t Put(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length); + + // Fully copies this ByteArray to another ByteArray to the extent that the + // destination array has storage for the data copied. + virtual int32_t CopyTo(ByteArray* array); + + // Copies a segment of this ByteArray to another ByteArray. + // @param array the destination + // @param offset the offset in this ByteArray to start copying from + // @param length the maximum length in bytes to copy + // @return the number of bytes copied + virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length); + + // Copies this ByteArray to another ByteArray. + // @param dstOffset the offset in the destination array to start copying to + // @param array the destination + // @param srcOffset the offset in this ByteArray to start copying from + // @param length the maximum length in bytes to copy + // @return the number of bytes copied + virtual int32_t CopyTo(int32_t dst_offset, + ByteArray* array, + int32_t src_offset, + int32_t length); + + // Copies this ByteArray to an OutputStream. + // @param os the destination + // @return the number of bytes copied + virtual int32_t CopyTo(OutputStream* os); + + // Copies this ByteArray to an OutputStream. + // @param os the destination + // @param offset + // @param length + // @return the number of bytes copied + virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length); + + // Copies from the InputStream into this ByteArray. + // @param is the source + // @param length the number of bytes to copy + virtual bool CopyFrom(InputStream* is, int32_t length); + + // Copies everything from the InputStream into this ByteArray. + // @param is the source + virtual bool CopyFrom(InputStream* is); + + protected: + // filledLength the length that is "filled" and readable counting from offset. + // storageLength the maximum storage size of the underlying data. + // growable is the storage growable - storageLength is the max growable size. + ByteArray(int32_t filled_length, int32_t storage_length, bool growable); + ByteArray(int32_t filled_length, int32_t storage_length); + void Init(int32_t filled_length, int32_t storage_length, bool growable); + + // Internal subclass API + + // Stores the byte at the index given. + // @param index the location to store at + // @param b the byte to store + virtual void InternalPut(int32_t index, uint8_t b) = 0; + + // Stores the array of bytes at the given index. + // @param index the location to store at + // @param b the bytes to store + // @param offset the offset to start from in the byte array + // @param length the length of the byte array to store from the offset + // @return the number of bytes actually stored + virtual int32_t InternalPut(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length) = 0; + + // Gets the byte at the index given. + // @param index the location to get from + // @return the byte stored at the index + virtual uint8_t InternalGet(int32_t index) = 0; + + // Gets the bytes at the index given of the given length. + // @param index the location to start getting from + // @param b the array to put the bytes into + // @param offset the offset in the array to put the bytes into + // @param length the length of bytes to read + // @return the number of bytes actually ready + virtual int32_t InternalGet(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length) = 0; + + // Close this instance of the ByteArray. + virtual void Close() = 0; + + // C++ port only, raw pointer to the first element of storage. + virtual uint8_t* Begin() = 0; + + // Java toString() not ported. + + static const int32_t COPY_BUFFER_SIZE; + + private: + //bool bound_; // unused, comment out + int32_t filled_length_; + int32_t storage_length_; + bool growable_; +}; +typedef Ptr<ByteArray> ByteArrayPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/data/font_data.cc b/gfx/sfntly/cpp/src/sfntly/data/font_data.cc new file mode 100644 index 0000000000..8fa8610349 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/font_data.cc @@ -0,0 +1,92 @@ +/* + * 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 "sfntly/data/font_data.h" + +#include <algorithm> +#include <functional> +#include <limits> + +#include "sfntly/port/logging.h" + +namespace sfntly { + +int32_t FontData::Size() const { + return std::min<int32_t>(array_->Size() - bound_offset_, bound_length_); +} + +void FontData::Bound(int32_t offset, int32_t length) { + // Inputs should not be negative. + CHECK(offset >= 0); + CHECK(length >= 0); + + // Check to make sure |bound_offset_| will not overflow. + CHECK(bound_offset_ <= std::numeric_limits<int32_t>::max() - offset); + const int32_t new_offset = bound_offset_ + offset; + + if (length == GROWABLE_SIZE) { + // When |length| has the special value of GROWABLE_SIZE, it means the size + // should not have any artificial limits, thus it is just the underlying + // |array_|'s size. Just make sure |new_offset| is still within bounds. + CHECK(new_offset <= array_->Size()); + } else { + // When |length| has any other value, |new_offset| + |length| points to the + // end of the array. Make sure that is within bounds, but use subtraction to + // avoid an integer overflow. + CHECK(new_offset <= array_->Size() - length); + } + + bound_offset_ = new_offset; + bound_length_ = length; +} + +int32_t FontData::Length() const { + return std::min<int32_t>(array_->Length() - bound_offset_, bound_length_); +} + +FontData::FontData(ByteArray* ba) { + Init(ba); +} + +FontData::FontData(FontData* data, int32_t offset, int32_t length) { + Init(data->array_); + Bound(data->bound_offset_ + offset, length); +} + +FontData::FontData(FontData* data, int32_t offset) { + Init(data->array_); + Bound(data->bound_offset_ + offset, + (data->bound_length_ == GROWABLE_SIZE) + ? GROWABLE_SIZE : data->bound_length_ - offset); +} + +FontData::~FontData() {} + +void FontData::Init(ByteArray* ba) { + array_ = ba; + bound_offset_ = 0; + bound_length_ = GROWABLE_SIZE; +} + +int32_t FontData::BoundOffset(int32_t offset) const { + return offset + bound_offset_; +} + +int32_t FontData::BoundLength(int32_t offset, int32_t length) const { + return std::min<int32_t>(length, bound_length_ - offset); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/data/font_data.h b/gfx/sfntly/cpp/src/sfntly/data/font_data.h new file mode 100644 index 0000000000..20c7e37d4a --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/font_data.h @@ -0,0 +1,124 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_ + +#include <limits.h> + +#include "sfntly/data/byte_array.h" +#include "sfntly/port/refcount.h" +#include "sfntly/port/type.h" + +namespace sfntly { + +struct DataSize { + enum { + kBYTE = 1, + kCHAR = 1, + kUSHORT = 2, + kSHORT = 2, + kUINT24 = 3, + kULONG = 4, + kLONG = 4, + kFixed = 4, + kFUNIT = 4, + kFWORD = 2, + kUFWORD = 2, + kF2DOT14 = 2, + kLONGDATETIME = 8, + kTag = 4, + kGlyphID = 2, + kOffset = 2 + }; +}; + +class FontData : virtual public RefCount { + public: + // Gets the maximum size of the FontData. This is the maximum number of bytes + // that the font data can hold and all of it may not be filled with data or + // even fully allocated yet. + // @return the maximum size of this font data + virtual int32_t Size() const; + + // Sets limits on the size of the FontData. The FontData is then only + // visible within the bounds set. + // @param offset the start of the new bounds + // @param length the number of bytes in the bounded array + virtual void Bound(int32_t offset, int32_t length); + + // Makes a slice of this FontData. The returned slice will share the data with + // the original <code>FontData</code>. + // @param offset the start of the slice + // @param length the number of bytes in the slice + // @return a slice of the original FontData + virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length) = 0; + + // Makes a bottom bound only slice of this array. The returned slice will + // share the data with the original <code>FontData</code>. + // @param offset the start of the slice + // @return a slice of the original FontData + virtual CALLER_ATTACH FontData* Slice(int32_t offset) = 0; + + // Gets the length of the data. + virtual int32_t Length() const; + + protected: + // Constructor. + // @param ba the byte array to use for the backing data + explicit FontData(ByteArray* ba); + + // Constructor. + // @param data the data to wrap + // @param offset the offset to start the wrap from + // @param length the length of the data wrapped + FontData(FontData* data, int32_t offset, int32_t length); + + // Constructor. + // @param data the data to wrap + // @param offset the offset to start the wrap from + FontData(FontData* data, int32_t offset); + virtual ~FontData(); + + void Init(ByteArray* ba); + + // Gets the offset in the underlying data taking into account any bounds on + // the data. + // @param offset the offset to get the bound compensated offset for + // @return the bound compensated offset + int32_t BoundOffset(int32_t offset) const; + + // Gets the length in the underlying data taking into account any bounds on + // the data. + // @param offset the offset that the length is being used at + // @param length the length to get the bound compensated length for + // @return the bound compensated length + int32_t BoundLength(int32_t offset, int32_t length) const; + + static const int32_t GROWABLE_SIZE = INT_MAX; + + // TODO(arthurhsu): style guide violation: refactor this protected member + ByteArrayPtr array_; + + private: + int32_t bound_offset_; + int32_t bound_length_; +}; +typedef Ptr<FontData> FontDataPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/data/font_input_stream.cc b/gfx/sfntly/cpp/src/sfntly/data/font_input_stream.cc new file mode 100644 index 0000000000..87a515b2a0 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/font_input_stream.cc @@ -0,0 +1,148 @@ +/* + * 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 "sfntly/data/font_input_stream.h" + +#include <algorithm> + +namespace sfntly { + +FontInputStream::FontInputStream(InputStream* is) + : stream_(is), position_(0), length_(0), bounded_(false) { +} + +FontInputStream::FontInputStream(InputStream* is, size_t length) + : stream_(is), position_(0), length_(length), bounded_(true) { +} + +FontInputStream::~FontInputStream() { + // Do not close here, underlying InputStream will close themselves. +} + +int32_t FontInputStream::Length() { + if (bounded_) + return length_; + if (stream_) + return stream_->Length(); + return 0; +} + +int32_t FontInputStream::Available() { + if (stream_) + return stream_->Available(); + return 0; +} + +void FontInputStream::Close() { + if (stream_) { + stream_->Close(); + } +} + +void FontInputStream::Mark(int32_t readlimit) { + if (stream_) { + stream_->Mark(readlimit); + } +} + +bool FontInputStream::MarkSupported() { + if (stream_) { + return stream_->MarkSupported(); + } + return false; +} + +void FontInputStream::Reset() { + if (stream_) { + stream_->Reset(); + } +} + +int32_t FontInputStream::Read() { + if (!stream_ || (bounded_ && position_ >= length_)) { + return -1; + } + int32_t b = stream_->Read(); + if (b >= 0) { + position_++; + } + return b; +} + +int32_t FontInputStream::Read(std::vector<uint8_t>* b, int32_t offset, int32_t length) { + if (!stream_ || offset < 0 || length < 0 || + (bounded_ && position_ >= length_)) { + return -1; + } + int32_t bytes_to_read = + bounded_ ? std::min<int32_t>(length, (int32_t)(length_ - position_)) : + length; + int32_t bytes_read = stream_->Read(b, offset, bytes_to_read); + position_ += bytes_read; + return bytes_read; +} + +int32_t FontInputStream::Read(std::vector<uint8_t>* b) { + return Read(b, 0, b->size()); +} + +int32_t FontInputStream::ReadChar() { + return Read(); +} + +int32_t FontInputStream::ReadUShort() { + return 0xffff & (Read() << 8 | Read()); +} + +int32_t FontInputStream::ReadShort() { + return ((Read() << 8 | Read()) << 16) >> 16; +} + +int32_t FontInputStream::ReadUInt24() { + return 0xffffff & (Read() << 16 | Read() << 8 | Read()); +} + +int64_t FontInputStream::ReadULong() { + return 0xffffffffL & ReadLong(); +} + +int32_t FontInputStream::ReadULongAsInt() { + int64_t ulong = ReadULong(); + return ((int32_t)ulong) & ~0x80000000; +} + +int32_t FontInputStream::ReadLong() { + return Read() << 24 | Read() << 16 | Read() << 8 | Read(); +} + +int32_t FontInputStream::ReadFixed() { + return ReadLong(); +} + +int64_t FontInputStream::ReadDateTimeAsLong() { + return (int64_t)ReadULong() << 32 | ReadULong(); +} + +int64_t FontInputStream::Skip(int64_t n) { + if (stream_) { + int64_t skipped = stream_->Skip(n); + position_ += skipped; + return skipped; + } + return 0; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/data/font_input_stream.h b/gfx/sfntly/cpp/src/sfntly/data/font_input_stream.h new file mode 100644 index 0000000000..c02848d947 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/font_input_stream.h @@ -0,0 +1,97 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_ + +#include "sfntly/port/type.h" +#include "sfntly/port/input_stream.h" + +namespace sfntly { + +// An input stream for reading font data. +// The data types used are as listed: +// BYTE 8-bit unsigned integer. +// CHAR 8-bit signed integer. +// USHORT 16-bit unsigned integer. +// SHORT 16-bit signed integer. +// UINT24 24-bit unsigned integer. +// ULONG 32-bit unsigned integer. +// LONG 32-bit signed integer. +// Fixed 32-bit signed fixed-point number (16.16) +// FUNIT Smallest measurable distance in the em space. +// FWORD 16-bit signed integer (SHORT) that describes a quantity in FUnits. +// UFWORD 16-bit unsigned integer (USHORT) that describes a quantity in +// FUnits. +// F2DOT14 16-bit signed fixed number with the low 14 bits of fraction (2.14) +// LONGDATETIME Date represented in number of seconds since 12:00 midnight, +// January 1, 1904. The value is represented as a signed 64-bit +// integer. + +// Note: Original class inherits from Java's FilterOutputStream, which wraps +// an InputStream within. In C++, we directly do the wrapping without +// defining another layer of abstraction. The wrapped output stream is +// *NOT* reference counted (because it's meaningless to ref-count an I/O +// stream). +class FontInputStream : public InputStream { + public: + // Constructor. + // @param is input stream to wrap + explicit FontInputStream(InputStream* is); + + // Constructor for a bounded font input stream. + // @param is input stream to wrap + // @param length the maximum length of bytes to read + FontInputStream(InputStream* is, size_t length); + + virtual ~FontInputStream(); + + virtual int32_t Length(); + virtual int32_t Available(); + virtual void Close(); + virtual void Mark(int32_t readlimit); + virtual bool MarkSupported(); + virtual void Reset(); + + virtual int32_t Read(); + virtual int32_t Read(std::vector<uint8_t>* buffer); + virtual int32_t Read(std::vector<uint8_t>* buffer, int32_t offset, int32_t length); + + // Get the current position in the stream in bytes. + // @return the current position in bytes + virtual int64_t position() { return position_; } + + virtual int32_t ReadChar(); + virtual int32_t ReadUShort(); + virtual int32_t ReadShort(); + virtual int32_t ReadUInt24(); + virtual int64_t ReadULong(); + virtual int32_t ReadULongAsInt(); + virtual int32_t ReadLong(); + virtual int32_t ReadFixed(); + virtual int64_t ReadDateTimeAsLong(); + virtual int64_t Skip(int64_t n); // n can be negative. + + private: + InputStream* stream_; + int64_t position_; + int64_t length_; // Bound on length of data to read. + bool bounded_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/data/font_output_stream.cc b/gfx/sfntly/cpp/src/sfntly/data/font_output_stream.cc new file mode 100644 index 0000000000..169b02f511 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/font_output_stream.cc @@ -0,0 +1,130 @@ +/* + * 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 "sfntly/data/font_output_stream.h" + +#include <algorithm> + +namespace sfntly { + +FontOutputStream::FontOutputStream(OutputStream* os) + : stream_(os), + position_(0) { +} + +FontOutputStream::~FontOutputStream() { + // Do not close, underlying stream shall clean up themselves. +} + +void FontOutputStream::Write(uint8_t b) { + if (stream_) { + stream_->Write(b); + position_++; + } +} + +void FontOutputStream::Write(std::vector<uint8_t>* b) { + if (b) { + Write(b, 0, b->size()); + position_ += b->size(); + } +} + +void FontOutputStream::Write(std::vector<uint8_t>* b, int32_t off, int32_t len) { + assert(b); + assert(stream_); + if (off < 0 || len < 0 || off + len < 0 || + static_cast<size_t>(off + len) > b->size()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#else + return; +#endif + } + + stream_->Write(b, off, len); + position_ += len; +} + +void FontOutputStream::Write(uint8_t* b, int32_t off, int32_t len) { + assert(b); + assert(stream_); + if (off < 0 || len < 0 || off + len < 0) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#else + return; +#endif + } + + stream_->Write(b, off, len); + position_ += len; +} + +void FontOutputStream::WriteChar(uint8_t c) { + Write(c); +} + +void FontOutputStream::WriteUShort(int32_t us) { + Write((uint8_t)((us >> 8) & 0xff)); + Write((uint8_t)(us & 0xff)); +} + +void FontOutputStream::WriteShort(int32_t s) { + WriteUShort(s); +} + +void FontOutputStream::WriteUInt24(int32_t ui) { + Write((uint8_t)(ui >> 16) & 0xff); + Write((uint8_t)(ui >> 8) & 0xff); + Write((uint8_t)ui & 0xff); +} + +void FontOutputStream::WriteULong(int64_t ul) { + Write((uint8_t)((ul >> 24) & 0xff)); + Write((uint8_t)((ul >> 16) & 0xff)); + Write((uint8_t)((ul >> 8) & 0xff)); + Write((uint8_t)(ul & 0xff)); +} + +void FontOutputStream::WriteLong(int64_t l) { + WriteULong(l); +} + +void FontOutputStream::WriteFixed(int32_t f) { + WriteULong(f); +} + +void FontOutputStream::WriteDateTime(int64_t date) { + WriteULong((date >> 32) & 0xffffffff); + WriteULong(date & 0xffffffff); +} + +void FontOutputStream::Flush() { + if (stream_) { + stream_->Flush(); + } +} + +void FontOutputStream::Close() { + if (stream_) { + stream_->Flush(); + stream_->Close(); + position_ = 0; + } +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/data/font_output_stream.h b/gfx/sfntly/cpp/src/sfntly/data/font_output_stream.h new file mode 100644 index 0000000000..fa4d346b69 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/font_output_stream.h @@ -0,0 +1,77 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_ + +#include "sfntly/port/type.h" +#include "sfntly/port/output_stream.h" + +namespace sfntly { + +// An output stream for writing font data. +// The data types used are as listed: +// BYTE 8-bit unsigned integer. +// CHAR 8-bit signed integer. +// USHORT 16-bit unsigned integer. +// SHORT 16-bit signed integer. +// UINT24 24-bit unsigned integer. +// ULONG 32-bit unsigned integer. +// LONG 32-bit signed integer. +// Fixed 32-bit signed fixed-point number (16.16) +// FUNIT Smallest measurable distance in the em space. +// FWORD 16-bit signed integer (SHORT) that describes a quantity in FUnits. +// UFWORD 16-bit unsigned integer (USHORT) that describes a quantity in +// FUnits. +// F2DOT14 16-bit signed fixed number with the low 14 bits of fraction (2.14) +// LONGDATETIME Date represented in number of seconds since 12:00 midnight, +// January 1, 1904. The value is represented as a signed 64-bit +// integer. + +// Note: The wrapped output stream is *NOT* reference counted (because it's +// meaningless to ref-count an I/O stream). +class FontOutputStream : public OutputStream { + public: + explicit FontOutputStream(OutputStream* os); + virtual ~FontOutputStream(); + + virtual void Write(uint8_t b); + virtual void Write(std::vector<uint8_t>* b); + virtual void Write(std::vector<uint8_t>* b, int32_t off, int32_t len); + virtual void Write(uint8_t* b, int32_t off, int32_t len); + virtual void WriteChar(uint8_t c); + virtual void WriteUShort(int32_t us); + virtual void WriteShort(int32_t s); + virtual void WriteUInt24(int32_t ui); + virtual void WriteULong(int64_t ul); + virtual void WriteLong(int64_t l); + virtual void WriteFixed(int32_t l); + virtual void WriteDateTime(int64_t date); + + // Note: C++ port only. + virtual void Flush(); + virtual void Close(); + + private: + // Note: we do not use the variable name out as in Java because it has + // special meaning in VC++ and will be very confusing. + OutputStream* stream_; + size_t position_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/data/growable_memory_byte_array.cc b/gfx/sfntly/cpp/src/sfntly/data/growable_memory_byte_array.cc new file mode 100644 index 0000000000..b7b10fcdf8 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/growable_memory_byte_array.cc @@ -0,0 +1,82 @@ +/* + * 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 "sfntly/data/growable_memory_byte_array.h" + +#include <limits.h> +#include <string.h> + +#include <algorithm> + +namespace sfntly { + +GrowableMemoryByteArray::GrowableMemoryByteArray() + : ByteArray(0, INT_MAX, true) { + // Note: We did not set an initial size of array like Java because STL + // implementation will determine the best strategy. +} + +GrowableMemoryByteArray::~GrowableMemoryByteArray() {} + +int32_t GrowableMemoryByteArray::CopyTo(OutputStream* os, + int32_t offset, + int32_t length) { + assert(os); + os->Write(&b_, offset, length); + return length; +} + +void GrowableMemoryByteArray::InternalPut(int32_t index, uint8_t b) { + if ((size_t)index >= b_.size()) { + b_.resize((size_t)(index + 1)); + } + b_[index] = b; +} + +int32_t GrowableMemoryByteArray::InternalPut(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length) { + if ((size_t)index + length >= b_.size()) { + // Note: We grow one byte more than Java version. VC debuggers shows + // data better this way. + b_.resize((size_t)(index + length + 1)); + } + std::copy(b + offset, b + offset + length, b_.begin() + index); + return length; +} + +uint8_t GrowableMemoryByteArray::InternalGet(int32_t index) { + return b_[index]; +} + +int32_t GrowableMemoryByteArray::InternalGet(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length) { + memcpy(b + offset, &(b_[0]) + index, length); + return length; +} + +void GrowableMemoryByteArray::Close() { + b_.clear(); +} + +uint8_t* GrowableMemoryByteArray::Begin() { + return &(b_[0]); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/data/growable_memory_byte_array.h b/gfx/sfntly/cpp/src/sfntly/data/growable_memory_byte_array.h new file mode 100644 index 0000000000..370d2cb732 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/growable_memory_byte_array.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_ + +#include "sfntly/data/byte_array.h" + +namespace sfntly { + +// Note: This is not really a port of Java version. Instead, this wraps a +// std::vector inside and let it grow by calling resize(). +class GrowableMemoryByteArray : public ByteArray, + public RefCounted<GrowableMemoryByteArray> { + public: + GrowableMemoryByteArray(); + virtual ~GrowableMemoryByteArray(); + virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length); + + // Make gcc -Woverloaded-virtual happy. + virtual int32_t CopyTo(ByteArray* array) { return ByteArray::CopyTo(array); } + virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length) { + return ByteArray::CopyTo(array, offset, length); + } + virtual int32_t CopyTo(int32_t dst_offset, + ByteArray* array, + int32_t src_offset, + int32_t length) { + return ByteArray::CopyTo(dst_offset, array, src_offset, length); + } + virtual int32_t CopyTo(OutputStream* os) { return ByteArray::CopyTo(os); } + + protected: + virtual void InternalPut(int32_t index, uint8_t b); + virtual int32_t InternalPut(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length); + virtual uint8_t InternalGet(int32_t index); + virtual int32_t InternalGet(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length); + virtual void Close(); + virtual uint8_t* Begin(); + + private: + std::vector<uint8_t> b_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/data/memory_byte_array.cc b/gfx/sfntly/cpp/src/sfntly/data/memory_byte_array.cc new file mode 100644 index 0000000000..9a81cf6a40 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/memory_byte_array.cc @@ -0,0 +1,93 @@ +/* + * 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 "sfntly/data/memory_byte_array.h" + +#include <string.h> + +namespace sfntly { + +MemoryByteArray::MemoryByteArray(int32_t length) + : ByteArray(0, length), b_(NULL), allocated_(true) { +} + +MemoryByteArray::MemoryByteArray(uint8_t* b, int32_t filled_length) + : ByteArray(filled_length, filled_length), b_(b), allocated_(false) { + assert(b); +} + +MemoryByteArray::~MemoryByteArray() { + Close(); +} + +int32_t MemoryByteArray::CopyTo(OutputStream* os, + int32_t offset, + int32_t length) { + assert(os); + os->Write(b_, offset, length); + return length; +} + +void MemoryByteArray::Init() { + if (allocated_ && b_ == NULL) { + b_ = new uint8_t[Size()]; + memset(b_, 0, Size()); + } +} + +void MemoryByteArray::InternalPut(int32_t index, uint8_t b) { + Init(); + b_[index] = b; +} + +int32_t MemoryByteArray::InternalPut(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length) { + assert(b); + Init(); + memcpy(b_ + index, b + offset, length); + return length; +} + +uint8_t MemoryByteArray::InternalGet(int32_t index) { + Init(); + return b_[index]; +} + +int32_t MemoryByteArray::InternalGet(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length) { + assert(b); + Init(); + memcpy(b + offset, b_ + index, length); + return length; +} + +void MemoryByteArray::Close() { + if (allocated_ && b_) { + delete[] b_; + } + b_ = NULL; +} + +uint8_t* MemoryByteArray::Begin() { + Init(); + return b_; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/data/memory_byte_array.h b/gfx/sfntly/cpp/src/sfntly/data/memory_byte_array.h new file mode 100644 index 0000000000..b84cc5a11e --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/memory_byte_array.h @@ -0,0 +1,81 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_ + +#include "sfntly/data/byte_array.h" + +namespace sfntly { + +class MemoryByteArray : public ByteArray, public RefCounted<MemoryByteArray> { + public: + // Construct a new MemoryByteArray with a new array of the size given. It is + // assumed that none of the array is filled and readable. + explicit MemoryByteArray(int32_t length); + + // Note: not implemented due to dangerous operations in constructor. + //explicit MemoryByteArray(std::vector<uint8_t>* b); + + // Construct a new MemoryByteArray using byte array. + // @param b the byte array that provides the actual storage + // @param filled_length the index of the last byte in the array has data + // Note: This is different from Java version, it does not take over the + // ownership of b. Caller is responsible for handling the lifetime + // of b. C++ port also assumes filled_length is buffer_length since + // there is not a reliable way to identify the actual size of buffer. + MemoryByteArray(uint8_t* b, int32_t filled_length); + + virtual ~MemoryByteArray(); + virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length); + + // Make gcc -Woverloaded-virtual happy. + virtual int32_t CopyTo(ByteArray* array) { return ByteArray::CopyTo(array); } + virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length) { + return ByteArray::CopyTo(array, offset, length); + } + virtual int32_t CopyTo(int32_t dst_offset, + ByteArray* array, + int32_t src_offset, + int32_t length) { + return ByteArray::CopyTo(dst_offset, array, src_offset, length); + } + virtual int32_t CopyTo(OutputStream* os) { return ByteArray::CopyTo(os); } + + protected: + virtual void InternalPut(int32_t index, uint8_t b); + virtual int32_t InternalPut(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length); + virtual uint8_t InternalGet(int32_t index); + virtual int32_t InternalGet(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length); + virtual void Close(); + virtual uint8_t* Begin(); + + private: + void Init(); // C++ port only, used to allocate memory outside constructor. + + uint8_t* b_; + bool allocated_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/data/readable_font_data.cc b/gfx/sfntly/cpp/src/sfntly/data/readable_font_data.cc new file mode 100644 index 0000000000..b7c53323e2 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/readable_font_data.cc @@ -0,0 +1,395 @@ +/* + * 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 "sfntly/data/readable_font_data.h" + +#include <stdio.h> + +#include <limits> + +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/data/writable_font_data.h" +#include "sfntly/port/exception_type.h" + +namespace sfntly { + +ReadableFontData::ReadableFontData(ByteArray* array) + : FontData(array), + checksum_set_(false), + checksum_(0) { +} + +ReadableFontData::~ReadableFontData() {} + +// TODO(arthurhsu): re-investigate the memory model of this function. It's +// not too useful without copying, but it's not performance +// savvy to do copying. +CALLER_ATTACH +ReadableFontData* ReadableFontData::CreateReadableFontData(std::vector<uint8_t>* b) { + assert(b); + ByteArrayPtr ba = new MemoryByteArray(b->size()); + ba->Put(0, b); + ReadableFontDataPtr wfd = new ReadableFontData(ba); + return wfd.Detach(); +} + +int64_t ReadableFontData::Checksum() { + AutoLock lock(checksum_lock_); + if (!checksum_set_) { + ComputeChecksum(); + } + return checksum_; +} + +void ReadableFontData::SetCheckSumRanges(const std::vector<int32_t>& ranges) { + checksum_range_ = ranges; + checksum_set_ = false; // UNIMPLEMENTED: atomicity +} + +int32_t ReadableFontData::ReadUByte(int32_t index) { + int32_t b = array_->Get(BoundOffset(index)); + if (b < 0) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException( + "Index attempted to be read from is out of bounds", index); +#endif + return kInvalidUnsigned; + } + return b; +} + +int32_t ReadableFontData::ReadByte(int32_t index) { + int32_t b = array_->Get(BoundOffset(index)); + if (b < 0) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException( + "Index attempted to be read from is out of bounds", index); +#endif + return kInvalidByte; + } + return (b << 24) >> 24; +} + +int32_t ReadableFontData::ReadBytes(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length) { + return array_->Get(BoundOffset(index), b, offset, BoundLength(index, length)); +} + +int32_t ReadableFontData::ReadChar(int32_t index) { + return ReadUByte(index); +} + +int32_t ReadableFontData::ReadUShort(int32_t index) { + int32_t b1 = ReadUByte(index); + if (b1 < 0) + return kInvalidUnsigned; + int32_t b2 = ReadUByte(index + 1); + if (b2 < 0) + return kInvalidUnsigned; + return 0xffff & (b1 << 8 | b2); +} + +int32_t ReadableFontData::ReadShort(int32_t index) { + int32_t b1 = ReadByte(index); + if (b1 == kInvalidByte) + return kInvalidShort; + int32_t b2 = ReadUByte(index + 1); + if (b2 < 0) + return kInvalidShort; + + uint32_t result = static_cast<uint32_t>(b1) << 8 | b2; + return static_cast<int32_t>(result << 16) >> 16; +} + +int32_t ReadableFontData::ReadUInt24(int32_t index) { + int32_t b1 = ReadUByte(index); + if (b1 < 0) + return kInvalidUnsigned; + int32_t b2 = ReadUByte(index + 1); + if (b2 < 0) + return kInvalidUnsigned; + int32_t b3 = ReadUByte(index + 2); + if (b3 < 0) + return kInvalidUnsigned; + return 0xffffff & (b1 << 16 | b2 << 8 | b3); +} + +int64_t ReadableFontData::ReadULong(int32_t index) { + int32_t b1 = ReadUByte(index); + if (b1 < 0) + return kInvalidUnsigned; + int32_t b2 = ReadUByte(index + 1); + if (b2 < 0) + return kInvalidUnsigned; + int32_t b3 = ReadUByte(index + 2); + if (b3 < 0) + return kInvalidUnsigned; + int32_t b4 = ReadUByte(index + 3); + if (b4 < 0) + return kInvalidUnsigned; + return 0xffffffffL & (b1 << 24 | b2 << 16 | b3 << 8 | b4); +} + +int32_t ReadableFontData::ReadULongAsInt(int32_t index) { + int64_t ulong = ReadULong(index); +#if !defined (SFNTLY_NO_EXCEPTION) + if ((ulong & 0x80000000) == 0x80000000) { + throw ArithmeticException("Long value too large to fit into an integer."); + } +#endif + return static_cast<int32_t>(ulong); +} + +int64_t ReadableFontData::ReadULongLE(int32_t index) { + int32_t b1 = ReadUByte(index); + if (b1 < 0) + return kInvalidUnsigned; + int32_t b2 = ReadUByte(index + 1); + if (b2 < 0) + return kInvalidUnsigned; + int32_t b3 = ReadUByte(index + 2); + if (b3 < 0) + return kInvalidUnsigned; + int32_t b4 = ReadUByte(index + 3); + if (b4 < 0) + return kInvalidUnsigned; + return 0xffffffffL & (b1 | b2 << 8 | b3 << 16 | b4 << 24); +} + +int32_t ReadableFontData::ReadLong(int32_t index) { + int32_t b1 = ReadByte(index); + if (b1 == kInvalidByte) + return kInvalidLong; + int32_t b2 = ReadUByte(index + 1); + if (b2 < 0) + return kInvalidLong; + int32_t b3 = ReadUByte(index + 2); + if (b3 < 0) + return kInvalidLong; + int32_t b4 = ReadUByte(index + 3); + if (b4 < 0) + return kInvalidLong; + return static_cast<uint32_t>(b1) << 24 | b2 << 16 | b3 << 8 | b4; +} + +int32_t ReadableFontData::ReadFixed(int32_t index) { + return ReadLong(index); +} + +int64_t ReadableFontData::ReadDateTimeAsLong(int32_t index) { + int64_t high = ReadULong(index); + if (high == kInvalidUnsigned) + return kInvalidLongDateTime; + int64_t low = ReadULong(index + 4); + if (low == kInvalidUnsigned) + return kInvalidLongDateTime; + return high << 32 | low; +} + +int32_t ReadableFontData::ReadFWord(int32_t index) { + return ReadShort(index); +} + +int32_t ReadableFontData::ReadFUFWord(int32_t index) { + return ReadUShort(index); +} + +int32_t ReadableFontData::CopyTo(OutputStream* os) { + return array_->CopyTo(os, BoundOffset(0), Length()); +} + +int32_t ReadableFontData::CopyTo(WritableFontData* wfd) { + return array_->CopyTo(wfd->BoundOffset(0), + wfd->array_, + BoundOffset(0), + Length()); +} + +int32_t ReadableFontData::CopyTo(ByteArray* ba) { + return array_->CopyTo(ba, BoundOffset(0), Length()); +} + +int32_t ReadableFontData::SearchUShort(int32_t start_index, + int32_t start_offset, + int32_t end_index, + int32_t end_offset, + int32_t length, + int32_t key) { + int32_t location = 0; + int32_t bottom = 0; + int32_t top = length; + while (top != bottom) { + location = (top + bottom) / 2; + int32_t location_start = ReadUShort(start_index + location * start_offset); + if (key < location_start) { + // location is below current location + top = location; + } else { + // is key below the upper bound? + int32_t location_end = ReadUShort(end_index + location * end_offset); +#if defined (SFNTLY_DEBUG_FONTDATA) + fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end); +#endif + if (key <= location_end) + return location; + + // location is above the current location + bottom = location + 1; + } + } + return -1; +} + +int32_t ReadableFontData::SearchUShort(int32_t start_index, + int32_t start_offset, + int32_t length, + int32_t key) { + int32_t location = 0; + int32_t bottom = 0; + int32_t top = length; + while (top != bottom) { + location = (top + bottom) / 2; + int32_t location_start = ReadUShort(start_index + location * start_offset); + if (key == location_start) + return location; + + if (key < location_start) { + // location is below current location + top = location; + } else { + // location is above current location + bottom = location + 1; + } + } + return -1; +} + +int32_t ReadableFontData::SearchULong(int32_t start_index, + int32_t start_offset, + int32_t end_index, + int32_t end_offset, + int32_t length, + int32_t key) { + int32_t location = 0; + int32_t bottom = 0; + int32_t top = length; + while (top != bottom) { + location = (top + bottom) / 2; + int32_t location_start = ReadULongAsInt(start_index + + location * start_offset); + if (key < location_start) { + // location is below current location + top = location; + } else { + // is key below the upper bound? + int32_t location_end = ReadULongAsInt(end_index + location * end_offset); +#if defined (SFNTLY_DEBUG_FONTDATA) + fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end); +#endif + if (key <= location_end) + return location; + + // location is above the current location + bottom = location + 1; + } + } + return -1; +} + +CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset, + int32_t length) { + if (offset < 0 || length < 0 || + offset > std::numeric_limits<int32_t>::max() - length || + offset + length > Size()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException( + "Attempt to bind data outside of its limits"); +#endif + return NULL; + } + FontDataPtr slice = new ReadableFontData(this, offset, length); + return slice.Detach(); +} + +CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset) { + if (offset < 0 || offset > Size()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException( + "Attempt to bind data outside of its limits"); +#endif + return NULL; + } + FontDataPtr slice = new ReadableFontData(this, offset); + return slice.Detach(); +} + +ReadableFontData::ReadableFontData(ReadableFontData* data, int32_t offset) + : FontData(data, offset), + checksum_set_(false), + checksum_(0) { +} + +ReadableFontData::ReadableFontData(ReadableFontData* data, + int32_t offset, + int32_t length) + : FontData(data, offset, length), + checksum_set_(false), + checksum_(0) { +} + +void ReadableFontData::ComputeChecksum() { + // TODO(arthurhsu): IMPLEMENT: synchronization/atomicity + int64_t sum = 0; + if (checksum_range_.empty()) { + sum = ComputeCheckSum(0, Length()); + } else { + for (uint32_t low_bound_index = 0; low_bound_index < checksum_range_.size(); + low_bound_index += 2) { + int32_t low_bound = checksum_range_[low_bound_index]; + int32_t high_bound = (low_bound_index == checksum_range_.size() - 1) ? + Length() : + checksum_range_[low_bound_index + 1]; + sum += ComputeCheckSum(low_bound, high_bound); + } + } + + checksum_ = sum & 0xffffffffL; + checksum_set_ = true; +} + +int64_t ReadableFontData::ComputeCheckSum(int32_t low_bound, + int32_t high_bound) { + int64_t sum = 0; + // Checksum all whole 4-byte chunks. + for (int32_t i = low_bound; i <= high_bound - 4; i += 4) { + sum += ReadULong(i); + } + + // Add last fragment if not 4-byte multiple + int32_t off = high_bound & -4; + if (off < high_bound) { + int32_t b3 = ReadUByte(off); + int32_t b2 = (off + 1 < high_bound) ? ReadUByte(off + 1) : 0; + int32_t b1 = (off + 2 < high_bound) ? ReadUByte(off + 2) : 0; + int32_t b0 = 0; + sum += (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; + } + return sum; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/data/readable_font_data.h b/gfx/sfntly/cpp/src/sfntly/data/readable_font_data.h new file mode 100644 index 0000000000..db5e70c3ba --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/readable_font_data.h @@ -0,0 +1,315 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_ + +#include "sfntly/data/font_data.h" +#include "sfntly/port/lock.h" + +namespace sfntly { + +class OutputStream; +class WritableFontData; + +// Writable font data wrapper. Supports reading of data primitives in the +// TrueType / OpenType spec. +// The data types used are as listed: +// BYTE 8-bit unsigned integer. +// CHAR 8-bit signed integer. +// USHORT 16-bit unsigned integer. +// SHORT 16-bit signed integer. +// UINT24 24-bit unsigned integer. +// ULONG 32-bit unsigned integer. +// LONG 32-bit signed integer. +// Fixed 32-bit signed fixed-point number (16.16) +// FUNIT Smallest measurable distance in the em space. +// FWORD 16-bit signed integer (SHORT) that describes a quantity in FUnits. +// UFWORD 16-bit unsigned integer (USHORT) that describes a quantity in +// FUnits. +// F2DOT14 16-bit signed fixed number with the low 14 bits of fraction (2.14) +// LONGDATETIME Date represented in number of seconds since 12:00 midnight, +// January 1, 1904. The value is represented as a signed 64-bit +// integer. + +class ReadableFontData : public FontData, + public RefCounted<ReadableFontData> { + public: + explicit ReadableFontData(ByteArray* array); + virtual ~ReadableFontData(); + + static const int32_t kInvalidByte = 128; + static const int32_t kInvalidShort = 32768; + static const int32_t kInvalidLong = 0xffffffff; + static const int32_t kInvalidUnsigned = -1; + static const int64_t kInvalidLongDateTime = -1; + + static CALLER_ATTACH ReadableFontData* CreateReadableFontData(std::vector<uint8_t>* b); + + // Gets a computed checksum for the data. This checksum uses the OpenType spec + // calculation. Every ULong value (32 bit unsigned) in the data is summed and + // the resulting value is truncated to 32 bits. If the data length in bytes is + // not an integral multiple of 4 then any remaining bytes are treated as the + // start of a 4 byte sequence whose remaining bytes are zero. + // @return the checksum + int64_t Checksum(); + + // Sets the bounds to use for computing the checksum. These bounds are in + // begin and end pairs. If an odd number is given then the final range is + // assumed to extend to the end of the data. The lengths of each range must be + // a multiple of 4. + // @param ranges the range bounds to use for the checksum + void SetCheckSumRanges(const std::vector<int32_t>& ranges); + + // Read the UBYTE at the given index. + // @param index index into the font data + // @return the UBYTE; -1 if outside the bounds of the font data + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadUByte(int32_t index); + + // Read the BYTE at the given index. + // @param index index into the font data + // @return the BYTE; |kInvalidByte| if outside the bounds of the font data + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadByte(int32_t index); + + // Read the bytes at the given index into the array. + // @param index index into the font data + // @param b the destination for the bytes read + // @param offset offset in the byte array to place the bytes + // @param length the length of bytes to read + // @return the number of bytes actually read; -1 if the index is outside the + // bounds of the font data + virtual int32_t ReadBytes(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length); + + // Read the CHAR at the given index. + // @param index index into the font data + // @return the CHAR; -1 if outside the bounds of the font data + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadChar(int32_t index); + + // Read the USHORT at the given index. + // @param index index into the font data + // @return the USHORT; -1 if outside the bounds of the font data + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadUShort(int32_t index); + + // Read the SHORT at the given index. + // @param index index into the font data + // @return the SHORT; |kInvalidShort| if outside the bounds of the font data + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadShort(int32_t index); + + // Read the UINT24 at the given index. + // @param index index into the font data + // @return the UINT24; -1 if outside the bounds of the font data + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadUInt24(int32_t index); + + // Read the ULONG at the given index. + // @param index index into the font data + // @return the ULONG; kInvalidUnsigned if outside the bounds of the font data + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int64_t ReadULong(int32_t index); + + // Read the ULONG at the given index as int32_t. + // @param index index into the font data + // @return the ULONG + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadULongAsInt(int32_t index); + + // Read the ULONG at the given index, little-endian variant + // @param index index into the font data + // @return the ULONG + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int64_t ReadULongLE(int32_t index); + + // Read the LONG at the given index. + // @param index index into the font data + // @return the LONG; kInvalidLong if outside the bounds of the font data + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadLong(int32_t index); + + // Read the Fixed at the given index. + // @param index index into the font data + // @return the Fixed + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadFixed(int32_t index); + + // Read the LONGDATETIME at the given index. + // @param index index into the font data + // @return the LONGDATETIME; kInvalidLongDateTime if outside the bounds of the + // font data + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int64_t ReadDateTimeAsLong(int32_t index); + + // Read the FWORD at the given index. + // @param index index into the font data + // @return the FWORD + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadFWord(int32_t index); + + // Read the UFWORD at the given index. + // @param index index into the font data + // @return the UFWORD + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t ReadFUFWord(int32_t index); + + // Note: Not ported because they just throw UnsupportedOperationException() + // in Java. + /* + virtual int32_t ReadFUnit(int32_t index); + virtual int64_t ReadF2Dot14(int32_t index); + */ + + // Copy the FontData to an OutputStream. + // @param os the destination + // @return number of bytes copied + // @throws IOException + virtual int32_t CopyTo(OutputStream* os); + + // Copy the FontData to a WritableFontData. + // @param wfd the destination + // @return number of bytes copied + // @throws IOException + virtual int32_t CopyTo(WritableFontData* wfd); + + // Make gcc -Woverloaded-virtual happy. + virtual int32_t CopyTo(ByteArray* ba); + + // Search for the key value in the range tables provided. + // The search looks through the start-end pairs looking for the key value. It + // is assumed that the start-end pairs are both represented by UShort values, + // ranges do not overlap, and are monotonically increasing. + // @param startIndex the position to read the first start value from + // @param startOffset the offset between subsequent start values + // @param endIndex the position to read the first end value from + // @param endOffset the offset between subsequent end values + // @param length the number of start-end pairs + // @param key the value to search for + // @return the index of the start-end pairs in which the key was found; -1 + // otherwise + int32_t SearchUShort(int32_t start_index, + int32_t start_offset, + int32_t end_index, + int32_t end_offset, + int32_t length, + int32_t key); + + // Search for the key value in the table provided. + // The search looks through the values looking for the key value. It is + // assumed that the are represented by UShort values and are monotonically + // increasing. + // @param startIndex the position to read the first start value from + // @param startOffset the offset between subsequent start values + // @param length the number of start-end pairs + // @param key the value to search for + // @return the index of the start-end pairs in which the key was found; -1 + // otherwise + int32_t SearchUShort(int32_t start_index, + int32_t start_offset, + int32_t length, + int32_t key); + + // Search for the key value in the range tables provided. + // The search looks through the start-end pairs looking for the key value. It + // is assumed that the start-end pairs are both represented by ULong values + // that can be represented within 31 bits, ranges do not overlap, and are + // monotonically increasing. + // @param startIndex the position to read the first start value from + // @param startOffset the offset between subsequent start values + // @param endIndex the position to read the first end value from + // @param endOffset the offset between subsequent end values + // @param length the number of start-end pairs + // @param key the value to search for + // @return the index of the start-end pairs in which the key was found; -1 + // otherwise + int32_t SearchULong(int32_t start_index, + int32_t start_offset, + int32_t end_index, + int32_t end_offset, + int32_t length, + int32_t key); + + + // TODO(arthurhsu): IMPLEMENT + /* + virtual int32_t ReadFUnit(int32_t index); + virtual int64_t ReadF2Dot14(int32_t index); + virtual int64_t ReadLongDateTime(int32_t index); + */ + + // Makes a slice of this FontData. The returned slice will share the data with + // the original FontData. + // @param offset the start of the slice + // @param length the number of bytes in the slice + // @return a slice of the original FontData + // Note: C++ polymorphism requires return type to be consistent + virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length); + + // Makes a bottom bound only slice of this array. The returned slice will + // share the data with the original FontData. + // @param offset the start of the slice + // @return a slice of the original FontData + // Note: C++ polymorphism requires return type to be consistent + virtual CALLER_ATTACH FontData* Slice(int32_t offset); + + // Not Ported: toString() + + protected: + // Constructor. Creates a bounded wrapper of another ReadableFontData from the + // given offset until the end of the original ReadableFontData. + // @param data data to wrap + // @param offset the start of this data's view of the original data + ReadableFontData(ReadableFontData* data, int32_t offset); + + // Constructor. Creates a bounded wrapper of another ReadableFontData from the + // given offset until the end of the original ReadableFontData. + // @param data data to wrap + // @param offset the start of this data's view of the original data + // @param length the length of the other FontData to use + ReadableFontData(ReadableFontData* data, int32_t offset, int32_t length); + + private: + // Compute the checksum for the font data using any ranges set for the + // calculation. + void ComputeChecksum(); + + // Do the actual computation of the checksum for a range using the + // TrueType/OpenType checksum algorithm. The range used is from the low bound + // to the high bound in steps of four bytes. If any of the bytes within that 4 + // byte segment are not readable then it will considered a zero for + // calculation. + // Only called from within a synchronized method so it does not need to be + // synchronized itself. + // @param lowBound first position to start a 4 byte segment on + // @param highBound last possible position to start a 4 byte segment on + // @return the checksum for the total range + int64_t ComputeCheckSum(int32_t low_bound, int32_t high_bound); + + Lock checksum_lock_; + bool checksum_set_; + int64_t checksum_; + std::vector<int32_t> checksum_range_; +}; +typedef Ptr<ReadableFontData> ReadableFontDataPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/data/writable_font_data.cc b/gfx/sfntly/cpp/src/sfntly/data/writable_font_data.cc new file mode 100644 index 0000000000..40c778ea3a --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/writable_font_data.cc @@ -0,0 +1,206 @@ +/* + * 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 "sfntly/data/writable_font_data.h" + +#include <algorithm> +#include <limits> + +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/data/growable_memory_byte_array.h" + +namespace sfntly { + +WritableFontData::WritableFontData(ByteArray* ba) : ReadableFontData(ba) { +} + +WritableFontData::~WritableFontData() {} + +// static +CALLER_ATTACH +WritableFontData* WritableFontData::CreateWritableFontData(int32_t length) { + ByteArrayPtr ba; + if (length > 0) { + ba = new MemoryByteArray(length); + ba->SetFilledLength(length); + } else { + ba = new GrowableMemoryByteArray(); + } + WritableFontDataPtr wfd = new WritableFontData(ba); + return wfd.Detach(); +} + +// TODO(arthurhsu): re-investigate the memory model of this function. It's +// not too useful without copying, but it's not performance +// savvy to do copying. +CALLER_ATTACH +WritableFontData* WritableFontData::CreateWritableFontData(std::vector<uint8_t>* b) { + ByteArrayPtr ba = new GrowableMemoryByteArray(); + ba->Put(0, b); + WritableFontDataPtr wfd = new WritableFontData(ba); + return wfd.Detach(); +} + +int32_t WritableFontData::WriteByte(int32_t index, uint8_t b) { + array_->Put(BoundOffset(index), b); + return 1; +} + +int32_t WritableFontData::WriteBytes(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length) { + return array_->Put(BoundOffset(index), + b, + offset, + BoundLength(index, length)); +} + +int32_t WritableFontData::WriteBytes(int32_t index, std::vector<uint8_t>* b) { + assert(b); + return WriteBytes(index, &((*b)[0]), 0, b->size()); +} + +int32_t WritableFontData::WriteBytesPad(int32_t index, + std::vector<uint8_t>* b, + int32_t offset, + int32_t length, + uint8_t pad) { + int32_t written = + array_->Put(BoundOffset(index), + &((*b)[0]), + offset, + BoundLength(index, + std::min<int32_t>(length, b->size() - offset))); + written += WritePadding(written + index, length - written, pad); + return written; +} + +int32_t WritableFontData::WritePadding(int32_t index, int32_t count) { + return WritePadding(index, count, (uint8_t)0); +} + +int32_t WritableFontData::WritePadding(int32_t index, int32_t count, + uint8_t pad) { + for (int32_t i = 0; i < count; ++i) { + array_->Put(index + i, pad); + } + return count; +} + +int32_t WritableFontData::WriteChar(int32_t index, uint8_t c) { + return WriteByte(index, c); +} + +int32_t WritableFontData::WriteUShort(int32_t index, int32_t us) { + WriteByte(index, (uint8_t)((us >> 8) & 0xff)); + WriteByte(index + 1, (uint8_t)(us & 0xff)); + return 2; +} + +int32_t WritableFontData::WriteUShortLE(int32_t index, int32_t us) { + WriteByte(index, (uint8_t)(us & 0xff)); + WriteByte(index + 1, (uint8_t)((us >> 8) & 0xff)); + return 2; +} + +int32_t WritableFontData::WriteShort(int32_t index, int32_t s) { + return WriteUShort(index, s); +} + +int32_t WritableFontData::WriteUInt24(int32_t index, int32_t ui) { + WriteByte(index, (uint8_t)((ui >> 16) & 0xff)); + WriteByte(index + 1, (uint8_t)((ui >> 8) & 0xff)); + WriteByte(index + 2, (uint8_t)(ui & 0xff)); + return 3; +} + +int32_t WritableFontData::WriteULong(int32_t index, int64_t ul) { + WriteByte(index, (uint8_t)((ul >> 24) & 0xff)); + WriteByte(index + 1, (uint8_t)((ul >> 16) & 0xff)); + WriteByte(index + 2, (uint8_t)((ul >> 8) & 0xff)); + WriteByte(index + 3, (uint8_t)(ul & 0xff)); + return 4; +} + +int32_t WritableFontData::WriteULongLE(int32_t index, int64_t ul) { + WriteByte(index, (uint8_t)(ul & 0xff)); + WriteByte(index + 1, (uint8_t)((ul >> 8) & 0xff)); + WriteByte(index + 2, (uint8_t)((ul >> 16) & 0xff)); + WriteByte(index + 3, (uint8_t)((ul >> 24) & 0xff)); + return 4; +} + +int32_t WritableFontData::WriteLong(int32_t index, int64_t l) { + return WriteULong(index, l); +} + +int32_t WritableFontData::WriteFixed(int32_t index, int32_t f) { + return WriteLong(index, f); +} + +int32_t WritableFontData::WriteDateTime(int32_t index, int64_t date) { + WriteULong(index, (date >> 32) & 0xffffffff); + WriteULong(index + 4, date & 0xffffffff); + return 8; +} + +void WritableFontData::CopyFrom(InputStream* is, int32_t length) { + array_->CopyFrom(is, length); +} + +void WritableFontData::CopyFrom(InputStream* is) { + array_->CopyFrom(is); +} + +CALLER_ATTACH FontData* WritableFontData::Slice(int32_t offset, + int32_t length) { + if (offset < 0 || length < 0 || + offset > std::numeric_limits<int32_t>::max() - length || + offset + length > Size()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException( + "Attempt to bind data outside of its limits"); +#endif + return NULL; + } + FontDataPtr slice = new WritableFontData(this, offset, length); + return slice.Detach(); +} + +CALLER_ATTACH FontData* WritableFontData::Slice(int32_t offset) { + if (offset < 0 || offset > Size()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException( + "Attempt to bind data outside of its limits"); +#endif + return NULL; + } + FontDataPtr slice = new WritableFontData(this, offset); + return slice.Detach(); +} + +WritableFontData::WritableFontData(WritableFontData* data, int32_t offset) + : ReadableFontData(data, offset) { +} + +WritableFontData::WritableFontData(WritableFontData* data, + int32_t offset, + int32_t length) + : ReadableFontData(data, offset, length) { +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/data/writable_font_data.h b/gfx/sfntly/cpp/src/sfntly/data/writable_font_data.h new file mode 100644 index 0000000000..61fc6a9c89 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/data/writable_font_data.h @@ -0,0 +1,211 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_ +#define SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_ + +#include "sfntly/data/readable_font_data.h" + +namespace sfntly { + +// Writable font data wrapper. Supports writing of data primitives in the +// TrueType / OpenType spec. +class WritableFontData : public ReadableFontData { + public: + explicit WritableFontData(ByteArray* ba); + virtual ~WritableFontData(); + + // Constructs a writable font data object. If the length is specified as + // positive then a fixed size font data object will be created. If the length + // is zero or less then a growable font data object will be created and the + // size will be used as an estimate to help in allocating the original space. + // @param length if length > 0 create a fixed length font data; otherwise + // create a growable font data + // @return a new writable font data + static CALLER_ATTACH WritableFontData* CreateWritableFontData(int32_t length); + + // Constructs a writable font data object. The new font data object will wrap + // the bytes passed in to the factory and it will take make a copy of those + // bytes. + // @param b the byte vector to wrap + // @return a new writable font data + static CALLER_ATTACH WritableFontData* CreateWritableFontData(std::vector<uint8_t>* b); + + // Write a byte at the given index. + // @param index index into the font data + // @param b the byte to write + // @return the number of bytes written + virtual int32_t WriteByte(int32_t index, uint8_t b); + + // Write the bytes from the array. + // @param index index into the font data + // @param b the source for the bytes to be written + // @param offset offset in the byte array + // @param length the length of the bytes to be written + // @return the number of bytes actually written; -1 if the index is outside + // the FontData's range + virtual int32_t WriteBytes(int32_t index, + uint8_t* b, + int32_t offset, + int32_t length); + + // Write the bytes from the array. + // @param index index into the font data + // @param b the source for the bytes to be written + // @return the number of bytes actually written; -1 if the index is outside + // the FontData's range + virtual int32_t WriteBytes(int32_t index, std::vector<uint8_t>* b); + + // Write the bytes from the array and pad if necessary. + // Write to the length given using the byte array provided and if there are + // not enough bytes in the array then pad to the requested length using the + // pad byte specified. + // @param index index into the font data + // @param b the source for the bytes to be written + // @param offset offset in the byte array + // @param length the length of the bytes to be written + // @param pad the padding byte to be used if necessary + // @return the number of bytes actually written + virtual int32_t WriteBytesPad(int32_t index, + std::vector<uint8_t>* b, + int32_t offset, + int32_t length, + uint8_t pad); + + // Writes padding to the FontData. The padding byte written is 0x00. + // @param index index into the font data + // @param count the number of pad bytes to write + // @return the number of pad bytes written + virtual int32_t WritePadding(int32_t index, int32_t count); + + // Writes padding to the FontData. + // @param index index into the font data + // @param count the number of pad bytes to write + // @param pad the byte value to use as padding + // @return the number of pad bytes written + virtual int32_t WritePadding(int32_t index, int32_t count, uint8_t pad); + + // Write the CHAR at the given index. + // @param index index into the font data + // @param c the CHAR + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteChar(int32_t index, uint8_t c); + + // Write the USHORT at the given index. + // @param index index into the font data + // @param us the USHORT + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteUShort(int32_t index, int32_t us); + + // Write the USHORT at the given index in little endian format. + // @param index index into the font data + // @param us the USHORT + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteUShortLE(int32_t index, int32_t us); + + // Write the SHORT at the given index. + // @param index index into the font data + // @param s the SHORT + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteShort(int32_t index, int32_t s); + + // Write the UINT24 at the given index. + // @param index index into the font data + // @param ui the UINT24 + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteUInt24(int32_t index, int32_t ui); + + // Write the ULONG at the given index. + // @param index index into the font data + // @param ul the ULONG + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteULong(int32_t index, int64_t ul); + + // Write the ULONG at the given index in little endian format. + // @param index index into the font data + // @param ul the ULONG + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteULongLE(int32_t index, int64_t ul); + + // Write the LONG at the given index. + // @param index index into the font data + // @param l the LONG + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteLong(int32_t index, int64_t l); + + // Write the Fixed at the given index. + // @param index index into the font data + // @param f the Fixed + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteFixed(int32_t index, int32_t f); + + // Write the LONGDATETIME at the given index. + // @param index index into the font data + // @param date the LONGDATETIME + // @return the number of bytes actually written + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int32_t WriteDateTime(int32_t index, int64_t date); + + // Copy from the InputStream into this FontData. + // @param is the source + // @param length the number of bytes to copy + // @throws IOException + virtual void CopyFrom(InputStream* is, int32_t length); + + // Copy everything from the InputStream into this FontData. + // @param is the source + // @throws IOException + virtual void CopyFrom(InputStream* is); + + // Makes a slice of this FontData. The returned slice will share the data with + // the original FontData. + // @param offset the start of the slice + // @param length the number of bytes in the slice + // @return a slice of the original FontData + virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length); + + // Makes a bottom bound only slice of this array. The returned slice will + // share the data with the original FontData. + // @param offset the start of the slice + // @return a slice of the original FontData + virtual CALLER_ATTACH FontData* Slice(int32_t offset); + + private: + // Constructor with a lower bound. + // @param data other WritableFontData object to share data with + // @param offset offset from the other WritableFontData's data + WritableFontData(WritableFontData* data, int32_t offset); + + // Constructor with lower bound and a length bound. + // @param data other WritableFontData object to share data with + // @param offset offset from the other WritableFontData's data + // @param length length of other WritableFontData's data to use + WritableFontData(WritableFontData* data, int32_t offset, int32_t length); +}; +typedef Ptr<WritableFontData> WritableFontDataPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/font.cc b/gfx/sfntly/cpp/src/sfntly/font.cc new file mode 100644 index 0000000000..eec7becd87 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/font.cc @@ -0,0 +1,586 @@ +/* + * 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 "sfntly/font.h" + +#include <stdio.h> + +#include <algorithm> +#include <functional> +#include <iterator> +#include <limits> +#include <map> +#include <string> +#include <typeinfo> + +#include "sfntly/data/font_input_stream.h" +#include "sfntly/font_factory.h" +#include "sfntly/math/fixed1616.h" +#include "sfntly/math/font_math.h" +#include "sfntly/port/exception_type.h" +#include "sfntly/table/core/font_header_table.h" +#include "sfntly/table/core/horizontal_device_metrics_table.h" +#include "sfntly/table/core/horizontal_header_table.h" +#include "sfntly/table/core/horizontal_metrics_table.h" +#include "sfntly/table/core/maximum_profile_table.h" +#include "sfntly/table/truetype/loca_table.h" +#include "sfntly/tag.h" + +namespace sfntly { + +namespace { + +const int32_t kSFNTVersionMajor = 1; +const int32_t kSFNTVersionMinor = 0; + +const int32_t kMaxTableSize = 200 * 1024 * 1024; + +bool IsValidHeaderRegion(int32_t data_length, int32_t offset, int32_t length) { + return offset >= 0 && length >= 0 && + offset <= std::numeric_limits<int32_t>::max() - length && + offset + length <= data_length; +} + +} // namespace + +/****************************************************************************** + * Font class + ******************************************************************************/ +Font::~Font() {} + +bool Font::HasTable(int32_t tag) const { + return tables_.find(tag) != tables_.end(); +} + +Table* Font::GetTable(int32_t tag) { + if (!HasTable(tag)) + return NULL; + return tables_[tag]; +} + +const TableMap* Font::GetTableMap() { + return &tables_; +} + +void Font::Serialize(OutputStream* os, std::vector<int32_t>* table_ordering) { + assert(table_ordering); + std::vector<int32_t> final_table_ordering; + GenerateTableOrdering(table_ordering, &final_table_ordering); + TableHeaderList table_records; + BuildTableHeadersForSerialization(&final_table_ordering, &table_records); + + FontOutputStream fos(os); + SerializeHeader(&fos, &table_records); + SerializeTables(&fos, &table_records); +} + +Font::Font(int32_t sfnt_version, std::vector<uint8_t>* digest) + : sfnt_version_(sfnt_version) { + // non-trivial assignments that makes debugging hard if placed in + // initialization list + digest_ = *digest; +} + +void Font::BuildTableHeadersForSerialization(std::vector<int32_t>* table_ordering, + TableHeaderList* table_headers) { + assert(table_headers); + assert(table_ordering); + + std::vector<int32_t> final_table_ordering; + GenerateTableOrdering(table_ordering, &final_table_ordering); + int32_t table_offset = Offset::kTableRecordBegin + num_tables() * + Offset::kTableRecordSize; + for (size_t i = 0; i < final_table_ordering.size(); ++i) { + int32_t tag = final_table_ordering[i]; + TablePtr table = GetTable(tag); + if (table == NULL) + continue; + + HeaderPtr header = new Header(tag, table->CalculatedChecksum(), + table_offset, table->header()->length()); + table_headers->push_back(header); + table_offset += (table->DataLength() + 3) & ~3; + } +} + +void Font::SerializeHeader(FontOutputStream* fos, + TableHeaderList* table_headers) { + fos->WriteFixed(sfnt_version_); + fos->WriteUShort(table_headers->size()); + int32_t log2_of_max_power_of_2 = FontMath::Log2(table_headers->size()); + int32_t search_range = 2 << (log2_of_max_power_of_2 - 1 + 4); + fos->WriteUShort(search_range); + fos->WriteUShort(log2_of_max_power_of_2); + fos->WriteUShort((table_headers->size() * 16) - search_range); + + HeaderTagSortedSet sorted_headers; + std::copy(table_headers->begin(), + table_headers->end(), + std::inserter(sorted_headers, sorted_headers.end())); + + for (HeaderTagSortedSet::iterator record = sorted_headers.begin(), + record_end = sorted_headers.end(); + record != record_end; ++record) { + fos->WriteULong((*record)->tag()); + fos->WriteULong((int32_t)((*record)->checksum())); + fos->WriteULong((*record)->offset()); + fos->WriteULong((*record)->length()); + } +} + +void Font::SerializeTables(FontOutputStream* fos, + TableHeaderList* table_headers) { + assert(fos); + assert(table_headers); + for (size_t i = 0; i < table_headers->size(); ++i) { + const HeaderPtr& record = (*table_headers)[i]; + TablePtr target_table = GetTable(record->tag()); + if (target_table == NULL) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("Table out of sync with font header."); +#endif + return; + } + int32_t table_size = target_table->Serialize(fos); + assert(table_size == record->length()); + + int32_t filler_size = ((table_size + 3) & ~3) - table_size; + for (int32_t i = 0; i < filler_size; ++i) { + fos->Write(static_cast<uint8_t>(0)); + } + } +} + +void Font::GenerateTableOrdering(std::vector<int32_t>* default_table_ordering, + std::vector<int32_t>* table_ordering) { + assert(default_table_ordering); + assert(table_ordering); + table_ordering->clear(); + if (default_table_ordering->empty()) { + DefaultTableOrdering(default_table_ordering); + } + + typedef std::map<int32_t, bool> Int2Bool; + typedef std::pair<int32_t, bool> Int2BoolEntry; + Int2Bool tables_in_font; + for (TableMap::iterator table = tables_.begin(), table_end = tables_.end(); + table != table_end; ++table) { + tables_in_font.insert(Int2BoolEntry(table->first, false)); + } + for (std::vector<int32_t>::iterator tag = default_table_ordering->begin(), + tag_end = default_table_ordering->end(); + tag != tag_end; ++tag) { + if (HasTable(*tag)) { + table_ordering->push_back(*tag); + tables_in_font[*tag] = true; + } + } + for (Int2Bool::iterator table = tables_in_font.begin(), + table_end = tables_in_font.end(); + table != table_end; ++table) { + if (table->second == false) + table_ordering->push_back(table->first); + } +} + +void Font::DefaultTableOrdering(std::vector<int32_t>* default_table_ordering) { + assert(default_table_ordering); + default_table_ordering->clear(); + if (HasTable(Tag::CFF)) { + default_table_ordering->resize(CFF_TABLE_ORDERING_SIZE); + std::copy(CFF_TABLE_ORDERING, CFF_TABLE_ORDERING + CFF_TABLE_ORDERING_SIZE, + default_table_ordering->begin()); + return; + } + default_table_ordering->resize(TRUE_TYPE_TABLE_ORDERING_SIZE); + std::copy(TRUE_TYPE_TABLE_ORDERING, + TRUE_TYPE_TABLE_ORDERING + TRUE_TYPE_TABLE_ORDERING_SIZE, + default_table_ordering->begin()); +} + +/****************************************************************************** + * Font::Builder class + ******************************************************************************/ +Font::Builder::~Builder() {} + +CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(FontFactory* factory, + InputStream* is) { + FontBuilderPtr builder = new Builder(factory); + builder->LoadFont(is); + return builder.Detach(); +} + +CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder( + FontFactory* factory, + WritableFontData* wfd, + int32_t offset_to_offset_table) { + FontBuilderPtr builder = new Builder(factory); + builder->LoadFont(wfd, offset_to_offset_table); + return builder.Detach(); +} + +CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder( + FontFactory* factory) { + FontBuilderPtr builder = new Builder(factory); + return builder.Detach(); +} + +bool Font::Builder::ReadyToBuild() { + // just read in data with no manipulation + if (table_builders_.empty() && !data_blocks_.empty()) { + return true; + } + + // TODO(stuartg): font level checks - required tables etc? + for (TableBuilderMap::iterator table_builder = table_builders_.begin(), + table_builder_end = table_builders_.end(); + table_builder != table_builder_end; + ++table_builder) { + if (!table_builder->second->ReadyToBuild()) + return false; + } + return true; +} + +CALLER_ATTACH Font* Font::Builder::Build() { + FontPtr font = new Font(sfnt_version_, &digest_); + + if (!table_builders_.empty()) { + // Note: Different from Java. Directly use font->tables_ here to avoid + // STL container copying. + BuildTablesFromBuilders(font, &table_builders_, &font->tables_); + } + + table_builders_.clear(); + data_blocks_.clear(); + return font.Detach(); +} + +void Font::Builder::SetDigest(std::vector<uint8_t>* digest) { + digest_.clear(); + digest_ = *digest; +} + +void Font::Builder::ClearTableBuilders() { + table_builders_.clear(); +} + +bool Font::Builder::HasTableBuilder(int32_t tag) { + return (table_builders_.find(tag) != table_builders_.end()); +} + +Table::Builder* Font::Builder::GetTableBuilder(int32_t tag) { + if (HasTableBuilder(tag)) + return table_builders_[tag]; + return NULL; +} + +Table::Builder* Font::Builder::NewTableBuilder(int32_t tag) { + HeaderPtr header = new Header(tag); + TableBuilderPtr builder; + builder.Attach(Table::Builder::GetBuilder(header, NULL)); + table_builders_.insert(TableBuilderEntry(header->tag(), builder)); + return builder; +} + +Table::Builder* Font::Builder::NewTableBuilder(int32_t tag, + ReadableFontData* src_data) { + assert(src_data); + WritableFontDataPtr data; + data.Attach(WritableFontData::CreateWritableFontData(src_data->Length())); + // TODO(stuarg): take over original data instead? + src_data->CopyTo(data); + + HeaderPtr header = new Header(tag, data->Length()); + TableBuilderPtr builder; + builder.Attach(Table::Builder::GetBuilder(header, data)); + table_builders_.insert(TableBuilderEntry(tag, builder)); + return builder; +} + +void Font::Builder::RemoveTableBuilder(int32_t tag) { + table_builders_.erase(tag); +} + +Font::Builder::Builder(FontFactory* factory) + : factory_(factory), + sfnt_version_(Fixed1616::Fixed(kSFNTVersionMajor, kSFNTVersionMinor)) { +} + +void Font::Builder::LoadFont(InputStream* is) { + // Note: we do not throw exception here for is. This is more of an assertion. + assert(is); + FontInputStream font_is(is); + HeaderOffsetSortedSet records; + ReadHeader(&font_is, &records); + LoadTableData(&records, &font_is, &data_blocks_); + BuildAllTableBuilders(&data_blocks_, &table_builders_); + font_is.Close(); +} + +void Font::Builder::LoadFont(WritableFontData* wfd, + int32_t offset_to_offset_table) { + // Note: we do not throw exception here for is. This is more of an assertion. + assert(wfd); + HeaderOffsetSortedSet records; + ReadHeader(wfd, offset_to_offset_table, &records); + LoadTableData(&records, wfd, &data_blocks_); + BuildAllTableBuilders(&data_blocks_, &table_builders_); +} + +int32_t Font::Builder::SfntWrapperSize() { + return Offset::kSfntHeaderSize + + (Offset::kTableRecordSize * table_builders_.size()); +} + +void Font::Builder::BuildAllTableBuilders(DataBlockMap* table_data, + TableBuilderMap* builder_map) { + for (DataBlockMap::iterator record = table_data->begin(), + record_end = table_data->end(); + record != record_end; ++record) { + TableBuilderPtr builder; + builder.Attach(GetTableBuilder(record->first.p_, record->second.p_)); + builder_map->insert(TableBuilderEntry(record->first->tag(), builder)); + } + InterRelateBuilders(&table_builders_); +} + +CALLER_ATTACH +Table::Builder* Font::Builder::GetTableBuilder(Header* header, + WritableFontData* data) { + return Table::Builder::GetBuilder(header, data); +} + +void Font::Builder::BuildTablesFromBuilders(Font* font, + TableBuilderMap* builder_map, + TableMap* table_map) { + UNREFERENCED_PARAMETER(font); + InterRelateBuilders(builder_map); + + // Now build all the tables. + for (TableBuilderMap::iterator builder = builder_map->begin(), + builder_end = builder_map->end(); + builder != builder_end; ++builder) { + TablePtr table; + if (builder->second && builder->second->ReadyToBuild()) { + table.Attach(down_cast<Table*>(builder->second->Build())); + } + if (table == NULL) { + table_map->clear(); +#if !defined (SFNTLY_NO_EXCEPTION) + std::string builder_string = "Unable to build table - "; + char* table_name = TagToString(builder->first); + builder_string += table_name; + delete[] table_name; + throw RuntimeException(builder_string.c_str()); +#endif + return; + } + table_map->insert(TableMapEntry(table->header()->tag(), table)); + } +} + +static Table::Builder* GetBuilder(TableBuilderMap* builder_map, int32_t tag) { + if (!builder_map) + return NULL; + + TableBuilderMap::iterator target = builder_map->find(tag); + if (target == builder_map->end()) + return NULL; + + return target->second.p_; +} + +// Like GetBuilder(), but the returned Builder must be able to support reads. +static Table::Builder* GetReadBuilder(TableBuilderMap* builder_map, int32_t tag) { + Table::Builder* builder = GetBuilder(builder_map, tag); + if (!builder || !builder->InternalReadData()) + return NULL; + + return builder; +} + +void Font::Builder::InterRelateBuilders(TableBuilderMap* builder_map) { + Table::Builder* raw_head_builder = GetReadBuilder(builder_map, Tag::head); + FontHeaderTableBuilderPtr header_table_builder; + if (raw_head_builder != NULL) { + header_table_builder = + down_cast<FontHeaderTable::Builder*>(raw_head_builder); + } + + Table::Builder* raw_hhea_builder = GetReadBuilder(builder_map, Tag::hhea); + HorizontalHeaderTableBuilderPtr horizontal_header_builder; + if (raw_head_builder != NULL) { + horizontal_header_builder = + down_cast<HorizontalHeaderTable::Builder*>(raw_hhea_builder); + } + + Table::Builder* raw_maxp_builder = GetReadBuilder(builder_map, Tag::maxp); + MaximumProfileTableBuilderPtr max_profile_builder; + if (raw_maxp_builder != NULL) { + max_profile_builder = + down_cast<MaximumProfileTable::Builder*>(raw_maxp_builder); + } + + Table::Builder* raw_loca_builder = GetBuilder(builder_map, Tag::loca); + LocaTableBuilderPtr loca_table_builder; + if (raw_loca_builder != NULL) { + loca_table_builder = down_cast<LocaTable::Builder*>(raw_loca_builder); + } + + Table::Builder* raw_hmtx_builder = GetReadBuilder(builder_map, Tag::hmtx); + HorizontalMetricsTableBuilderPtr horizontal_metrics_builder; + if (raw_hmtx_builder != NULL) { + horizontal_metrics_builder = + down_cast<HorizontalMetricsTable::Builder*>(raw_hmtx_builder); + } + +#if defined (SFNTLY_EXPERIMENTAL) + Table::Builder* raw_hdmx_builder = GetBuilder(builder_map, Tag::hdmx); + HorizontalDeviceMetricsTableBuilderPtr hdmx_table_builder; + if (raw_hdmx_builder != NULL) { + hdmx_table_builder = + down_cast<HorizontalDeviceMetricsTable::Builder*>(raw_hdmx_builder); + } +#endif + + // set the inter table data required to build certain tables + if (horizontal_metrics_builder != NULL) { + if (max_profile_builder != NULL) { + int32_t num_glyphs = max_profile_builder->NumGlyphs(); + if (num_glyphs >= 0) + horizontal_metrics_builder->SetNumGlyphs(num_glyphs); + } + if (horizontal_header_builder != NULL) { + int32_t num_hmetrics = horizontal_header_builder->NumberOfHMetrics(); + if (num_hmetrics >= 0) + horizontal_metrics_builder->SetNumberOfHMetrics(num_hmetrics); + } + } + + if (loca_table_builder != NULL) { + if (max_profile_builder != NULL) { + int32_t num_glyphs = max_profile_builder->NumGlyphs(); + if (num_glyphs >= 0) + loca_table_builder->SetNumGlyphs(num_glyphs); + } + if (header_table_builder != NULL) { + loca_table_builder->set_format_version( + header_table_builder->IndexToLocFormat()); + } + } + +#if defined (SFNTLY_EXPERIMENTAL) + // Note: In C++, hdmx_table_builder can be NULL in a subsetter. + if (max_profile_builder != NULL && hdmx_table_builder != NULL) { + hdmx_table_builder->SetNumGlyphs(max_profile_builder->NumGlyphs()); + } +#endif +} + +void Font::Builder::ReadHeader(FontInputStream* is, + HeaderOffsetSortedSet* records) { + assert(records); + sfnt_version_ = is->ReadFixed(); + num_tables_ = is->ReadUShort(); + search_range_ = is->ReadUShort(); + entry_selector_ = is->ReadUShort(); + range_shift_ = is->ReadUShort(); + + for (int32_t table_number = 0; table_number < num_tables_; ++table_number) { + // Need to use temporary vars here. C++ evaluates function parameters from + // right to left and thus breaks the order of input stream. + int32_t tag = is->ReadULongAsInt(); + int64_t checksum = is->ReadULong(); + int32_t offset = is->ReadULongAsInt(); + int32_t length = is->ReadULongAsInt(); + if (!IsValidHeaderRegion(is->Length(), offset, length)) + continue; + + HeaderPtr table = new Header(tag, checksum, offset, length); + records->insert(table); + } +} + +void Font::Builder::ReadHeader(ReadableFontData* fd, + int32_t offset, + HeaderOffsetSortedSet* records) { + assert(records); + sfnt_version_ = fd->ReadFixed(offset + Offset::kSfntVersion); + num_tables_ = fd->ReadUShort(offset + Offset::kNumTables); + search_range_ = fd->ReadUShort(offset + Offset::kSearchRange); + entry_selector_ = fd->ReadUShort(offset + Offset::kEntrySelector); + range_shift_ = fd->ReadUShort(offset + Offset::kRangeShift); + + if (num_tables_ > fd->Size() / Offset::kTableRecordSize) + return; + + int32_t table_offset = offset + Offset::kTableRecordBegin; + for (int32_t table_number = 0; + table_number < num_tables_; + table_number++, table_offset += Offset::kTableRecordSize) { + int32_t tag = fd->ReadULongAsInt(table_offset + Offset::kTableTag); + int64_t checksum = fd->ReadULong(table_offset + Offset::kTableCheckSum); + int32_t offset = fd->ReadULongAsInt(table_offset + Offset::kTableOffset); + int32_t length = fd->ReadULongAsInt(table_offset + Offset::kTableLength); + if (!IsValidHeaderRegion(fd->Size(), offset, length)) + continue; + + HeaderPtr table = new Header(tag, checksum, offset, length); + records->insert(table); + } +} + +void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers, + FontInputStream* is, + DataBlockMap* table_data) { + assert(table_data); + for (HeaderOffsetSortedSet::iterator it = headers->begin(), + table_end = headers->end(); + it != table_end; + ++it) { + const Ptr<Header> header = *it; + is->Skip(header->offset() - is->position()); + if (header->length() > kMaxTableSize) + continue; + + FontInputStream table_is(is, header->length()); + WritableFontDataPtr data; + data.Attach(WritableFontData::CreateWritableFontData(header->length())); + data->CopyFrom(&table_is, header->length()); + table_data->insert(DataBlockEntry(header, data)); + } +} + +void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers, + WritableFontData* fd, + DataBlockMap* table_data) { + for (HeaderOffsetSortedSet::iterator it = headers->begin(), + table_end = headers->end(); + it != table_end; + ++it) { + const Ptr<Header> header = *it; + if (header->length() > kMaxTableSize) + continue; + + FontDataPtr sliced_data; + sliced_data.Attach(fd->Slice(header->offset(), header->length())); + WritableFontDataPtr data = down_cast<WritableFontData*>(sliced_data.p_); + table_data->insert(DataBlockEntry(header, data)); + } +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/font.h b/gfx/sfntly/cpp/src/sfntly/font.h new file mode 100644 index 0000000000..3187c11aaf --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/font.h @@ -0,0 +1,352 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_FONT_H_ +#define SFNTLY_CPP_SRC_SFNTLY_FONT_H_ + +#include <vector> + +#include "sfntly/port/refcount.h" +#include "sfntly/port/type.h" +#include "sfntly/port/endian.h" +#include "sfntly/data/font_input_stream.h" +#include "sfntly/data/font_output_stream.h" +#include "sfntly/data/writable_font_data.h" +#include "sfntly/table/table.h" + +namespace sfntly { + +// Note: following constants are embedded in Font class in Java. They are +// extracted out for easier reference from other classes. Offset is the +// one that is kept within class. +// Platform ids. These are used in a number of places within the font whenever +// the platform needs to be specified. +struct PlatformId { + enum { + kUnknown = -1, + kUnicode = 0, + kMacintosh = 1, + kISO = 2, + kWindows = 3, + kCustom = 4 + }; +}; + +// Unicode encoding ids. These are used in a number of places within the font +// whenever character encodings need to be specified. +struct UnicodeEncodingId { + enum { + kUnknown = -1, + kUnicode1_0 = 0, + kUnicode1_1 = 1, + kISO10646 = 2, + kUnicode2_0_BMP = 3, + kUnicode2_0 = 4, + kUnicodeVariationSequences = 5 + }; +}; + +// Windows encoding ids. These are used in a number of places within the font +// whenever character encodings need to be specified. +struct WindowsEncodingId { + enum { + kUnknown = 0xffffffff, + kSymbol = 0, + kUnicodeUCS2 = 1, + kShiftJIS = 2, + kPRC = 3, + kBig5 = 4, + kWansung = 5, + kJohab = 6, + kUnicodeUCS4 = 10 + }; +}; + +// Macintosh encoding ids. These are used in a number of places within the +// font whenever character encodings need to be specified. +struct MacintoshEncodingId { + // Macintosh Platform Encodings + enum { + kUnknown = -1, + kRoman = 0, + kJapanese = 1, + kChineseTraditional = 2, + kKorean = 3, + kArabic = 4, + kHebrew = 5, + kGreek = 6, + kRussian = 7, + kRSymbol = 8, + kDevanagari = 9, + kGurmukhi = 10, + kGujarati = 11, + kOriya = 12, + kBengali = 13, + kTamil = 14, + kTelugu = 15, + kKannada = 16, + kMalayalam = 17, + kSinhalese = 18, + kBurmese = 19, + kKhmer = 20, + kThai = 21, + kLaotian = 22, + kGeorgian = 23, + kArmenian = 24, + kChineseSimplified = 25, + kTibetan = 26, + kMongolian = 27, + kGeez = 28, + kSlavic = 29, + kVietnamese = 30, + kSindhi = 31, + kUninterpreted = 32 + }; +}; + +class FontFactory; + +// An sfnt container font object. This object is immutable and thread safe. To +// construct one use an instance of Font::Builder. +class Font : public RefCounted<Font> { + public: + // A builder for a font object. The builder allows the for the creation of + // immutable Font objects. The builder is a one use non-thread safe object and + // once the Font object has been created it is no longer usable. To create a + // further Font object new builder will be required. + class Builder : public RefCounted<Builder> { + public: + virtual ~Builder(); + + static CALLER_ATTACH Builder* + GetOTFBuilder(FontFactory* factory, InputStream* is); + static CALLER_ATTACH Builder* + GetOTFBuilder(FontFactory* factory, + WritableFontData* ba, + int32_t offset_to_offset_table); + static CALLER_ATTACH Builder* GetOTFBuilder(FontFactory* factory); + + // Get the font factory that created this font builder. + FontFactory* GetFontFactory() { return factory_; } + + // Is the font ready to build? + bool ReadyToBuild(); + + // Build the Font. After this call this builder will no longer be usable. + CALLER_ATTACH Font* Build(); + + // Set a unique fingerprint for the font object. + void SetDigest(std::vector<uint8_t>* digest); + + // Clear all table builders. + void ClearTableBuilders(); + + // Does this font builder have the specified table builder. + bool HasTableBuilder(int32_t tag); + + // Get the table builder for the given tag. If there is no builder for that + // tag then return a null. + Table::Builder* GetTableBuilder(int32_t tag); + + // Creates a new table builder for the table type given by the table id tag. + // This new table has been added to the font and will replace any existing + // builder for that table. + // @return new empty table of the type specified by tag; if tag is not known + // then a generic OpenTypeTable is returned + virtual Table::Builder* NewTableBuilder(int32_t tag); + + // Creates a new table builder for the table type given by the table id tag. + // It makes a copy of the data provided and uses that copy for the table. + // This new table has been added to the font and will replace any existing + // builder for that table. + virtual Table::Builder* NewTableBuilder(int32_t tag, + ReadableFontData* src_data); + + // Get a map of the table builders in this font builder accessed by table + // tag. + virtual TableBuilderMap* table_builders() { return &table_builders_; } + + // Remove the specified table builder from the font builder. + // Note: different from Java: we don't return object in removeTableBuilder + virtual void RemoveTableBuilder(int32_t tag); + + // Get the number of table builders in the font builder. + virtual int32_t number_of_table_builders() { + return (int32_t)table_builders_.size(); + } + + private: + explicit Builder(FontFactory* factory); + virtual void LoadFont(InputStream* is); + virtual void LoadFont(WritableFontData* wfd, + int32_t offset_to_offset_table); + int32_t SfntWrapperSize(); + void BuildAllTableBuilders(DataBlockMap* table_data, + TableBuilderMap* builder_map); + CALLER_ATTACH Table::Builder* + GetTableBuilder(Header* header, WritableFontData* data); + void BuildTablesFromBuilders(Font* font, + TableBuilderMap* builder_map, + TableMap* tables); + static void InterRelateBuilders(TableBuilderMap* builder_map); + + void ReadHeader(FontInputStream* is, + HeaderOffsetSortedSet* records); + + void ReadHeader(ReadableFontData* fd, + int32_t offset, + HeaderOffsetSortedSet* records); + + void LoadTableData(HeaderOffsetSortedSet* headers, + FontInputStream* is, + DataBlockMap* table_data); + + void LoadTableData(HeaderOffsetSortedSet* headers, + WritableFontData* fd, + DataBlockMap* table_data); + + TableBuilderMap table_builders_; + FontFactory* factory_; // dumb pointer, avoid circular refcounting + int32_t sfnt_version_; + int32_t num_tables_; + int32_t search_range_; + int32_t entry_selector_; + int32_t range_shift_; + DataBlockMap data_blocks_; + std::vector<uint8_t> digest_; + }; + + virtual ~Font(); + + // Gets the sfnt version set in the sfnt wrapper of the font. + int32_t sfnt_version() { return sfnt_version_; } + + // Gets a copy of the fonts digest that was created when the font was read. If + // no digest was set at creation time then the return result will be null. + std::vector<uint8_t>* digest() { return &digest_; } + + // Get the checksum for this font. + int64_t checksum() { return checksum_; } + + // Get the number of tables in this font. + int32_t num_tables() { return (int32_t)tables_.size(); } + + // Whether the font has a particular table. + bool HasTable(int32_t tag) const; + + // UNIMPLEMENTED: public Iterator<? extends Table> iterator + + // Get the table in this font with the specified id. + // @param tag the identifier of the table + // @return the table specified if it exists; null otherwise + // C++ port: rename table() to GetTable() + Table* GetTable(int32_t tag); + + // Get a map of the tables in this font accessed by table tag. + // @return an unmodifiable view of the tables in this font + // Note: renamed tableMap() to GetTableMap() + const TableMap* GetTableMap(); + + // UNIMPLEMENTED: toString() + + // Serialize the font to the output stream. + // @param os the destination for the font serialization + // @param tableOrdering the table ordering to apply + void Serialize(OutputStream* os, std::vector<int32_t>* table_ordering); + + private: + // Offsets to specific elements in the underlying data. These offsets are + // relative to the start of the table or the start of sub-blocks within the + // table. + struct Offset { + enum { + // Offsets within the main directory + kSfntVersion = 0, + kNumTables = 4, + kSearchRange = 6, + kEntrySelector = 8, + kRangeShift = 10, + kTableRecordBegin = 12, + kSfntHeaderSize = 12, + + // Offsets within a specific table record + kTableTag = 0, + kTableCheckSum = 4, + kTableOffset = 8, + kTableLength = 12, + kTableRecordSize = 16 + }; + }; + + // Note: the two constants are moved to tag.h to avoid VC++ bug. +// static const int32_t CFF_TABLE_ORDERING[]; +// static const int32_t TRUE_TYPE_TABLE_ORDERING[]; + + // Constructor. + // @param sfntVersion the sfnt version + // @param digest the computed digest for the font; null if digest was not + // computed + // Note: Current C++ port does not support SHA digest validation. + Font(int32_t sfnt_version, std::vector<uint8_t>* digest); + + // Build the table headers to be used for serialization. These headers will be + // filled out with the data required for serialization. The headers will be + // sorted in the order specified and only those specified will have headers + // generated. + // @param tableOrdering the tables to generate headers for and the order to + // sort them + // @return a list of table headers ready for serialization + void BuildTableHeadersForSerialization(std::vector<int32_t>* table_ordering, + TableHeaderList* table_headers); + + // Searialize the headers. + // @param fos the destination stream for the headers + // @param tableHeaders the headers to serialize + // @throws IOException + void SerializeHeader(FontOutputStream* fos, TableHeaderList* table_headers); + + // Serialize the tables. + // @param fos the destination stream for the headers + // @param tableHeaders the headers for the tables to serialize + // @throws IOException + void SerializeTables(FontOutputStream* fos, TableHeaderList* table_headers); + + // Generate the full table ordering to used for serialization. The full + // ordering uses the partial ordering as a seed and then adds all remaining + // tables in the font in an undefined order. + // @param defaultTableOrdering the partial ordering to be used as a seed for + // the full ordering + // @param (out) table_ordering the full ordering for serialization + void GenerateTableOrdering(std::vector<int32_t>* default_table_ordering, + std::vector<int32_t>* table_ordering); + + // Get the default table ordering based on the type of the font. + // @param (out) default_table_ordering the default table ordering + void DefaultTableOrdering(std::vector<int32_t>* default_table_ordering); + + int32_t sfnt_version_; + std::vector<uint8_t> digest_; + int64_t checksum_; + TableMap tables_; +}; +typedef Ptr<Font> FontPtr; +typedef std::vector<FontPtr> FontArray; +typedef Ptr<Font::Builder> FontBuilderPtr; +typedef std::vector<FontBuilderPtr> FontBuilderArray; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_FONT_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/font_factory.cc b/gfx/sfntly/cpp/src/sfntly/font_factory.cc new file mode 100644 index 0000000000..bb1986fa68 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/font_factory.cc @@ -0,0 +1,217 @@ +/* + * 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 "sfntly/font_factory.h" + +#include <string.h> + +#include "sfntly/tag.h" + +namespace sfntly { + +FontFactory::~FontFactory() { +} + +CALLER_ATTACH FontFactory* FontFactory::GetInstance() { + FontFactoryPtr instance = new FontFactory(); + return instance.Detach(); +} + +void FontFactory::FingerprintFont(bool fingerprint) { + fingerprint_ = fingerprint; +} + +bool FontFactory::FingerprintFont() { + return fingerprint_; +} + +void FontFactory::LoadFonts(InputStream* is, FontArray* output) { + assert(output); + PushbackInputStream* pbis = down_cast<PushbackInputStream*>(is); + if (IsCollection(pbis)) { + LoadCollection(pbis, output); + return; + } + FontPtr font; + font.Attach(LoadSingleOTF(pbis)); + if (font) { + output->push_back(font); + } +} + +void FontFactory::LoadFonts(std::vector<uint8_t>* b, FontArray* output) { + WritableFontDataPtr wfd; + wfd.Attach(WritableFontData::CreateWritableFontData(b)); + if (IsCollection(wfd)) { + LoadCollection(wfd, output); + return; + } + FontPtr font; + font.Attach(LoadSingleOTF(wfd)); + if (font) { + output->push_back(font); + } +} + +void FontFactory::LoadFontsForBuilding(InputStream* is, + FontBuilderArray* output) { + PushbackInputStream* pbis = down_cast<PushbackInputStream*>(is); + if (IsCollection(pbis)) { + LoadCollectionForBuilding(pbis, output); + return; + } + FontBuilderPtr builder; + builder.Attach(LoadSingleOTFForBuilding(pbis)); + if (builder) { + output->push_back(builder); + } +} + +void FontFactory::LoadFontsForBuilding(std::vector<uint8_t>* b, + FontBuilderArray* output) { + WritableFontDataPtr wfd; + wfd.Attach(WritableFontData::CreateWritableFontData(b)); + if (IsCollection(wfd)) { + LoadCollectionForBuilding(wfd, output); + return; + } + FontBuilderPtr builder; + builder.Attach(LoadSingleOTFForBuilding(wfd, 0)); + if (builder) { + output->push_back(builder); + } +} + +void FontFactory::SerializeFont(Font* font, OutputStream* os) { + std::vector<int32_t> table_ordering; + font->Serialize(os, &table_ordering); +} + +CALLER_ATTACH Font::Builder* FontFactory::NewFontBuilder() { + return Font::Builder::GetOTFBuilder(this); +} + +CALLER_ATTACH Font* FontFactory::LoadSingleOTF(InputStream* is) { + FontBuilderPtr builder; + builder.Attach(LoadSingleOTFForBuilding(is)); + return builder->Build(); +} + +CALLER_ATTACH Font* FontFactory::LoadSingleOTF(WritableFontData* wfd) { + FontBuilderPtr builder; + builder.Attach(LoadSingleOTFForBuilding(wfd, 0)); + return builder->Build(); +} + +void FontFactory::LoadCollection(InputStream* is, FontArray* output) { + FontBuilderArray ba; + LoadCollectionForBuilding(is, &ba); + output->reserve(ba.size()); + for (FontBuilderArray::iterator builder = ba.begin(), builders_end = ba.end(); + builder != builders_end; ++builder) { + FontPtr font; + font.Attach((*builder)->Build()); + output->push_back(font); + } +} + +void FontFactory::LoadCollection(WritableFontData* wfd, FontArray* output) { + FontBuilderArray builders; + LoadCollectionForBuilding(wfd, &builders); + output->reserve(builders.size()); + for (FontBuilderArray::iterator builder = builders.begin(), + builders_end = builders.end(); + builder != builders_end; ++builder) { + FontPtr font; + font.Attach((*builder)->Build()); + output->push_back(font); + } +} + +CALLER_ATTACH +Font::Builder* FontFactory::LoadSingleOTFForBuilding(InputStream* is) { + // UNIMPLEMENTED: SHA-1 hash checking via Java DigestStream + Font::Builder* builder = Font::Builder::GetOTFBuilder(this, is); + // UNIMPLEMENTED: setDigest + return builder; +} + +CALLER_ATTACH Font::Builder* + FontFactory::LoadSingleOTFForBuilding(WritableFontData* wfd, + int32_t offset_to_offset_table) { + // UNIMPLEMENTED: SHA-1 hash checking via Java DigestStream + Font::Builder* builder = + Font::Builder::GetOTFBuilder(this, wfd, offset_to_offset_table); + // UNIMPLEMENTED: setDigest + return builder; +} + +void FontFactory::LoadCollectionForBuilding(InputStream* is, + FontBuilderArray* builders) { + assert(is); + assert(builders); + WritableFontDataPtr wfd; + wfd.Attach(WritableFontData::CreateWritableFontData(is->Available())); + wfd->CopyFrom(is); + LoadCollectionForBuilding(wfd, builders); +} + +void FontFactory::LoadCollectionForBuilding(WritableFontData* wfd, + FontBuilderArray* builders) { + int32_t ttc_tag = wfd->ReadULongAsInt(Offset::kTTCTag); + UNREFERENCED_PARAMETER(ttc_tag); + int32_t version = wfd->ReadFixed(Offset::kVersion); + UNREFERENCED_PARAMETER(version); + int32_t num_fonts = wfd->ReadULongAsInt(Offset::kNumFonts); + if (num_fonts < 0) + return; + if (num_fonts > wfd->Length() / 4) + return; + + builders->reserve(num_fonts); + int32_t offset_table_offset = Offset::kOffsetTable; + for (int32_t font_number = 0; + font_number < num_fonts; + font_number++, offset_table_offset += DataSize::kULONG) { + int32_t offset = wfd->ReadULongAsInt(offset_table_offset); + if (offset < 0 || offset >= wfd->Length()) + continue; + + FontBuilderPtr builder; + builder.Attach(LoadSingleOTFForBuilding(wfd, offset)); + builders->push_back(builder); + } +} + +bool FontFactory::IsCollection(PushbackInputStream* pbis) { + std::vector<uint8_t> tag(4); + pbis->Read(&tag); + pbis->Unread(&tag); + return Tag::ttcf == GenerateTag(tag[0], tag[1], tag[2], tag[3]); +} + +bool FontFactory::IsCollection(ReadableFontData* rfd) { + std::vector<uint8_t> tag(4); + rfd->ReadBytes(0, &(tag[0]), 0, tag.size()); + return Tag::ttcf == + GenerateTag(tag[0], tag[1], tag[2], tag[3]); +} + +FontFactory::FontFactory() + : fingerprint_(false) { +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/font_factory.h b/gfx/sfntly/cpp/src/sfntly/font_factory.h new file mode 100644 index 0000000000..12e54a5ceb --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/font_factory.h @@ -0,0 +1,133 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_ +#define SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_ + +#include <vector> + +#include "sfntly/port/refcount.h" +#include "sfntly/port/type.h" +#include "sfntly/font.h" + +namespace sfntly { + +class FontFactory : public RefCounted<FontFactory> { + public: + virtual ~FontFactory(); + + // Factory method for the construction of a font factory. + static CALLER_ATTACH FontFactory* GetInstance(); + + // Toggle whether fonts that are loaded are fingerprinted with a SHA-1 hash. + // If a font is fingerprinted then a SHA-1 hash is generated at load time and + // stored in the font. This is useful for uniquely identifying fonts. By + // default this is turned on. + // @param fingerprint whether fingerprinting should be turned on or off + // TODO(arthurhsu): IMPLEMENT: C++ port currently don't do any SHA-1 + void FingerprintFont(bool fingerprint); + bool FingerprintFont(); + + // Load the font(s) from the input stream. The current settings on the factory + // are used during the loading process. One or more fonts are returned if the + // stream contains valid font data. Some font container formats may have more + // than one font and in this case multiple font objects will be returned. If + // the data in the stream cannot be parsed or is invalid an array of size zero + // will be returned. + void LoadFonts(InputStream* is, FontArray* output); + + // ByteArray font loading + // Load the font(s) from the byte array. The current settings on the factory + // are used during the loading process. One or more fonts are returned if the + // stream contains valid font data. Some font container formats may have more + // than one font and in this case multiple font objects will be returned. If + // the data in the stream cannot be parsed or is invalid an array of size zero + // will be returned. + void LoadFonts(std::vector<uint8_t>* b, FontArray* output); + + // Load the font(s) from the input stream into font builders. The current + // settings on the factory are used during the loading process. One or more + // font builders are returned if the stream contains valid font data. Some + // font container formats may have more than one font and in this case + // multiple font builder objects will be returned. If the data in the stream + // cannot be parsed or is invalid an array of size zero will be returned. + void LoadFontsForBuilding(InputStream* is, FontBuilderArray* output); + + // Load the font(s) from the byte array into font builders. The current + // settings on the factory are used during the loading process. One or more + // font builders are returned if the stream contains valid font data. Some + // font container formats may have more than one font and in this case + // multiple font builder objects will be returned. If the data in the stream + // cannot be parsed or is invalid an array of size zero will be returned. + void LoadFontsForBuilding(std::vector<uint8_t>* b, FontBuilderArray* output); + + // Font serialization + // Serialize the font to the output stream. + // NOTE: in this port we attempted not to implement I/O stream because dealing + // with cross-platform I/O stream itself is big enough as a project. + // Byte buffer it is. + void SerializeFont(Font* font, OutputStream* os); + + // Get an empty font builder for creating a new font from scratch. + CALLER_ATTACH Font::Builder* NewFontBuilder(); + + private: + // Offsets to specific elements in the underlying data. These offsets are + // relative to the start of the table or the start of sub-blocks within the + // table. + struct Offset { + enum { + // Offsets within the main directory. + kTTCTag = 0, + kVersion = 4, + kNumFonts = 8, + kOffsetTable = 12, + + // TTC Version 2.0 extensions. + // Offsets from end of OffsetTable. + kulDsigTag = 0, + kulDsigLength = 4, + kulDsigOffset = 8 + }; + }; + + FontFactory(); + + CALLER_ATTACH Font* LoadSingleOTF(InputStream* is); + CALLER_ATTACH Font* LoadSingleOTF(WritableFontData* wfd); + + void LoadCollection(InputStream* is, FontArray* output); + void LoadCollection(WritableFontData* wfd, FontArray* output); + + CALLER_ATTACH Font::Builder* LoadSingleOTFForBuilding(InputStream* is); + CALLER_ATTACH Font::Builder* + LoadSingleOTFForBuilding(WritableFontData* wfd, + int32_t offset_to_offset_table); + + void LoadCollectionForBuilding(InputStream* is, FontBuilderArray* builders); + void LoadCollectionForBuilding(WritableFontData* ba, + FontBuilderArray* builders); + + static bool IsCollection(PushbackInputStream* pbis); + static bool IsCollection(ReadableFontData* wfd); + + bool fingerprint_; +}; +typedef Ptr<FontFactory> FontFactoryPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/math/fixed1616.h b/gfx/sfntly/cpp/src/sfntly/math/fixed1616.h new file mode 100644 index 0000000000..4abbe18098 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/math/fixed1616.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_ +#define SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_ + +#include "sfntly/port/type.h" + +namespace sfntly { + +class Fixed1616 { + public: + static inline int32_t Integral(int32_t fixed) { + return (fixed >> 16); + } + + static inline int32_t Fractional(int32_t fixed) { + return (fixed & 0xffff); + } + + static inline int32_t Fixed(int32_t integral, int32_t fractional) { + return ((integral & 0xffff) << 16) | (fractional & 0xffff); + } +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/math/font_math.h b/gfx/sfntly/cpp/src/sfntly/math/font_math.h new file mode 100644 index 0000000000..f1cd2d2a6f --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/math/font_math.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_ +#define SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_ + +#include "sfntly/port/type.h" + +namespace sfntly { + +class FontMath { + public: + static int32_t Log2(int32_t a) { + int r = 0; // r will be lg(a) + while (a != 0) { + a >>= 1; + r++; + } + return r - 1; + } + + // Calculates the amount of padding needed. The values provided need to be in + // the same units. So, if the size is given as the number of bytes then the + // alignment size must also be specified as byte size to align to. + // @param size the size of the data that may need padding + // @param alignmentSize the number of units to align to + // @return the number of units needing to be added for alignment + static int32_t PaddingRequired(int32_t size, int32_t alignment_size) { + int32_t padding = alignment_size - (size % alignment_size); + return padding == alignment_size ? 0 : padding; + } +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/port/atomic.h b/gfx/sfntly/cpp/src/sfntly/port/atomic.h new file mode 100644 index 0000000000..b381a52af7 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/atomic.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_ + +#if defined (WIN32) + +#include <windows.h> + +static inline size_t AtomicIncrement(size_t* address) { +#if defined (_WIN64) + return InterlockedIncrement64(reinterpret_cast<LONGLONG*>(address)); +#else + return InterlockedIncrement(reinterpret_cast<LONG*>(address)); +#endif +} + +static inline size_t AtomicDecrement(size_t* address) { +#if defined (_WIN64) + return InterlockedDecrement64(reinterpret_cast<LONGLONG*>(address)); +#else + return InterlockedDecrement(reinterpret_cast<LONG*>(address)); +#endif +} + +#elif defined (__APPLE__) + +#include <libkern/OSAtomic.h> + +static inline size_t AtomicIncrement(size_t* address) { + return OSAtomicIncrement32Barrier(reinterpret_cast<int32_t*>(address)); +} + +static inline size_t AtomicDecrement(size_t* address) { + return OSAtomicDecrement32Barrier(reinterpret_cast<int32_t*>(address)); +} + +// Originally we check __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4, however, there are +// issues that clang not carring over this definition. Therefore we boldly +// assume it's gcc or gcc-compatible here. Compilation shall still fail since +// the intrinsics used are GCC-specific. + +#else + +#include <stddef.h> + +static inline size_t AtomicIncrement(size_t* address) { + return __sync_add_and_fetch(address, 1); +} + +static inline size_t AtomicDecrement(size_t* address) { + return __sync_sub_and_fetch(address, 1); +} + +#endif // WIN32 + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/port/config.h b/gfx/sfntly/cpp/src/sfntly/port/config.h new file mode 100644 index 0000000000..0fcdffe724 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/config.h @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_ + +#if !defined(SFNTLY_BIG_ENDIAN) && !defined(SFNTLY_LITTLE_ENDIAN) + #if defined (__ppc__) || defined (__ppc64__) + #define SFNTLY_BIG_ENDIAN + #else + #define SFNTLY_LITTLE_ENDIAN + #endif +#endif + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/port/endian.h b/gfx/sfntly/cpp/src/sfntly/port/endian.h new file mode 100644 index 0000000000..db58f0a307 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/endian.h @@ -0,0 +1,77 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_ + +#include "sfntly/port/config.h" +#include "sfntly/port/type.h" + +namespace sfntly { + +static inline uint16_t EndianSwap16(uint16_t value) { + return (uint16_t)((value >> 8) | (value << 8)); +} + +static inline int32_t EndianSwap32(int32_t value) { + return (((value & 0x000000ff) << 24) | + ((value & 0x0000ff00) << 8) | + ((value & 0x00ff0000) >> 8) | + ((value & 0xff000000) >> 24)); +} + +static inline uint64_t EndianSwap64(uint64_t value) { + return (((value & 0x00000000000000ffLL) << 56) | + ((value & 0x000000000000ff00LL) << 40) | + ((value & 0x0000000000ff0000LL) << 24) | + ((value & 0x00000000ff000000LL) << 8) | + ((value & 0x000000ff00000000LL) >> 8) | + ((value & 0x0000ff0000000000LL) >> 24) | + ((value & 0x00ff000000000000LL) >> 40) | + ((value & 0xff00000000000000LL) >> 56)); +} + +#ifdef SFNTLY_LITTLE_ENDIAN + #define ToBE16(n) EndianSwap16(n) + #define ToBE32(n) EndianSwap32(n) + #define ToBE64(n) EndianSwap64(n) + #define ToLE16(n) (n) + #define ToLE32(n) (n) + #define ToLE64(n) (n) + #define FromBE16(n) EndianSwap16(n) + #define FromBE32(n) EndianSwap32(n) + #define FromBE64(n) EndianSwap64(n) + #define FromLE16(n) (n) + #define FromLE32(n) (n) + #define FromLE64(n) (n) +#else // SFNTLY_BIG_ENDIAN + #define ToBE16(n) (n) + #define ToBE32(n) (n) + #define ToBE64(n) (n) + #define ToLE16(n) EndianSwap16(n) + #define ToLE32(n) EndianSwap32(n) + #define ToLE64(n) EndianSwap64(n) + #define FromBE16(n) (n) + #define FromBE32(n) (n) + #define FromBE64(n) (n) + #define FromLE16(n) EndianSwap16(n) + #define FromLE32(n) EndianSwap32(n) + #define FromLE64(n) EndianSwap64(n) +#endif + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/port/exception_type.h b/gfx/sfntly/cpp/src/sfntly/port/exception_type.h new file mode 100644 index 0000000000..b96efcb6c5 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/exception_type.h @@ -0,0 +1,125 @@ +/* + * 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. + */ + +// Exceptions used in sfntly + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_ + +#if !defined (SFNTLY_NO_EXCEPTION) + +#include <exception> +#include <string> +#include <sstream> + +namespace sfntly { + +class Exception : public std::exception { + public: + Exception() : what_("Unknown exception") {} + explicit Exception(const char* message) throw() { SetMessage(message); } + virtual ~Exception() throw() {} + virtual const char* what() const throw() { return what_.c_str(); } + + protected: + void SetMessage(const char* message) throw() { + try { + what_ = message; + } catch (...) {} + } + + private: + std::string what_; +}; + +class IndexOutOfBoundException : public Exception { + public: + IndexOutOfBoundException() throw() : Exception("Index out of bound") {} + explicit IndexOutOfBoundException(const char* message) throw() + : Exception(message) {} + IndexOutOfBoundException(const char* message, int32_t index) throw() { + try { + std::ostringstream msg; + msg << message; + msg << ":"; + msg << index; + SetMessage(msg.str().c_str()); + } catch (...) {} + } + virtual ~IndexOutOfBoundException() throw() {} +}; + +class IOException : public Exception { + public: + IOException() throw() : Exception("I/O exception") {} + explicit IOException(const char* message) throw() : Exception(message) {} + virtual ~IOException() throw() {} +}; + +class ArithmeticException : public Exception { + public: + ArithmeticException() throw() : Exception("Arithmetic exception") {} + explicit ArithmeticException(const char* message) throw() + : Exception(message) {} + virtual ~ArithmeticException() throw() {} +}; + +class UnsupportedOperationException : public Exception { + public: + UnsupportedOperationException() throw() : + Exception("Operation not supported") {} + explicit UnsupportedOperationException(const char* message) throw() + : Exception(message) {} + virtual ~UnsupportedOperationException() throw() {} +}; + +class RuntimeException : public Exception { + public: + RuntimeException() throw() : Exception("Runtime exception") {} + explicit RuntimeException(const char* message) throw() + : Exception(message) {} + virtual ~RuntimeException() throw() {} +}; + +class NoSuchElementException : public Exception { + public: + NoSuchElementException() throw() : Exception("No such element") {} + explicit NoSuchElementException(const char* message) throw() + : Exception(message) {} + virtual ~NoSuchElementException() throw() {} +}; + +class IllegalArgumentException : public Exception { + public: + IllegalArgumentException() throw() : Exception("Illegal argument") {} + explicit IllegalArgumentException(const char* message) throw() + : Exception(message) {} + virtual ~IllegalArgumentException() throw() {} +}; + +class IllegalStateException : public Exception { + public: + IllegalStateException() throw() : Exception("Illegal state") {} + explicit IllegalStateException(const char* message) throw() + : Exception(message) {} + virtual ~IllegalStateException() throw() {} +}; + +} // namespace sfntly + +#endif // #if !defined (SFNTLY_NO_EXCEPTION) + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/port/file_input_stream.cc b/gfx/sfntly/cpp/src/sfntly/port/file_input_stream.cc new file mode 100644 index 0000000000..87b7c8cb89 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/file_input_stream.cc @@ -0,0 +1,175 @@ +/* + * 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. + */ + +#if defined (WIN32) +#include <windows.h> +#endif + +#include <algorithm> + +#include "sfntly/port/file_input_stream.h" +#include "sfntly/port/exception_type.h" + +namespace sfntly { + +FileInputStream::FileInputStream() + : file_(NULL), + position_(0), + length_(0) { +} + +FileInputStream::~FileInputStream() { + Close(); +} + +int32_t FileInputStream::Length() { + return length_; +} + +int32_t FileInputStream::Available() { + return length_ - position_; +} + +void FileInputStream::Close() { + if (file_) { + fclose(file_); + length_ = 0; + position_ = 0; + file_ = NULL; + } +} + +void FileInputStream::Mark(int32_t readlimit) { + // NOP + UNREFERENCED_PARAMETER(readlimit); +} + +bool FileInputStream::MarkSupported() { + return false; +} + +int32_t FileInputStream::Read() { + if (!file_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no opened file"); +#endif + return 0; + } + if (feof(file_)) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("eof reached"); +#endif + return 0; + } + uint8_t value = 0; + size_t length = fread(&value, 1, 1, file_); + position_ += length; + return value; +} + +int32_t FileInputStream::Read(std::vector<uint8_t>* b) { + return Read(b, 0, b->size()); +} + +int32_t FileInputStream::Read(std::vector<uint8_t>* b, int32_t offset, int32_t length) { + assert(b); + if (!file_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no opened file"); +#endif + return 0; + } + if (feof(file_)) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("eof reached"); +#endif + return 0; + } + size_t read_count = std::min<size_t>(length_ - position_, length); + if (b->size() < (size_t)(offset + read_count)) { + b->resize((size_t)(offset + read_count)); + } + int32_t actual_read = fread(&((*b)[offset]), 1, read_count, file_); + position_ += actual_read; + return actual_read; +} + +void FileInputStream::Reset() { + // NOP +} + +int64_t FileInputStream::Skip(int64_t n) { + if (!file_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no opened file"); +#endif + return 0; + } + int64_t skip_count = 0; + if (n < 0) { // move backwards + skip_count = std::max<int64_t>(0 - (int64_t)position_, n); + position_ -= (size_t)(0 - skip_count); + fseek(file_, position_, SEEK_SET); + } else { + skip_count = std::min<size_t>(length_ - position_, (size_t)n); + position_ += (size_t)skip_count; + fseek(file_, (size_t)skip_count, SEEK_CUR); + } + return skip_count; +} + +void FileInputStream::Unread(std::vector<uint8_t>* b) { + Unread(b, 0, b->size()); +} + +void FileInputStream::Unread(std::vector<uint8_t>* b, int32_t offset, int32_t length) { + assert(b); + assert(b->size() >= size_t(offset + length)); + if (!file_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no opened file"); +#endif + return; + } + size_t unread_count = std::min<size_t>(position_, length); + fseek(file_, position_ - unread_count, SEEK_SET); + position_ -= unread_count; + Read(b, offset, length); + fseek(file_, position_ - unread_count, SEEK_SET); + position_ -= unread_count; +} + +bool FileInputStream::Open(const char* file_path) { + assert(file_path); + if (file_) { + Close(); + } +#if defined (WIN32) + fopen_s(&file_, file_path, "rb"); +#else + file_ = fopen(file_path, "rb"); +#endif + if (file_ == NULL) { + return false; + } + + fseek(file_, 0, SEEK_END); + length_ = ftell(file_); + fseek(file_, 0, SEEK_SET); + return true; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/port/file_input_stream.h b/gfx/sfntly/cpp/src/sfntly/port/file_input_stream.h new file mode 100644 index 0000000000..11284440ea --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/file_input_stream.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_ + +#include <stdio.h> + +#include "sfntly/port/input_stream.h" + +namespace sfntly { + +class FileInputStream : public PushbackInputStream { + public: + FileInputStream(); + virtual ~FileInputStream(); + + // InputStream methods + virtual int32_t Length(); + virtual int32_t Available(); + virtual void Close(); + virtual void Mark(int32_t readlimit); + virtual bool MarkSupported(); + virtual int32_t Read(); + virtual int32_t Read(std::vector<uint8_t>* b); + virtual int32_t Read(std::vector<uint8_t>* b, int32_t offset, int32_t length); + virtual void Reset(); + virtual int64_t Skip(int64_t n); + + // PushbackInputStream methods + virtual void Unread(std::vector<uint8_t>* b); + virtual void Unread(std::vector<uint8_t>* b, int32_t offset, int32_t length); + + // Own methods + virtual bool Open(const char* file_path); + + private: + FILE* file_; + size_t position_; + size_t length_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/port/input_stream.h b/gfx/sfntly/cpp/src/sfntly/port/input_stream.h new file mode 100644 index 0000000000..a403c1181f --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/input_stream.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_ + +#include "sfntly/port/type.h" + +namespace sfntly { + +// C++ equivalent to Java's OutputStream class +class InputStream { + public: + virtual int32_t Length() = 0; + virtual int32_t Available() = 0; + virtual void Close() = 0; + virtual void Mark(int32_t readlimit) = 0; + virtual bool MarkSupported() = 0; + virtual int32_t Read() = 0; + virtual int32_t Read(std::vector<uint8_t>* b) = 0; + virtual int32_t Read(std::vector<uint8_t>* b, int32_t offset, int32_t length) = 0; + virtual void Reset() = 0; + virtual int64_t Skip(int64_t n) = 0; + + protected: + virtual ~InputStream() {} +}; + +class PushbackInputStream : public InputStream { + public: + virtual void Unread(std::vector<uint8_t>* b) = 0; + virtual void Unread(std::vector<uint8_t>* b, int32_t offset, int32_t length) = 0; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/port/java_iterator.h b/gfx/sfntly/cpp/src/sfntly/port/java_iterator.h new file mode 100644 index 0000000000..0a99bca1d0 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/java_iterator.h @@ -0,0 +1,94 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_ + +#include "sfntly/port/refcount.h" + +// Interface of Java iterator. +// This is a forward read-only iterator that represents java.util.Iterator<E> + +namespace sfntly { + +template <typename ReturnType, typename ContainerBase> +class Iterator : public virtual RefCount { + public: + virtual ~Iterator() {} + virtual ContainerBase* container_base() = 0; + + protected: + Iterator() {} + NO_COPY_AND_ASSIGN(Iterator); +}; + +template <typename ReturnType, typename Container, + typename ContainerBase = Container> +class PODIterator : public Iterator<ReturnType, ContainerBase>, + public RefCounted< PODIterator<ReturnType, Container> > { + public: + explicit PODIterator(Container* container) : container_(container) {} + virtual ~PODIterator() {} + virtual ContainerBase* container_base() { + return static_cast<ContainerBase*>(container_); + } + + virtual bool HasNext() = 0; + virtual ReturnType Next() = 0; + virtual void Remove() { +#if !defined (SFNTLY_NO_EXCEPTION) + // Default to no support. + throw UnsupportedOperationException(); +#endif + } + + protected: + Container* container() { return container_; } + + private: + Container* container_; // Dumb pointer is used to avoid circular ref-counting +}; + +template <typename ReturnType, typename Container, + typename ContainerBase = Container> +class RefIterator : public Iterator<ReturnType, ContainerBase>, + public RefCounted< RefIterator<ReturnType, Container> > { + public: + explicit RefIterator(Container* container) : container_(container) {} + virtual ~RefIterator() {} + virtual ContainerBase* container_base() { + return static_cast<ContainerBase*>(container_); + } + + virtual bool HasNext() = 0; + CALLER_ATTACH virtual ReturnType* Next() = 0; + virtual void Remove() { +#if !defined (SFNTLY_NO_EXCEPTION) + // Default to no support. + throw UnsupportedOperationException(); +#endif + } + + protected: + Container* container() { return container_; } + + private: + Container* container_; // Dumb pointer is used to avoid circular ref-counting +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/port/lock.cc b/gfx/sfntly/cpp/src/sfntly/port/lock.cc new file mode 100644 index 0000000000..6c0c309a94 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/lock.cc @@ -0,0 +1,72 @@ +/* + * 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 "sfntly/port/lock.h" + +namespace sfntly { + +#if defined (WIN32) + +Lock::Lock() { + // The second parameter is the spin count, for short-held locks it avoid the + // contending thread from going to sleep which helps performance greatly. + ::InitializeCriticalSectionAndSpinCount(&os_lock_, 2000); +} + +Lock::~Lock() { + ::DeleteCriticalSection(&os_lock_); +} + +bool Lock::Try() { + if (::TryEnterCriticalSection(&os_lock_) != FALSE) { + return true; + } + return false; +} + +void Lock::Acquire() { + ::EnterCriticalSection(&os_lock_); +} + +void Lock::Unlock() { + ::LeaveCriticalSection(&os_lock_); +} + +#else // We assume it's pthread + +Lock::Lock() { + pthread_mutex_init(&os_lock_, NULL); +} + +Lock::~Lock() { + pthread_mutex_destroy(&os_lock_); +} + +bool Lock::Try() { + return (pthread_mutex_trylock(&os_lock_) == 0); +} + +void Lock::Acquire() { + pthread_mutex_lock(&os_lock_); +} + +void Lock::Unlock() { + pthread_mutex_unlock(&os_lock_); +} + +#endif + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/port/lock.h b/gfx/sfntly/cpp/src/sfntly/port/lock.h new file mode 100644 index 0000000000..b2e29bf64f --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/lock.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_ + +#if defined (WIN32) +#include <windows.h> +#else // Assume pthread. +#include <pthread.h> +#include <errno.h> +#endif + +#include "sfntly/port/type.h" + +namespace sfntly { + +#if defined (WIN32) + typedef CRITICAL_SECTION OSLockType; +#else // Assume pthread. + typedef pthread_mutex_t OSLockType; +#endif + +class Lock { + public: + Lock(); + ~Lock(); + + // If the lock is not held, take it and return true. If the lock is already + // held by something else, immediately return false. + bool Try(); + + // Take the lock, blocking until it is available if necessary. + void Acquire(); + + // Release the lock. This must only be called by the lock's holder: after + // a successful call to Try, or a call to Lock. + void Unlock(); + + private: + OSLockType os_lock_; + NO_COPY_AND_ASSIGN(Lock); +}; + +// A helper class that acquires the given Lock while the AutoLock is in scope. +class AutoLock { + public: + explicit AutoLock(Lock& lock) : lock_(lock) { + lock_.Acquire(); + } + + ~AutoLock() { + lock_.Unlock(); + } + + private: + Lock& lock_; + NO_COPY_AND_ASSIGN(AutoLock); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/port/logging.h b/gfx/sfntly/cpp/src/sfntly/port/logging.h new file mode 100644 index 0000000000..1d9e31956d --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/logging.h @@ -0,0 +1,31 @@ +/* + * Copyright 2015 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_LOGGING_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_LOGGING_H_ + +#include <stdio.h> +#include <stdlib.h> + +// Cheap base/logging.h knock off. + +#define CHECK(expr) \ + if (!(expr)) { \ + printf("CHECK failed\n"); \ + abort(); \ + } + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_LOGGING_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/port/memory_input_stream.cc b/gfx/sfntly/cpp/src/sfntly/port/memory_input_stream.cc new file mode 100755 index 0000000000..73f03f55ba --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/memory_input_stream.cc @@ -0,0 +1,153 @@ +/* + * 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. + */ + +#if defined (WIN32) +#include <windows.h> +#endif + +#include <string.h> + +#include <algorithm> + +#include "sfntly/port/memory_input_stream.h" +#include "sfntly/port/exception_type.h" + +namespace sfntly { + +MemoryInputStream::MemoryInputStream() + : buffer_(NULL), + position_(0), + length_(0) { +} + +MemoryInputStream::~MemoryInputStream() { + Close(); +} + +int32_t MemoryInputStream::Length() { + return length_; +} + +int32_t MemoryInputStream::Available() { + return length_ - position_; +} + +void MemoryInputStream::Close() { +} + +void MemoryInputStream::Mark(int32_t readlimit) { + // NOP + UNREFERENCED_PARAMETER(readlimit); +} + +bool MemoryInputStream::MarkSupported() { + return false; +} + +int32_t MemoryInputStream::Read() { + if (!buffer_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no memory attached"); +#endif + return 0; + } + if (position_ >= length_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("eof reached"); +#endif + return 0; + } + uint8_t value = buffer_[position_++]; + return value; +} + +int32_t MemoryInputStream::Read(std::vector<uint8_t>* b) { + return Read(b, 0, b->size()); +} + +int32_t MemoryInputStream::Read(std::vector<uint8_t>* b, int32_t offset, int32_t length) { + assert(b); + if (!buffer_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no memory attached"); +#endif + return 0; + } + if (position_ >= length_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("eof reached"); +#endif + return 0; + } + size_t read_count = std::min<size_t>(length_ - position_, length); + if (b->size() < (size_t)(offset + read_count)) { + b->resize((size_t)(offset + read_count)); + } + memcpy(&((*b)[offset]), buffer_ + position_, read_count); + position_ += read_count; + return read_count; +} + +void MemoryInputStream::Reset() { + // NOP +} + +int64_t MemoryInputStream::Skip(int64_t n) { + if (!buffer_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no memory attached"); +#endif + return 0; + } + int64_t skip_count = 0; + if (n < 0) { // move backwards + skip_count = std::max<int64_t>(0 - (int64_t)position_, n); + position_ -= (size_t)(0 - skip_count); + } else { + skip_count = std::min<size_t>(length_ - position_, (size_t)n); + position_ += (size_t)skip_count; + } + return skip_count; +} + +void MemoryInputStream::Unread(std::vector<uint8_t>* b) { + Unread(b, 0, b->size()); +} + +void MemoryInputStream::Unread(std::vector<uint8_t>* b, int32_t offset, int32_t length) { + assert(b); + assert(b->size() >= size_t(offset + length)); + if (!buffer_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("no memory attached"); +#endif + return; + } + size_t unread_count = std::min<size_t>(position_, length); + position_ -= unread_count; + Read(b, offset, length); + position_ -= unread_count; +} + +bool MemoryInputStream::Attach(const uint8_t* buffer, size_t length) { + assert(buffer); + assert(length); + buffer_ = buffer; + length_ = length; + return true; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/port/memory_input_stream.h b/gfx/sfntly/cpp/src/sfntly/port/memory_input_stream.h new file mode 100755 index 0000000000..247889329c --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/memory_input_stream.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_ + +#include <stdio.h> + +#include "sfntly/port/input_stream.h" + +namespace sfntly { + +class MemoryInputStream : public PushbackInputStream { + public: + MemoryInputStream(); + virtual ~MemoryInputStream(); + + // InputStream methods + virtual int32_t Length(); + virtual int32_t Available(); + virtual void Close(); + virtual void Mark(int32_t readlimit); + virtual bool MarkSupported(); + virtual int32_t Read(); + virtual int32_t Read(std::vector<uint8_t>* b); + virtual int32_t Read(std::vector<uint8_t>* b, int32_t offset, int32_t length); + virtual void Reset(); + virtual int64_t Skip(int64_t n); + + // PushbackInputStream methods + virtual void Unread(std::vector<uint8_t>* b); + virtual void Unread(std::vector<uint8_t>* b, int32_t offset, int32_t length); + + // Own methods + virtual bool Attach(const uint8_t* buffer, size_t length); + + private: + const uint8_t* buffer_; + size_t position_; + size_t length_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/port/memory_output_stream.cc b/gfx/sfntly/cpp/src/sfntly/port/memory_output_stream.cc new file mode 100644 index 0000000000..f071c97b08 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/memory_output_stream.cc @@ -0,0 +1,72 @@ +/* + * 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 "sfntly/port/memory_output_stream.h" + +namespace sfntly { + +MemoryOutputStream::MemoryOutputStream() { +} + +MemoryOutputStream::~MemoryOutputStream() { +} + +void MemoryOutputStream::Write(std::vector<uint8_t>* buffer) { + store_.insert(store_.end(), buffer->begin(), buffer->end()); +} + +void MemoryOutputStream::Write(std::vector<uint8_t>* buffer, + int32_t offset, + int32_t length) { + assert(buffer); + if (offset >= 0 && length > 0) { + store_.insert(store_.end(), + buffer->begin() + offset, + buffer->begin() + offset + length); + } else { +#if !defined(SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#endif + } +} + +void MemoryOutputStream::Write(uint8_t* buffer, int32_t offset, int32_t length) { + assert(buffer); + if (offset >= 0 && length > 0) { + store_.insert(store_.end(), buffer + offset, buffer + offset + length); + } else { +#if !defined(SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#endif + } +} + +void MemoryOutputStream::Write(uint8_t b) { + store_.push_back(b); +} + +uint8_t* MemoryOutputStream::Get() { + if (store_.empty()) { + return NULL; + } + return &(store_[0]); +} + +size_t MemoryOutputStream::Size() { + return store_.size(); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/port/memory_output_stream.h b/gfx/sfntly/cpp/src/sfntly/port/memory_output_stream.h new file mode 100644 index 0000000000..586c9d9936 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/memory_output_stream.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_ + +#include <cstddef> +#include <vector> + +#include "sfntly/port/type.h" +#include "sfntly/port/output_stream.h" + +namespace sfntly { + +// OutputStream backed by STL vector + +class MemoryOutputStream : public OutputStream { + public: + MemoryOutputStream(); + virtual ~MemoryOutputStream(); + + virtual void Close() {} // no-op + virtual void Flush() {} // no-op + virtual void Write(std::vector<uint8_t>* buffer); + virtual void Write(std::vector<uint8_t>* buffer, int32_t offset, int32_t length); + virtual void Write(uint8_t* buffer, int32_t offset, int32_t length); + virtual void Write(uint8_t b); + + uint8_t* Get(); + size_t Size(); + + private: + std::vector<uint8_t> store_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/port/output_stream.h b/gfx/sfntly/cpp/src/sfntly/port/output_stream.h new file mode 100644 index 0000000000..8dd2e5c8bc --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/output_stream.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_ + +#include "sfntly/port/type.h" + +namespace sfntly { + +// C++ equivalent to Java's OutputStream class +class OutputStream { + public: + // Make gcc -Wnon-virtual-dtor happy. + virtual ~OutputStream() {} + + virtual void Close() = 0; + virtual void Flush() = 0; + virtual void Write(std::vector<uint8_t>* buffer) = 0; + virtual void Write(uint8_t b) = 0; + + // Note: C++ port offered both versions of Write() here. The first one is + // better because it does check bounds. The second one is there for + // performance concerns. + virtual void Write(std::vector<uint8_t>* buffer, int32_t offset, int32_t length) = 0; + + // Note: Caller is responsible for the boundary of buffer. + virtual void Write(uint8_t* buffer, int32_t offset, int32_t length) = 0; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/port/refcount.h b/gfx/sfntly/cpp/src/sfntly/port/refcount.h new file mode 100644 index 0000000000..d083c73e18 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/refcount.h @@ -0,0 +1,277 @@ +/* + * 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. + */ + +// Object reference count and smart pointer implementation. + +// Smart pointer usage in sfntly: +// +// sfntly carries a smart pointer implementation like COM. Ref-countable object +// type inherits from RefCounted<>, which have AddRef and Release just like +// IUnknown (but no QueryInterface). Use a Ptr<> based smart pointer to hold +// the object so that the object ref count is handled correctly. +// +// class Foo : public RefCounted<Foo> { +// public: +// static Foo* CreateInstance() { +// Ptr<Foo> obj = new Foo(); // ref count = 1 +// return obj.Detach(); +// } +// }; +// typedef Ptr<Foo> FooPtr; // common short-hand notation +// FooPtr obj; +// obj.Attach(Foo::CreatedInstance()); // ref count = 1 +// { +// FooPtr obj2 = obj; // ref count = 2 +// } // ref count = 1, obj2 out of scope +// obj.Release(); // ref count = 0, object destroyed + +// Notes on usage: +// 1. Virtual inherit from RefCount interface in base class if smart pointers +// are going to be defined. +// 2. All RefCounted objects must be instantiated on the heap. Allocating the +// object on stack will cause crash. +// 3. Be careful when you have complex inheritance. For example, +// class A : public RefCounted<A>; +// class B : public A, public RefCounted<B>; +// In this case the smart pointer is pretty dumb and don't count on it to +// nicely destroy your objects as designed. Try refactor your code like +// class I; // the common interface and implementations +// class A : public I, public RefCounted<A>; // A specific implementation +// class B : public I, public RefCounted<B>; // B specific implementation +// 4. Smart pointers here are very bad candidates for function parameters. Use +// dumb pointers in function parameter list. +// 5. When down_cast is performed on a dangling pointer due to bugs in code, +// VC++ will generate SEH which is not handled well in VC++ debugger. One +// can use WinDBG to run it and get the faulting stack. +// 6. Idioms for heap object as return value +// Foo* createFoo() { FooPtr obj = new Foo(); return obj.Detach(); } +// Foo* passthru() { FooPtr obj = createFoo(), return obj; } +// FooPtr end_scope_pointer; +// end_scope_pointer.Attach(passThrough); +// If you are not passing that object back, you are the end of scope. + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_ + +#if !defined (NDEBUG) + #define ENABLE_OBJECT_COUNTER +// #define REF_COUNT_DEBUGGING +#endif + +#if defined (REF_COUNT_DEBUGGING) + #include <stdio.h> + #include <typeinfo> +#endif + +#include "sfntly/port/atomic.h" +#include "sfntly/port/type.h" + +// Special tag for functions that requires caller to attach instead of using +// assignment operators. +#define CALLER_ATTACH + +#if defined (REF_COUNT_DEBUGGING) + #define DEBUG_OUTPUT(a) \ + fprintf(stderr, "%s%s:oc=%d,oid=%d,rc=%d\n", a, \ + typeid(this).name(), object_counter_, object_id_, ref_count_) +#else + #define DEBUG_OUTPUT(a) +#endif + +#if defined (_MSC_VER) + // VC 2008/2010 incorrectly gives this warning for pure virtual functions + // in virtual inheritance. The only way to get around it is to disable it. + #pragma warning(disable:4250) +#endif + +bool TestSmartPointer(); + +namespace sfntly { + +template <typename T> +class Ptr; + +class RefCount { + public: + // Make gcc -Wnon-virtual-dtor happy. + virtual ~RefCount() {} + + private: + template <typename T> + friend class Ptr; + + virtual size_t AddRef() const = 0; + virtual size_t Release() const = 0; +}; + +template <typename TDerived> +class RefCounted : virtual public RefCount { + public: + RefCounted() : ref_count_(0) { +#if defined (ENABLE_OBJECT_COUNTER) + object_id_ = AtomicIncrement(&next_id_); + AtomicIncrement(&object_counter_); + DEBUG_OUTPUT("C "); +#endif + } + RefCounted(const RefCounted<TDerived>&) : ref_count_(0) {} + virtual ~RefCounted() { +#if defined (ENABLE_OBJECT_COUNTER) + AtomicDecrement(&object_counter_); + DEBUG_OUTPUT("D "); +#endif + } + + RefCounted<TDerived>& operator=(const RefCounted<TDerived>&) { + // Each object maintains own ref count, don't propagate. + return *this; + } + + private: + virtual size_t AddRef() const { + size_t new_count = AtomicIncrement(&ref_count_); + DEBUG_OUTPUT("A "); + return new_count; + } + + virtual size_t Release() const { + size_t new_ref_count = AtomicDecrement(&ref_count_); + DEBUG_OUTPUT("R "); + if (new_ref_count == 0) { + // A C-style is used to cast away const-ness and to derived. + // lint does not like this but this is how it works. + delete (TDerived*)(this); + } + return new_ref_count; + } + + mutable size_t ref_count_; // reference count of current object + friend bool ::TestSmartPointer(); +#if defined (ENABLE_OBJECT_COUNTER) + static size_t object_counter_; + static size_t next_id_; + mutable size_t object_id_; +#endif +}; + +#if defined (ENABLE_OBJECT_COUNTER) +template <typename TDerived> size_t RefCounted<TDerived>::object_counter_ = 0; +template <typename TDerived> size_t RefCounted<TDerived>::next_id_ = 0; +#endif + +// semi-smart pointer for RefCount derived objects, similar to CComPtr +template <typename T> +class Ptr { + public: + Ptr() : p_(NULL) { + } + + // This constructor shall not be explicit. + // lint does not like this but this is how it works. + Ptr(T* pT) : p_(NULL) { + *this = pT; + } + + Ptr(const Ptr<T>& p) : p_(NULL) { + *this = p; + } + + ~Ptr() { + Release(); + } + + T* operator=(T* pT) { + if (p_ == pT) { + return p_; + } + if (pT) { + RefCount* p = static_cast<RefCount*>(pT); + if (p == NULL) { + return NULL; + } + p->AddRef(); // always AddRef() before Release() + } + Release(); + p_ = pT; + return p_; + } + + T* operator=(const Ptr<T>& p) { + if (p_ == p.p_) { + return p_; + } + return operator=(p.p_); + } + + operator T*&() { + return p_; + } + + T& operator*() const { + return *p_; // It can throw! + } + + T* operator->() const { + return p_; // It can throw! + } + + bool operator!() const { + return (p_ == NULL); + } + + bool operator<(const Ptr<T>& p) const { + return (p_ < p.p_); + } + + bool operator!=(T* pT) const { + return !operator==(pT); + } + + bool operator==(T* pT) const { + return (p_ == pT); + } + + size_t Release() const { + size_t ref_count = 0; + if (p_) { + RefCount* p = static_cast<RefCount*>(p_); + if (p) { + ref_count = p->Release(); + } + p_ = NULL; + } + return ref_count; + } + + void Attach(T* pT) { + if (p_ != pT) { + Release(); + p_ = pT; + } + } + + T* Detach() { + T* pT = p_; + p_ = NULL; + return pT; + } + + mutable T* p_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/port/type.h b/gfx/sfntly/cpp/src/sfntly/port/type.h new file mode 100644 index 0000000000..cb8c1eac9c --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/port/type.h @@ -0,0 +1,81 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_ + +#include <stdint.h> + +#include <cassert> +#include <cstddef> +#include <set> +#include <vector> + +namespace sfntly { + +// deprecated +typedef uint8_t byte_t; +typedef uint16_t word_t; +typedef uint32_t dword_t; +typedef uint64_t qword_t; +typedef std::vector<uint8_t> ByteVector; +typedef std::vector<int32_t> IntegerList; +typedef std::set<int32_t> IntegerSet; + +// A macro to disallow the copy constructor and operator= functions. +// This should be used in the private: declarations for a class. +#define NO_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +} // namespace sfntly + +// Make google3 happy since it prohibits RTTI. +template<typename To, typename From> +inline To implicit_cast(From const &f) { + return f; +} + +template<typename To, typename From> // use like this: down_cast<T*>(foo); +inline To down_cast(From* f) { // so we only accept pointers + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. +#if defined (_MSC_VER) + #pragma warning(push) + #pragma warning(disable:4127) // disable "conditional expression is constant" +#endif + if (false) { + implicit_cast<From*, To>(0); + } +#if defined (_MSC_VER) + #pragma warning(pop) +#endif + +// The following code is the only place for RTTI. It is done so to allow +// additional type checking when SFNTLY_TYPE_VERIFICATION is defined. +#if defined (SFNTLY_TYPE_VERIFICATION) + assert(f == NULL || dynamic_cast<To>(f) != NULL); +#endif + return static_cast<To>(f); +} + +#if !defined(WIN32) + #define UNREFERENCED_PARAMETER(p) do { (void)p; } while (0) +#endif + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/big_glyph_metrics.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/big_glyph_metrics.cc new file mode 100644 index 0000000000..041366fc4c --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/big_glyph_metrics.cc @@ -0,0 +1,171 @@ +/* + * 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 "sfntly/table/bitmap/big_glyph_metrics.h" + +namespace sfntly { +/****************************************************************************** + * BigGlyphMetrics class + ******************************************************************************/ +BigGlyphMetrics::BigGlyphMetrics(ReadableFontData* data) + : GlyphMetrics(data) { +} + +BigGlyphMetrics::~BigGlyphMetrics() { +} + +int32_t BigGlyphMetrics::Height() { + return data_->ReadByte(Offset::kHeight); +} + +int32_t BigGlyphMetrics::Width() { + return data_->ReadByte(Offset::kWidth); +} + +int32_t BigGlyphMetrics::HoriBearingX() { + return data_->ReadByte(Offset::kHoriBearingX); +} + +int32_t BigGlyphMetrics::HoriBearingY() { + return data_->ReadByte(Offset::kHoriBearingY); +} + +int32_t BigGlyphMetrics::HoriAdvance() { + return data_->ReadByte(Offset::kHoriAdvance); +} + +int32_t BigGlyphMetrics::VertBearingX() { + return data_->ReadByte(Offset::kVertBearingX); +} + +int32_t BigGlyphMetrics::VertBearingY() { + return data_->ReadByte(Offset::kVertBearingY); +} + +int32_t BigGlyphMetrics::VertAdvance() { + return data_->ReadByte(Offset::kVertAdvance); +} + +/****************************************************************************** + * BigGlyphMetrics::Builder class + ******************************************************************************/ +BigGlyphMetrics::Builder::Builder(WritableFontData* data) + : GlyphMetrics::Builder(data) { +} + +BigGlyphMetrics::Builder::Builder(ReadableFontData* data) + : GlyphMetrics::Builder(data) { +} + +BigGlyphMetrics::Builder::~Builder() { +} + +int32_t BigGlyphMetrics::Builder::Height() { + return InternalReadData()->ReadByte(Offset::kHeight); +} + +void BigGlyphMetrics::Builder::SetHeight(uint8_t height) { + InternalWriteData()->WriteByte(Offset::kHeight, height); +} + +int32_t BigGlyphMetrics::Builder::Width() { + return InternalReadData()->ReadByte(Offset::kWidth); +} + +void BigGlyphMetrics::Builder::SetWidth(uint8_t width) { + InternalWriteData()->WriteByte(Offset::kWidth, width); +} + +int32_t BigGlyphMetrics::Builder::HoriBearingX() { + return InternalReadData()->ReadByte(Offset::kHoriBearingX); +} + +void BigGlyphMetrics::Builder::SetHoriBearingX(uint8_t bearing) { + InternalWriteData()->WriteByte(Offset::kHoriBearingX, bearing); +} + +int32_t BigGlyphMetrics::Builder::HoriBearingY() { + return InternalReadData()->ReadByte(Offset::kHoriBearingY); +} + +void BigGlyphMetrics::Builder::SetHoriBearingY(uint8_t bearing) { + InternalWriteData()->WriteByte(Offset::kHoriBearingY, bearing); +} + +int32_t BigGlyphMetrics::Builder::HoriAdvance() { + return InternalReadData()->ReadByte(Offset::kHoriAdvance); +} + +void BigGlyphMetrics::Builder::SetHoriAdvance(uint8_t advance) { + InternalWriteData()->WriteByte(Offset::kHoriAdvance, advance); +} + +int32_t BigGlyphMetrics::Builder::VertBearingX() { + return InternalReadData()->ReadByte(Offset::kVertBearingX); +} + +void BigGlyphMetrics::Builder::SetVertBearingX(uint8_t bearing) { + InternalWriteData()->WriteByte(Offset::kVertBearingX, bearing); +} + +int32_t BigGlyphMetrics::Builder::VertBearingY() { + return InternalReadData()->ReadByte(Offset::kVertBearingY); +} + +void BigGlyphMetrics::Builder::SetVertBearingY(uint8_t bearing) { + InternalWriteData()->WriteByte(Offset::kVertBearingY, bearing); +} + +int32_t BigGlyphMetrics::Builder::VertAdvance() { + return InternalReadData()->ReadByte(Offset::kVertAdvance); +} + +void BigGlyphMetrics::Builder::SetVertAdvance(uint8_t advance) { + InternalWriteData()->WriteByte(Offset::kVertAdvance, advance); +} + +CALLER_ATTACH FontDataTable* + BigGlyphMetrics::Builder::SubBuildTable(ReadableFontData* data) { + BigGlyphMetricsPtr output = new BigGlyphMetrics(data); + return output.Detach(); +} + +void BigGlyphMetrics::Builder::SubDataSet() { + // NOP. +} + +int32_t BigGlyphMetrics::Builder::SubDataSizeToSerialize() { + return 0; +} + +bool BigGlyphMetrics::Builder::SubReadyToSerialize() { + return false; +} + +int32_t BigGlyphMetrics::Builder::SubSerialize(WritableFontData* new_data) { + return Data()->CopyTo(new_data); +} + +// static +CALLER_ATTACH +BigGlyphMetrics::Builder* BigGlyphMetrics::Builder::CreateBuilder() { + WritableFontDataPtr data; + data.Attach(WritableFontData::CreateWritableFontData(Offset::kMetricsLength)); + BigGlyphMetricsBuilderPtr output = new BigGlyphMetrics::Builder(data); + return output.Detach(); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/big_glyph_metrics.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/big_glyph_metrics.h new file mode 100644 index 0000000000..84783c21ca --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/big_glyph_metrics.h @@ -0,0 +1,96 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_ + +#include "sfntly/table/bitmap/glyph_metrics.h" + +namespace sfntly { + +class BigGlyphMetrics : public GlyphMetrics, + public RefCounted<BigGlyphMetrics> { + public: + struct Offset { + enum { + kMetricsLength = 8, + + kHeight = 0, + kWidth = 1, + kHoriBearingX = 2, + kHoriBearingY = 3, + kHoriAdvance = 4, + kVertBearingX = 5, + kVertBearingY = 6, + kVertAdvance = 7, + }; + }; + + class Builder : public GlyphMetrics::Builder, + public RefCounted<Builder> { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + explicit Builder(WritableFontData* data); + explicit Builder(ReadableFontData* data); + + virtual ~Builder(); + + int32_t Height(); + void SetHeight(uint8_t height); + int32_t Width(); + void SetWidth(uint8_t width); + int32_t HoriBearingX(); + void SetHoriBearingX(uint8_t bearing); + int32_t HoriBearingY(); + void SetHoriBearingY(uint8_t bearing); + int32_t HoriAdvance(); + void SetHoriAdvance(uint8_t advance); + int32_t VertBearingX(); + void SetVertBearingX(uint8_t bearing); + int32_t VertBearingY(); + void SetVertBearingY(uint8_t bearing); + int32_t VertAdvance(); + void SetVertAdvance(uint8_t advance); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + // Static instantiation function. + static CALLER_ATTACH Builder* CreateBuilder(); + }; + + explicit BigGlyphMetrics(ReadableFontData* data); + virtual ~BigGlyphMetrics(); + + int32_t Height(); + int32_t Width(); + int32_t HoriBearingX(); + int32_t HoriBearingY(); + int32_t HoriAdvance(); + int32_t VertBearingX(); + int32_t VertBearingY(); + int32_t VertAdvance(); +}; +typedef Ptr<BigGlyphMetrics> BigGlyphMetricsPtr; +typedef Ptr<BigGlyphMetrics::Builder> BigGlyphMetricsBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_glyph.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_glyph.cc new file mode 100644 index 0000000000..334a0c07fb --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_glyph.cc @@ -0,0 +1,101 @@ +/* + * 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 "sfntly/table/bitmap/bitmap_glyph.h" +#include "sfntly/table/bitmap/simple_bitmap_glyph.h" +#include "sfntly/table/bitmap/composite_bitmap_glyph.h" + +namespace sfntly { +/****************************************************************************** + * BitmapGlyph class + ******************************************************************************/ +BitmapGlyph::~BitmapGlyph() { +} + +CALLER_ATTACH BitmapGlyph* BitmapGlyph::CreateGlyph(ReadableFontData* data, + int32_t format) { + BitmapGlyphPtr glyph; + BitmapGlyphBuilderPtr builder; + builder.Attach(Builder::CreateGlyphBuilder(data, format)); + if (builder) { + glyph.Attach(down_cast<BitmapGlyph*>(builder->Build())); + } + return glyph; +} + +BitmapGlyph::BitmapGlyph(ReadableFontData* data, int32_t format) + : SubTable(data), format_(format) { +} + +/****************************************************************************** + * BitmapGlyph::Builder class + ******************************************************************************/ +BitmapGlyph::Builder::~Builder() { +} + +CALLER_ATTACH BitmapGlyph::Builder* +BitmapGlyph::Builder::CreateGlyphBuilder(ReadableFontData* data, + int32_t format) { + BitmapGlyphBuilderPtr builder; + switch (format) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + builder = new SimpleBitmapGlyph::Builder(data, format); + break; + case 8: + case 9: + builder = new CompositeBitmapGlyph::Builder(data, format); + break; + } + return builder.Detach(); +} + +BitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format) + : SubTable::Builder(data), format_(format) { +} + +BitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format) + : SubTable::Builder(data), format_(format) { +} + +CALLER_ATTACH +FontDataTable* BitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) { + UNREFERENCED_PARAMETER(data); + return NULL; +} + +void BitmapGlyph::Builder::SubDataSet() { + // NOP +} + +int32_t BitmapGlyph::Builder::SubDataSizeToSerialize() { + return InternalReadData()->Length(); +} + +bool BitmapGlyph::Builder::SubReadyToSerialize() { + return true; +} + +int32_t BitmapGlyph::Builder::SubSerialize(WritableFontData* new_data) { + return InternalReadData()->CopyTo(new_data); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_glyph.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_glyph.h new file mode 100644 index 0000000000..2dd4c3a130 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_glyph.h @@ -0,0 +1,119 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_ + +#include <vector> +#include <map> + +#include "sfntly/table/subtable.h" + +namespace sfntly { + +class BitmapGlyph : public SubTable { + public: + struct Offset { + enum { + // header + kVersion = 0, + + kSmallGlyphMetricsLength = 5, + kBigGlyphMetricsLength = 8, + // format 1 + kGlyphFormat1_imageData = kSmallGlyphMetricsLength, + + // format 2 + kGlyphFormat2_imageData = kSmallGlyphMetricsLength, + + // format 3 + + // format 4 + + // format 5 + kGlyphFormat5_imageData = 0, + + // format 6 + kGlyphFormat6_imageData = kBigGlyphMetricsLength, + + // format 7 + kGlyphFormat7_imageData = kBigGlyphMetricsLength, + + // format 8 + kGlyphFormat8_numComponents = kSmallGlyphMetricsLength + 1, + kGlyphFormat8_componentArray = kGlyphFormat8_numComponents + + DataSize::kUSHORT, + + // format 9 + kGlyphFormat9_numComponents = kBigGlyphMetricsLength, + kGlyphFormat9_componentArray = kGlyphFormat9_numComponents + + DataSize::kUSHORT, + + // ebdtComponent + kEbdtComponentLength = DataSize::kUSHORT + 2 * DataSize::kCHAR, + kEbdtComponent_glyphCode = 0, + kEbdtComponent_xOffset = 2, + kEbdtComponent_yOffset = 3, + }; + }; + + // TODO(stuartg): builder is not functional at all + // - need to add subclasses for each type of bitmap glyph + class Builder : public SubTable::Builder { + public: + virtual ~Builder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + int32_t format() { return format_; } + + static CALLER_ATTACH Builder* CreateGlyphBuilder(ReadableFontData* data, + int32_t format); + + protected: + Builder(WritableFontData* data, int32_t format); + Builder(ReadableFontData* data, int32_t format); + + private: + int32_t format_; + }; + + virtual ~BitmapGlyph(); + + static CALLER_ATTACH BitmapGlyph* CreateGlyph(ReadableFontData* data, + int32_t format); + int32_t format() { return format_; } + + // UNIMPLEMENTED: toString() + + protected: + BitmapGlyph(ReadableFontData* data, int32_t format); + + private: + int32_t format_; +}; +typedef Ptr<BitmapGlyph> BitmapGlyphPtr; +typedef Ptr<BitmapGlyph::Builder> BitmapGlyphBuilderPtr; +typedef std::map<int32_t, BitmapGlyphBuilderPtr> BitmapGlyphBuilderMap; +typedef std::vector<BitmapGlyphBuilderMap> BitmapGlyphBuilderList; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.cc new file mode 100644 index 0000000000..a299b3e813 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.cc @@ -0,0 +1,68 @@ +/* + * 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 "sfntly/table/bitmap/bitmap_glyph_info.h" + +namespace sfntly { + +BitmapGlyphInfo::BitmapGlyphInfo(int32_t glyph_id, + int32_t block_offset, + int32_t start_offset, + int32_t length, + int32_t format) + : glyph_id_(glyph_id), + relative_(true), + block_offset_(block_offset), + start_offset_(start_offset), + length_(length), + format_(format) { +} + +BitmapGlyphInfo::BitmapGlyphInfo(int32_t glyph_id, + int32_t start_offset, + int32_t length, + int32_t format) + : glyph_id_(glyph_id), + relative_(false), + block_offset_(0), + start_offset_(start_offset), + length_(length), + format_(format) { +} + +bool BitmapGlyphInfo::operator==(const BitmapGlyphInfo& rhs) const { + return (format_ == rhs.format_ && + glyph_id_ == rhs.glyph_id_ && + length_ == rhs.length_ && + offset() == rhs.offset()); +} + +bool BitmapGlyphInfo::operator==(BitmapGlyphInfo* rhs) { + if (rhs == NULL) { + return false; // Well defined C++ code's this is always not null. + } + return (format_ == rhs->format() && + glyph_id_ == rhs->glyph_id() && + length_ == rhs->length() && + offset() == rhs->offset()); +} + +bool StartOffsetComparator::operator()(BitmapGlyphInfo* lhs, + BitmapGlyphInfo* rhs) { + return lhs->start_offset() > rhs->start_offset(); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.h new file mode 100644 index 0000000000..9921d0d526 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.h @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_ + +#include <vector> +#include <map> + +#include "sfntly/table/subtable.h" + +namespace sfntly { + +// An immutable class holding bitmap glyph information. +class BitmapGlyphInfo : public RefCounted<BitmapGlyphInfo> { + public: + // Constructor for a relative located glyph. The glyph's position in the EBDT + // table is a combination of it's block offset and it's own start offset. + // @param glyphId the glyph id + // @param blockOffset the offset of the block to which the glyph belongs + // @param startOffset the offset of the glyph within the block + // @param length the byte length + // @param format the glyph image format + BitmapGlyphInfo(int32_t glyph_id, + int32_t block_offset, + int32_t start_offset, + int32_t length, + int32_t format); + + // Constructor for an absolute located glyph. The glyph's position in the EBDT + // table is only given by it's own start offset. + // @param glyphId the glyph id + // @param startOffset the offset of the glyph within the block + // @param length the byte length + // @param format the glyph image format + BitmapGlyphInfo(int32_t glyph_id, + int32_t start_offset, + int32_t length, + int32_t format); + + int32_t glyph_id() const { return glyph_id_; } + bool relative() const { return relative_; } + int32_t block_offset() const { return block_offset_; } + int32_t offset() const { return block_offset() + start_offset(); } + int32_t start_offset() const { return start_offset_; } + int32_t length() const { return length_; } + int32_t format() const { return format_; } + + // UNIMPLEMENTED: hashCode() + bool operator==(const BitmapGlyphInfo& rhs) const; + bool operator==(BitmapGlyphInfo* rhs); + + private: + int32_t glyph_id_; + bool relative_; + int32_t block_offset_; + int32_t start_offset_; + int32_t length_; + int32_t format_; +}; +typedef Ptr<BitmapGlyphInfo> BitmapGlyphInfoPtr; +typedef std::map<int32_t, BitmapGlyphInfoPtr> BitmapGlyphInfoMap; +typedef std::vector<BitmapGlyphInfoMap> BitmapLocaList; + +class StartOffsetComparator { + public: + bool operator()(BitmapGlyphInfo* lhs, BitmapGlyphInfo* rhs); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_size_table.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_size_table.cc new file mode 100644 index 0000000000..6c7d7315a4 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_size_table.cc @@ -0,0 +1,604 @@ +/* + * 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 "sfntly/table/bitmap/bitmap_size_table.h" + +#include <stdio.h> +#include <stdlib.h> + +#include "sfntly/math/font_math.h" +#include "sfntly/table/bitmap/eblc_table.h" +#include "sfntly/table/bitmap/index_sub_table_format1.h" +#include "sfntly/table/bitmap/index_sub_table_format2.h" +#include "sfntly/table/bitmap/index_sub_table_format3.h" +#include "sfntly/table/bitmap/index_sub_table_format4.h" +#include "sfntly/table/bitmap/index_sub_table_format5.h" + +namespace sfntly { +/****************************************************************************** + * BitmapSizeTable class + ******************************************************************************/ +BitmapSizeTable::~BitmapSizeTable() { +} + +int32_t BitmapSizeTable::IndexSubTableArrayOffset() { + return data_->ReadULongAsInt( + EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset); +} + +int32_t BitmapSizeTable::IndexTableSize() { + return data_->ReadULongAsInt( + EblcTable::Offset::kBitmapSizeTable_indexTableSize); +} + +int32_t BitmapSizeTable::NumberOfIndexSubTables() { + return NumberOfIndexSubTables(data_, 0); +} + +int32_t BitmapSizeTable::ColorRef() { + return data_->ReadULongAsInt(EblcTable::Offset::kBitmapSizeTable_colorRef); +} + +int32_t BitmapSizeTable::StartGlyphIndex() { + return data_->ReadUShort(EblcTable::Offset::kBitmapSizeTable_startGlyphIndex); +} + +int32_t BitmapSizeTable::EndGlyphIndex() { + return data_->ReadUShort(EblcTable::Offset::kBitmapSizeTable_endGlyphIndex); +} + +int32_t BitmapSizeTable::PpemX() { + return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_ppemX); +} + +int32_t BitmapSizeTable::PpemY() { + return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_ppemY); +} + +int32_t BitmapSizeTable::BitDepth() { + return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_bitDepth); +} + +int32_t BitmapSizeTable::FlagsAsInt() { + return data_->ReadChar(EblcTable::Offset::kBitmapSizeTable_flags); +} + +IndexSubTable* BitmapSizeTable::GetIndexSubTable(int32_t index) { + IndexSubTableList* subtable_list = GetIndexSubTableList(); + if (index >= 0 && (size_t)index < subtable_list->size()) { + return (*subtable_list)[index]; + } + return NULL; +} + +int32_t BitmapSizeTable::GlyphOffset(int32_t glyph_id) { + IndexSubTable* subtable = SearchIndexSubTables(glyph_id); + if (subtable == NULL) { + return -1; + } + return subtable->GlyphOffset(glyph_id); +} + +int32_t BitmapSizeTable::GlyphLength(int32_t glyph_id) { + IndexSubTable* subtable = SearchIndexSubTables(glyph_id); + if (subtable == NULL) { + return -1; + } + return subtable->GlyphLength(glyph_id); +} + +CALLER_ATTACH BitmapGlyphInfo* BitmapSizeTable::GlyphInfo(int32_t glyph_id) { + IndexSubTable* sub_table = SearchIndexSubTables(glyph_id); + if (sub_table == NULL) { + return NULL; + } + return sub_table->GlyphInfo(glyph_id); +} + +int32_t BitmapSizeTable::GlyphFormat(int32_t glyph_id) { + IndexSubTable* subtable = SearchIndexSubTables(glyph_id); + if (subtable == NULL) { + return -1; + } + return subtable->image_format(); +} + +BitmapSizeTable::BitmapSizeTable(ReadableFontData* data, + ReadableFontData* master_data) + : SubTable(data, master_data) { +} + +// static +int32_t BitmapSizeTable::NumberOfIndexSubTables(ReadableFontData* data, + int32_t table_offset) { + return data->ReadULongAsInt(table_offset + + EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables); +} + +IndexSubTable* BitmapSizeTable::SearchIndexSubTables(int32_t glyph_id) { + // would be faster to binary search but too many size tables don't have + // sorted subtables +#if (SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH) + return BinarySearchIndexSubTables(glyph_id); +#else + return LinearSearchIndexSubTables(glyph_id); +#endif +} + +IndexSubTable* BitmapSizeTable::LinearSearchIndexSubTables(int32_t glyph_id) { + IndexSubTableList* subtable_list = GetIndexSubTableList(); + for (IndexSubTableList::iterator b = subtable_list->begin(), + e = subtable_list->end(); b != e; b++) { + if ((*b)->first_glyph_index() <= glyph_id && + (*b)->last_glyph_index() >= glyph_id) { + return *b; + } + } + return NULL; +} + +IndexSubTable* BitmapSizeTable::BinarySearchIndexSubTables(int32_t glyph_id) { + IndexSubTableList* subtable_list = GetIndexSubTableList(); + int32_t index = 0; + int32_t bottom = 0; + int32_t top = subtable_list->size(); + while (top != bottom) { + index = (top + bottom) / 2; + IndexSubTable* subtable = (*subtable_list)[index]; + if (glyph_id < subtable->first_glyph_index()) { + // Location beow current location + top = index; + } else { + if (glyph_id <= subtable->last_glyph_index()) { + return subtable; + } else { + bottom = index + 1; + } + } + } + return NULL; +} + +CALLER_ATTACH +IndexSubTable* BitmapSizeTable::CreateIndexSubTable(int32_t index) { + return IndexSubTable::CreateIndexSubTable(master_read_data(), + IndexSubTableArrayOffset(), + index); +} + +IndexSubTableList* BitmapSizeTable::GetIndexSubTableList() { + AutoLock lock(index_subtables_lock_); + if (index_subtables_.empty()) { + for (int32_t i = 0; i < NumberOfIndexSubTables(); ++i) { + IndexSubTablePtr table; + table.Attach(CreateIndexSubTable(i)); + index_subtables_.push_back(table); + } + } + return &index_subtables_; +} + +/****************************************************************************** + * BitmapSizeTable::Builder class + ******************************************************************************/ +BitmapSizeTable::Builder::~Builder() { +} + +CALLER_ATTACH +FontDataTable* BitmapSizeTable::Builder::SubBuildTable(ReadableFontData* data) { + BitmapSizeTablePtr output = new BitmapSizeTable(data, master_read_data()); + return output.Detach(); +} + +void BitmapSizeTable::Builder::SubDataSet() { + Revert(); +} + +int32_t BitmapSizeTable::Builder::SubDataSizeToSerialize() { + IndexSubTableBuilderList* builders = IndexSubTableBuilders(); + if (builders->empty()) { + return 0; + } + int32_t size = EblcTable::Offset::kBitmapSizeTableLength; + bool variable = false; + for (IndexSubTableBuilderList::iterator b = builders->begin(), + e = builders->end(); b != e; b++) { + size += EblcTable::Offset::kIndexSubTableEntryLength; + int32_t sub_table_size = (*b)->SubDataSizeToSerialize(); + int32_t padding = FontMath::PaddingRequired(abs(sub_table_size), + DataSize::kULONG); +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "subtable size=%d\n", sub_table_size); +#endif + variable = (sub_table_size > 0) ? variable : true; + size += abs(sub_table_size) + padding; + } +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "bitmap table size=%d\n", variable ? -size : size); +#endif + return variable ? -size : size; +} + +bool BitmapSizeTable::Builder::SubReadyToSerialize() { + if (IndexSubTableBuilders()->empty()) { + return false; + } + return true; +} + +int32_t BitmapSizeTable::Builder::SubSerialize(WritableFontData* new_data) { + SetNumberOfIndexSubTables(IndexSubTableBuilders()->size()); + int32_t size = InternalReadData()->CopyTo(new_data); + return size; +} + +CALLER_ATTACH BitmapSizeTable::Builder* +BitmapSizeTable::Builder::CreateBuilder(WritableFontData* data, + ReadableFontData* master_data) { + BitmapSizeTableBuilderPtr output = + new BitmapSizeTable::Builder(data, master_data); + return output.Detach(); +} + +CALLER_ATTACH BitmapSizeTable::Builder* +BitmapSizeTable::Builder::CreateBuilder(ReadableFontData* data, + ReadableFontData* master_data) { + BitmapSizeTableBuilderPtr output = + new BitmapSizeTable::Builder(data, master_data); + return output.Detach(); +} + +int32_t BitmapSizeTable::Builder::IndexSubTableArrayOffset() { + return InternalReadData()->ReadULongAsInt( + EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset); +} + +void BitmapSizeTable::Builder::SetIndexSubTableArrayOffset(int32_t offset) { + InternalWriteData()->WriteULong( + EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset, offset); +} + +int32_t BitmapSizeTable::Builder::IndexTableSize() { + return InternalReadData()->ReadULongAsInt( + EblcTable::Offset::kBitmapSizeTable_indexTableSize); +} + +void BitmapSizeTable::Builder::SetIndexTableSize(int32_t size) { + InternalWriteData()->WriteULong( + EblcTable::Offset::kBitmapSizeTable_indexTableSize, size); +} + +int32_t BitmapSizeTable::Builder::NumberOfIndexSubTables() { + return GetIndexSubTableBuilders()->size(); +} + +int32_t BitmapSizeTable::Builder::ColorRef() { + return InternalReadData()->ReadULongAsInt( + EblcTable::Offset::kBitmapSizeTable_colorRef); +} + +int32_t BitmapSizeTable::Builder::StartGlyphIndex() { + return InternalReadData()->ReadUShort( + EblcTable::Offset::kBitmapSizeTable_startGlyphIndex); +} + +int32_t BitmapSizeTable::Builder::EndGlyphIndex() { + return InternalReadData()->ReadUShort( + EblcTable::Offset::kBitmapSizeTable_endGlyphIndex); +} + +int32_t BitmapSizeTable::Builder::PpemX() { + return InternalReadData()->ReadByte( + EblcTable::Offset::kBitmapSizeTable_ppemX); +} + +int32_t BitmapSizeTable::Builder::PpemY() { + return InternalReadData()->ReadByte( + EblcTable::Offset::kBitmapSizeTable_ppemY); +} + +int32_t BitmapSizeTable::Builder::BitDepth() { + return InternalReadData()->ReadByte( + EblcTable::Offset::kBitmapSizeTable_bitDepth); +} + +int32_t BitmapSizeTable::Builder::FlagsAsInt() { + return InternalReadData()->ReadChar( + EblcTable::Offset::kBitmapSizeTable_flags); +} + +IndexSubTable::Builder* BitmapSizeTable::Builder::IndexSubTableBuilder( + int32_t index) { + IndexSubTableBuilderList* sub_table_list = GetIndexSubTableBuilders(); + return sub_table_list->at(index); +} + +CALLER_ATTACH BitmapGlyphInfo* BitmapSizeTable::Builder::GlyphInfo( + int32_t glyph_id) { + IndexSubTable::Builder* sub_table = SearchIndexSubTables(glyph_id); + if (sub_table == NULL) { + return NULL; + } + return sub_table->GlyphInfo(glyph_id); +} + +int32_t BitmapSizeTable::Builder::GlyphOffset(int32_t glyph_id) { + IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id); + if (subtable == NULL) { + return -1; + } + return subtable->GlyphOffset(glyph_id); +} + +int32_t BitmapSizeTable::Builder::GlyphLength(int32_t glyph_id) { + IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id); + if (subtable == NULL) { + return -1; + } + return subtable->GlyphLength(glyph_id); +} + +int32_t BitmapSizeTable::Builder::GlyphFormat(int32_t glyph_id) { + IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id); + if (subtable == NULL) { + return -1; + } + return subtable->image_format(); +} + +IndexSubTableBuilderList* BitmapSizeTable::Builder::IndexSubTableBuilders() { + return GetIndexSubTableBuilders(); +} + +CALLER_ATTACH BitmapSizeTable::Builder::BitmapGlyphInfoIterator* +BitmapSizeTable::Builder::GetIterator() { + Ptr<BitmapSizeTable::Builder::BitmapGlyphInfoIterator> output = + new BitmapSizeTable::Builder::BitmapGlyphInfoIterator(this); + return output.Detach(); +} + +void BitmapSizeTable::Builder::GenerateLocaMap(BitmapGlyphInfoMap* output) { + assert(output); + Ptr<BitmapSizeTable::Builder::BitmapGlyphInfoIterator> it; + it.Attach(GetIterator()); + while (it->HasNext()) { + BitmapGlyphInfoPtr info; + info.Attach(it->Next()); + (*output)[info->glyph_id()] = info; + } +} + +void BitmapSizeTable::Builder::Revert() { + index_sub_tables_.clear(); + set_model_changed(false); +} + +BitmapSizeTable::Builder::Builder(WritableFontData* data, + ReadableFontData* master_data) + : SubTable::Builder(data, master_data) { +} + +BitmapSizeTable::Builder::Builder(ReadableFontData* data, + ReadableFontData* master_data) + : SubTable::Builder(data, master_data) { +} + +void BitmapSizeTable::Builder::SetNumberOfIndexSubTables(int32_t count) { + InternalWriteData()->WriteULong( + EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables, count); +} + +IndexSubTable::Builder* BitmapSizeTable::Builder::SearchIndexSubTables( + int32_t glyph_id) { + // would be faster to binary search but too many size tables don't have + // sorted subtables +#if (SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH) + return BinarySearchIndexSubTables(glyph_id); +#else + return LinearSearchIndexSubTables(glyph_id); +#endif +} + +IndexSubTable::Builder* BitmapSizeTable::Builder::LinearSearchIndexSubTables( + int32_t glyph_id) { + IndexSubTableBuilderList* subtable_list = GetIndexSubTableBuilders(); + for (IndexSubTableBuilderList::iterator b = subtable_list->begin(), + e = subtable_list->end(); + b != e; b++) { + if ((*b)->first_glyph_index() <= glyph_id && + (*b)->last_glyph_index() >= glyph_id) { + return *b; + } + } + return NULL; +} + +IndexSubTable::Builder* BitmapSizeTable::Builder::BinarySearchIndexSubTables( + int32_t glyph_id) { + IndexSubTableBuilderList* subtable_list = GetIndexSubTableBuilders(); + int32_t index = 0; + int32_t bottom = 0; + int32_t top = subtable_list->size(); + while (top != bottom) { + index = (top + bottom) / 2; + IndexSubTable::Builder* subtable = subtable_list->at(index); + if (glyph_id < subtable->first_glyph_index()) { + // Location beow current location + top = index; + } else { + if (glyph_id <= subtable->last_glyph_index()) { + return subtable; + } else { + bottom = index + 1; + } + } + } + return NULL; +} + +IndexSubTableBuilderList* BitmapSizeTable::Builder::GetIndexSubTableBuilders() { + if (index_sub_tables_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &index_sub_tables_; +} + +void BitmapSizeTable::Builder::Initialize(ReadableFontData* data) { + index_sub_tables_.clear(); + if (data) { + int32_t number_of_index_subtables = + BitmapSizeTable::NumberOfIndexSubTables(data, 0); + index_sub_tables_.resize(number_of_index_subtables); + for (int32_t i = 0; i < number_of_index_subtables; ++i) { + index_sub_tables_[i].Attach(CreateIndexSubTableBuilder(i)); + } + } +} + +CALLER_ATTACH IndexSubTable::Builder* +BitmapSizeTable::Builder::CreateIndexSubTableBuilder(int32_t index) { + return IndexSubTable::Builder::CreateBuilder(master_read_data(), + IndexSubTableArrayOffset(), + index); +} + +/****************************************************************************** + * BitmapSizeTable::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +BitmapSizeTable::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + BitmapSizeTable::Builder* container) + : RefIterator<BitmapGlyphInfo, BitmapSizeTable::Builder>(container) { + sub_table_iter_ = container->IndexSubTableBuilders()->begin(); + sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator()); +} + +bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext() { + if (sub_table_glyph_info_iter_ && HasNext(sub_table_glyph_info_iter_)) { + return true; + } + while (++sub_table_iter_ != container()->IndexSubTableBuilders()->end()) { + sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator()); + if (HasNext(sub_table_glyph_info_iter_)) { + return true; + } + } + return false; +} + +CALLER_ATTACH +BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next() { + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + return Next(sub_table_glyph_info_iter_); +} + +bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext( + BitmapGlyphInfoIter* iterator_base) { + if (iterator_base) { + switch (iterator_base->container_base()->index_format()) { + case 1: { + IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->HasNext(); + } + + case 2: { + IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->HasNext(); + } + + case 3: { + IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->HasNext(); + } + + case 4: { + IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->HasNext(); + } + + case 5: { + IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->HasNext(); + } + + default: + break; + } + } + return false; +} + +CALLER_ATTACH +BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next( + BitmapGlyphInfoIter* iterator_base) { + if (iterator_base) { + switch (iterator_base->container_base()->index_format()) { + case 1: { + IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->Next(); + } + + case 2: { + IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->Next(); + } + + case 3: { + IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->Next(); + } + + case 4: { + IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->Next(); + } + + case 5: { + IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->Next(); + } + + default: + break; + } + } + return NULL; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_size_table.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_size_table.h new file mode 100644 index 0000000000..6733e20304 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/bitmap_size_table.h @@ -0,0 +1,173 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_ + +#include "sfntly/port/lock.h" +#include "sfntly/table/bitmap/bitmap_glyph_info.h" +#include "sfntly/table/bitmap/index_sub_table.h" + +namespace sfntly { +// Binary search would be faster but many fonts have index subtables that +// aren't sorted. +// Note: preprocessor define is used to avoid const expression warnings in C++ +// code. +#define SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH 0 + +class BitmapSizeTable : public SubTable, + public RefCounted<BitmapSizeTable> { + public: + class Builder : public SubTable::Builder, + public RefCounted<Builder> { + public: + class BitmapGlyphInfoIterator : + public RefIterator<BitmapGlyphInfo, Builder> { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + bool HasNext(BitmapGlyphInfoIter* iterator_base); + CALLER_ATTACH BitmapGlyphInfo* Next(BitmapGlyphInfoIter* iterator_base); + + IndexSubTableBuilderList::iterator sub_table_iter_; + BitmapGlyphInfoIterPtr sub_table_glyph_info_iter_; + }; + + virtual ~Builder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + ReadableFontData* master_data); + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + ReadableFontData* master_data); + // Gets the subtable array offset as set in the original table as read from + // the font file. This value cannot be explicitly set and will be generated + // during table building. + // @return the subtable array offset + int32_t IndexSubTableArrayOffset(); + + // Sets the subtable array offset. This is used only during the building + // process when the objects are being serialized. + // @param offset the offset to the index subtable array + void SetIndexSubTableArrayOffset(int32_t offset); + + // Gets the subtable array size as set in the original table as read from + // the font file. This value cannot be explicitly set and will be generated + // during table building. + // @return the subtable array size + int32_t IndexTableSize(); + + // Sets the subtable size. This is used only during the building process + // when the objects are being serialized. + // @param size the offset to the index subtable array + void SetIndexTableSize(int32_t size); + + int32_t NumberOfIndexSubTables(); + int32_t ColorRef(); + // TODO(stuartg): SBitLineMetrics hori(); + // TODO(stuartg): SBitLineMetrics vert(); + int32_t StartGlyphIndex(); + int32_t EndGlyphIndex(); + int32_t PpemX(); + int32_t PpemY(); + int32_t BitDepth(); + int32_t FlagsAsInt(); + + IndexSubTable::Builder* IndexSubTableBuilder(int32_t index); + CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id); + int32_t GlyphOffset(int32_t glyph_id); + int32_t GlyphLength(int32_t glyph_id); + int32_t GlyphFormat(int32_t glyph_id); + IndexSubTableBuilderList* IndexSubTableBuilders(); + // Note: renamed from iterator(), type is the derived type. + CALLER_ATTACH BitmapGlyphInfoIterator* GetIterator(); + void GenerateLocaMap(BitmapGlyphInfoMap* output); + + protected: + void Revert(); + + private: + Builder(WritableFontData* data, ReadableFontData* master_data); + Builder(ReadableFontData* data, ReadableFontData* master_data); + + void SetNumberOfIndexSubTables(int32_t count); + IndexSubTable::Builder* SearchIndexSubTables(int32_t glyph_id); + IndexSubTable::Builder* LinearSearchIndexSubTables(int32_t glyph_id); + IndexSubTable::Builder* BinarySearchIndexSubTables(int32_t glyph_id); + IndexSubTableBuilderList* GetIndexSubTableBuilders(); + void Initialize(ReadableFontData* data); + CALLER_ATTACH IndexSubTable::Builder* CreateIndexSubTableBuilder( + int32_t index); + + IndexSubTableBuilderList index_sub_tables_; + }; + + virtual ~BitmapSizeTable(); + + int32_t IndexSubTableArrayOffset(); + int32_t IndexTableSize(); + int32_t NumberOfIndexSubTables(); + int32_t ColorRef(); + // TODO(stuartg): SBitLineMetrics hori(); + // TODO(stuartg): SBitLineMetrics vert(); + int32_t StartGlyphIndex(); + int32_t EndGlyphIndex(); + int32_t PpemX(); + int32_t PpemY(); + int32_t BitDepth(); + int32_t FlagsAsInt(); + + // Note: renamed from indexSubTable() + IndexSubTable* GetIndexSubTable(int32_t index); + int32_t GlyphOffset(int32_t glyph_id); + int32_t GlyphLength(int32_t glyph_id); + CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id); + int32_t GlyphFormat(int32_t glyph_id); + + protected: + BitmapSizeTable(ReadableFontData* data, + ReadableFontData* master_data); + + private: + static int32_t NumberOfIndexSubTables(ReadableFontData* data, + int32_t table_offset); + IndexSubTable* SearchIndexSubTables(int32_t glyph_id); + IndexSubTable* LinearSearchIndexSubTables(int32_t glyph_id); + IndexSubTable* BinarySearchIndexSubTables(int32_t glyph_id); + CALLER_ATTACH IndexSubTable* CreateIndexSubTable(int32_t index); + IndexSubTableList* GetIndexSubTableList(); + + Lock index_subtables_lock_; + IndexSubTableList index_subtables_; +}; +typedef Ptr<BitmapSizeTable> BitmapSizeTablePtr; +typedef std::vector<BitmapSizeTablePtr> BitmapSizeTableList; +typedef Ptr<BitmapSizeTable::Builder> BitmapSizeTableBuilderPtr; +typedef std::vector<BitmapSizeTableBuilderPtr> BitmapSizeTableBuilderList; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.cc new file mode 100644 index 0000000000..ae7dc5a731 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.cc @@ -0,0 +1,109 @@ +/* + * 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 "sfntly/table/bitmap/composite_bitmap_glyph.h" + +namespace sfntly { +/****************************************************************************** + * CompositeBitmapGlyph class + ******************************************************************************/ +CompositeBitmapGlyph::CompositeBitmapGlyph(ReadableFontData* data, + int32_t format) + : BitmapGlyph(data, format) { + Initialize(format); +} + +CompositeBitmapGlyph::~CompositeBitmapGlyph() { +} + +int32_t CompositeBitmapGlyph::NumComponents() { + return data_->ReadUShort(num_components_offset_); +} + +CompositeBitmapGlyph::Component CompositeBitmapGlyph::GetComponent( + int32_t component_num) const { + int32_t component_offset = component_array_offset_ + + component_num * Offset::kEbdtComponentLength; + return CompositeBitmapGlyph::Component( + data_->ReadUShort(component_offset + Offset::kEbdtComponent_glyphCode), + data_->ReadChar(component_offset + Offset::kEbdtComponent_xOffset), + data_->ReadChar(component_offset + Offset::kEbdtComponent_yOffset)); +} + +void CompositeBitmapGlyph::Initialize(int32_t format) { + if (format == 8) { + num_components_offset_ = Offset::kGlyphFormat8_numComponents; + component_array_offset_ = Offset::kGlyphFormat8_componentArray; + } else if (format == 9) { + num_components_offset_ = Offset::kGlyphFormat9_numComponents; + component_array_offset_ = Offset::kGlyphFormat9_componentArray; + } else { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalStateException("Attempt to create a Composite Bitmap Glyph " + "with a non-composite format."); +#endif + } +} + +/****************************************************************************** + * CompositeBitmapGlyph::Component class + ******************************************************************************/ +CompositeBitmapGlyph::Component::Component(const Component& rhs) + : glyph_code_(rhs.glyph_code_), + x_offset_(rhs.x_offset_), + y_offset_(rhs.y_offset_) { +} + +bool CompositeBitmapGlyph::Component::operator==( + const CompositeBitmapGlyph::Component& rhs) { + return glyph_code_ == rhs.glyph_code_; +} + +CompositeBitmapGlyph::Component& CompositeBitmapGlyph::Component::operator=( + const CompositeBitmapGlyph::Component& rhs) { + glyph_code_ = rhs.glyph_code_; + x_offset_ = rhs.x_offset_; + y_offset_ = rhs.y_offset_; + return *this; +} + +CompositeBitmapGlyph::Component::Component(int32_t glyph_code, + int32_t x_offset, + int32_t y_offset) + : glyph_code_(glyph_code), x_offset_(x_offset), y_offset_(y_offset) { +} + +/****************************************************************************** + * CompositeBitmapGlyph::Builder class + ******************************************************************************/ +CompositeBitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format) + : BitmapGlyph::Builder(data, format) { +} + +CompositeBitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format) + : BitmapGlyph::Builder(data, format) { +} + +CompositeBitmapGlyph::Builder::~Builder() { +} + +CALLER_ATTACH FontDataTable* +CompositeBitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) { + Ptr<CompositeBitmapGlyph> glyph = new CompositeBitmapGlyph(data, format()); + return glyph.Detach(); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.h new file mode 100644 index 0000000000..897db7e22a --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.h @@ -0,0 +1,75 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_ + +#include "sfntly/table/bitmap/bitmap_glyph.h" + +namespace sfntly { + +class CompositeBitmapGlyph : public BitmapGlyph, + public RefCounted<CompositeBitmapGlyph> { + public: + class Component { + public: + Component(const Component& rhs); + + int32_t glyph_code() { return glyph_code_; } + int32_t x_offset() { return x_offset_; } + int32_t y_offset() { return y_offset_; } + + // UNIMPLEMENTED: int hashCode() + bool operator==(const Component& rhs); + Component& operator=(const Component& rhs); + + protected: + Component(int32_t glyph_code, int32_t x_offset, int32_t y_offset); + + private: + int32_t glyph_code_; + int32_t x_offset_; + int32_t y_offset_; + + friend class CompositeBitmapGlyph; + }; + + class Builder : public BitmapGlyph::Builder, + public RefCounted<Builder> { + public: + Builder(WritableFontData* data, int32_t format); + Builder(ReadableFontData* data, int32_t format); + virtual ~Builder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + }; + + CompositeBitmapGlyph(ReadableFontData* data, int32_t format); + virtual ~CompositeBitmapGlyph(); + int32_t NumComponents(); + // Note: returned immutable object over stack. + Component GetComponent(int32_t component_num) const; + + private: + void Initialize(int32_t format); + + int32_t num_components_offset_; + int32_t component_array_offset_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/ebdt_table.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/ebdt_table.cc new file mode 100644 index 0000000000..eeb1fa06b3 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/ebdt_table.cc @@ -0,0 +1,236 @@ +/* + * 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 "sfntly/table/bitmap/ebdt_table.h" + +#include <stdlib.h> + +#include "sfntly/table/bitmap/composite_bitmap_glyph.h" +#include "sfntly/table/bitmap/simple_bitmap_glyph.h" + +namespace sfntly { +/****************************************************************************** + * EbdtTable class + ******************************************************************************/ +EbdtTable::~EbdtTable() { +} + +int32_t EbdtTable::Version() { + return data_->ReadFixed(Offset::kVersion); +} + +CALLER_ATTACH +BitmapGlyph* EbdtTable::Glyph(int32_t offset, int32_t length, int32_t format) { + ReadableFontDataPtr glyph_data; + glyph_data.Attach(down_cast<ReadableFontData*>(data_->Slice(offset, length))); + return BitmapGlyph::CreateGlyph(glyph_data, format); +} + +EbdtTable::EbdtTable(Header* header, ReadableFontData* data) + : SubTableContainerTable(header, data) { +} + +/****************************************************************************** + * EbdtTable::Builder class + ******************************************************************************/ +EbdtTable::Builder::Builder(Header* header, WritableFontData* data) + : SubTableContainerTable::Builder(header, data) { +} + +EbdtTable::Builder::Builder(Header* header, ReadableFontData* data) + : SubTableContainerTable::Builder(header, data) { +} + +EbdtTable::Builder::~Builder() { +} + +CALLER_ATTACH FontDataTable* + EbdtTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new EbdtTable(header(), data); + return table.Detach(); +} + +void EbdtTable::Builder::SubDataSet() { + Revert(); +} + +int32_t EbdtTable::Builder::SubDataSizeToSerialize() { + if (glyph_builders_.empty()) { + return 0; + } + bool fixed = true; + int32_t size = Offset::kHeaderLength; + for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(), + builder_end = glyph_builders_.end(); + builder_map != builder_end; + builder_map++) { + for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(), + glyph_entry_end = builder_map->end(); + glyph_entry != glyph_entry_end; + glyph_entry++) { + int32_t glyph_size = glyph_entry->second->SubDataSizeToSerialize(); + size += abs(glyph_size); + fixed = (glyph_size <= 0) ? false : fixed; + } + } + return (fixed ? 1 : -1) * size; +} + +bool EbdtTable::Builder::SubReadyToSerialize() { + if (glyph_builders_.empty()) { + return false; + } + return true; +} + +int32_t EbdtTable::Builder::SubSerialize(WritableFontData* new_data) { + int32_t size = 0; + size += new_data->WriteFixed(Offset::kVersion, kVersion); + for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(), + builder_end = glyph_builders_.end(); + builder_map != builder_end; + builder_map++) { + for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(), + glyph_entry_end = builder_map->end(); + glyph_entry != glyph_entry_end; + glyph_entry++) { + WritableFontDataPtr slice; + slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size))); + size += glyph_entry->second->SubSerialize(slice); + } + } + return size; +} + +void EbdtTable::Builder::SetLoca(BitmapLocaList* loca_list) { + assert(loca_list); + Revert(); + glyph_loca_.resize(loca_list->size()); + std::copy(loca_list->begin(), loca_list->end(), glyph_loca_.begin()); +} + +void EbdtTable::Builder::GenerateLocaList(BitmapLocaList* output) { + assert(output); + output->clear(); + + if (glyph_builders_.empty()) { + if (glyph_loca_.empty()) { + return; + } + } + + int start_offset = Offset::kHeaderLength; + for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(), + builder_end = glyph_builders_.end(); + builder_map != builder_end; + builder_map++) { + BitmapGlyphInfoMap new_loca_map; + int32_t glyph_offset = 0; + for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(), + glyph_end = builder_map->end(); + glyph_entry != glyph_end; + glyph_entry++) { + BitmapGlyphBuilderPtr builder = glyph_entry->second; + int32_t size = builder->SubDataSizeToSerialize(); + BitmapGlyphInfoPtr info = new BitmapGlyphInfo(glyph_entry->first, + start_offset + glyph_offset, size, builder->format()); + new_loca_map[glyph_entry->first] = info; + glyph_offset += size; + } + start_offset += glyph_offset; + output->push_back(new_loca_map); + } +} + +BitmapGlyphBuilderList* EbdtTable::Builder::GlyphBuilders() { + return GetGlyphBuilders(); +} + +void EbdtTable::Builder::SetGlyphBuilders( + BitmapGlyphBuilderList* glyph_builders) { + glyph_builders_.clear(); + std::copy(glyph_builders->begin(), glyph_builders->end(), + glyph_builders_.begin()); + set_model_changed(); +} + +void EbdtTable::Builder::Revert() { + glyph_loca_.clear(); + glyph_builders_.clear(); + set_model_changed(false); +} + +CALLER_ATTACH +EbdtTable::Builder* EbdtTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr<EbdtTable::Builder> builder; + builder = new Builder(header, data); + return builder.Detach(); +} + +CALLER_ATTACH +EbdtTable::Builder* EbdtTable::Builder::CreateBuilder(Header* header, + ReadableFontData* data) { + Ptr<EbdtTable::Builder> builder; + builder = new Builder(header, data); + return builder.Detach(); +} + +BitmapGlyphBuilderList* EbdtTable::Builder::GetGlyphBuilders() { + if (glyph_builders_.empty()) { + if (glyph_loca_.empty()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalStateException( + "Loca values not set - unable to parse glyph data."); +#endif + return NULL; + } + Initialize(InternalReadData(), &glyph_loca_, &glyph_builders_); + set_model_changed(); + } + return &glyph_builders_; +} + +void EbdtTable::Builder::Initialize(ReadableFontData* data, + BitmapLocaList* loca_list, + BitmapGlyphBuilderList* output) { + assert(loca_list); + assert(output); + + output->clear(); + if (data) { + for (BitmapLocaList::iterator loca_map = loca_list->begin(), + loca_end = loca_list->end(); + loca_map != loca_end; loca_map++) { + BitmapGlyphBuilderMap glyph_builder_map; + for (BitmapGlyphInfoMap::iterator entry = loca_map->begin(), + entry_end = loca_map->end(); + entry != entry_end; entry++) { + BitmapGlyphInfoPtr info = entry->second; + ReadableFontDataPtr slice; + slice.Attach(down_cast<ReadableFontData*>(data->Slice( + info->offset(), info->length()))); + BitmapGlyphBuilderPtr glyph_builder; + glyph_builder.Attach(BitmapGlyph::Builder::CreateGlyphBuilder( + slice, info->format())); + glyph_builder_map[entry->first] = glyph_builder; + } + output->push_back(glyph_builder_map); + } + } +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/ebdt_table.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/ebdt_table.h new file mode 100644 index 0000000000..d138c14ca5 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/ebdt_table.h @@ -0,0 +1,108 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_ + +#include "sfntly/table/bitmap/bitmap_glyph.h" +#include "sfntly/table/bitmap/bitmap_glyph_info.h" +#include "sfntly/table/subtable_container_table.h" + +namespace sfntly { + +class EbdtTable : public SubTableContainerTable, + public RefCounted<EbdtTable> { + public: + struct Offset { + enum { + kVersion = 0, + kHeaderLength = DataSize::kFixed, + }; + }; + + class Builder : public SubTableContainerTable::Builder, + public RefCounted<Builder> { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + + virtual int32_t SubSerialize(WritableFontData* new_data); + virtual bool SubReadyToSerialize(); + virtual int32_t SubDataSizeToSerialize(); + virtual void SubDataSet(); + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + void SetLoca(BitmapLocaList* loca_list); + void GenerateLocaList(BitmapLocaList* output); + + // Gets the List of glyph builders for the glyph table builder. These may be + // manipulated in any way by the caller and the changes will be reflected in + // the final glyph table produced. + // If there is no current data for the glyph builder or the glyph builders + // have not been previously set then this will return an empty glyph builder + // List. If there is current data (i.e. data read from an existing font) and + // the loca list has not been set or is null, empty, or invalid, then an + // empty glyph builder List will be returned. + // @return the list of glyph builders + BitmapGlyphBuilderList* GlyphBuilders(); + + // Replace the internal glyph builders with the one provided. The provided + // list and all contained objects belong to this builder. + // This call is only required if the entire set of glyphs in the glyph + // table builder are being replaced. If the glyph builder list provided from + // the {@link EbdtTable.Builder#glyphBuilders()} is being used and modified + // then those changes will already be reflected in the glyph table builder. + // @param glyphBuilders the new glyph builders + void SetGlyphBuilders(BitmapGlyphBuilderList* glyph_builders); + + void Revert(); + + // Create a new builder using the header information and data provided. + // @param header the header information + // @param data the data holding the table + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + ReadableFontData* data); + + private: + BitmapGlyphBuilderList* GetGlyphBuilders(); + static void Initialize(ReadableFontData* data, + BitmapLocaList* loca_list, + BitmapGlyphBuilderList* output); + + static const int32_t kVersion = 0x00020000; // TODO(stuartg): const/enum + BitmapLocaList glyph_loca_; + BitmapGlyphBuilderList glyph_builders_; + }; + + virtual ~EbdtTable(); + int32_t Version(); + CALLER_ATTACH BitmapGlyph* Glyph(int32_t offset, + int32_t length, + int32_t format); + protected: + EbdtTable(Header* header, ReadableFontData* data); +}; +typedef Ptr<EbdtTable> EbdtTablePtr; +typedef Ptr<EbdtTable::Builder> EbdtTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/eblc_table.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/eblc_table.cc new file mode 100644 index 0000000000..d0700d9984 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/eblc_table.cc @@ -0,0 +1,317 @@ +/* + * 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 "sfntly/table/bitmap/eblc_table.h" + +#include <stdio.h> +#include <stdlib.h> + +#include "sfntly/math/font_math.h" + +namespace sfntly { +/****************************************************************************** + * EblcTable class + ******************************************************************************/ +int32_t EblcTable::Version() { + return data_->ReadFixed(Offset::kVersion); +} + +int32_t EblcTable::NumSizes() { + return data_->ReadULongAsInt(Offset::kNumSizes); +} + +BitmapSizeTable* EblcTable::GetBitmapSizeTable(int32_t index) { + if (index < 0 || index > NumSizes()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException( + "Size table index is outside the range of tables."); +#endif + return NULL; + } + BitmapSizeTableList* bitmap_size_table_list = GetBitmapSizeTableList(); + if (bitmap_size_table_list) { + return (*bitmap_size_table_list)[index]; + } + return NULL; +} + +EblcTable::EblcTable(Header* header, ReadableFontData* data) + : SubTableContainerTable(header, data) { +} + +BitmapSizeTableList* EblcTable::GetBitmapSizeTableList() { + AutoLock lock(bitmap_size_table_lock_); + if (bitmap_size_table_.empty()) { + CreateBitmapSizeTable(data_, NumSizes(), &bitmap_size_table_); + } + return &bitmap_size_table_; +} + +// static +void EblcTable::CreateBitmapSizeTable(ReadableFontData* data, + int32_t num_sizes, + BitmapSizeTableList* output) { + assert(data); + assert(output); + for (int32_t i = 0; i < num_sizes; ++i) { + ReadableFontDataPtr new_data; + new_data.Attach(down_cast<ReadableFontData*>( + data->Slice(Offset::kBitmapSizeTableArrayStart + + i * Offset::kBitmapSizeTableLength, + Offset::kBitmapSizeTableLength))); + BitmapSizeTableBuilderPtr size_builder; + size_builder.Attach( + BitmapSizeTable::Builder::CreateBuilder(new_data, data)); + BitmapSizeTablePtr size; + size.Attach(down_cast<BitmapSizeTable*>(size_builder->Build())); + output->push_back(size); + } +} + +/****************************************************************************** + * EblcTable::Builder class + ******************************************************************************/ +EblcTable::Builder::Builder(Header* header, WritableFontData* data) + : SubTableContainerTable::Builder(header, data) { +} + +EblcTable::Builder::Builder(Header* header, ReadableFontData* data) + : SubTableContainerTable::Builder(header, data) { +} + +EblcTable::Builder::~Builder() { +} + +int32_t EblcTable::Builder::SubSerialize(WritableFontData* new_data) { + // header + int32_t size = new_data->WriteFixed(0, kVersion); + size += new_data->WriteULong(size, size_table_builders_.size()); + + // calculate the offsets + // offset to the start of the size table array + int32_t size_table_start_offset = size; + // walking offset in the size table array + int32_t size_table_offset = size_table_start_offset; + // offset to the start of the whole index subtable block + int32_t sub_table_block_start_offset = size_table_offset + + size_table_builders_.size() * Offset::kBitmapSizeTableLength; + // walking offset in the index subtable + // points to the start of the current subtable block + int32_t current_sub_table_block_start_offset = sub_table_block_start_offset; + +#if defined (SFNTLY_DEBUG_BITMAP) + int32_t size_index = 0; +#endif + for (BitmapSizeTableBuilderList::iterator + size_builder = size_table_builders_.begin(), + size_builder_end = size_table_builders_.end(); + size_builder != size_builder_end; size_builder++) { + (*size_builder)->SetIndexSubTableArrayOffset( + current_sub_table_block_start_offset); + IndexSubTableBuilderList* index_sub_table_builder_list = + (*size_builder)->IndexSubTableBuilders(); + + // walking offset within the current subTable array + int32_t index_sub_table_array_offset = current_sub_table_block_start_offset; + // walking offset within the subTable entries + int32_t index_sub_table_offset = index_sub_table_array_offset + + index_sub_table_builder_list->size() * Offset::kIndexSubHeaderLength; + +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "size %d: sizeTable=%x, current subTable Block=%x, ", + size_index, size_table_offset, + current_sub_table_block_start_offset); + fprintf(stderr, "index subTableStart=%x\n", index_sub_table_offset); + size_index++; + int32_t sub_table_index = 0; +#endif + for (IndexSubTableBuilderList::iterator + index_sub_table_builder = index_sub_table_builder_list->begin(), + index_sub_table_builder_end = index_sub_table_builder_list->end(); + index_sub_table_builder != index_sub_table_builder_end; + index_sub_table_builder++) { +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "\tsubTableIndex %d: format=%x, ", sub_table_index, + (*index_sub_table_builder)->index_format()); + fprintf(stderr, "indexSubTableArrayOffset=%x, indexSubTableOffset=%x\n", + index_sub_table_array_offset, index_sub_table_offset); + sub_table_index++; +#endif + // array entry + index_sub_table_array_offset += new_data->WriteUShort( + index_sub_table_array_offset, + (*index_sub_table_builder)->first_glyph_index()); + index_sub_table_array_offset += new_data->WriteUShort( + index_sub_table_array_offset, + (*index_sub_table_builder)->last_glyph_index()); + index_sub_table_array_offset += new_data->WriteULong( + index_sub_table_array_offset, + index_sub_table_offset - current_sub_table_block_start_offset); + + // index sub table + WritableFontDataPtr slice_index_sub_table; + slice_index_sub_table.Attach(down_cast<WritableFontData*>( + new_data->Slice(index_sub_table_offset))); + int32_t current_sub_table_size = + (*index_sub_table_builder)->SubSerialize(slice_index_sub_table); + int32_t padding = FontMath::PaddingRequired(current_sub_table_size, + DataSize::kULONG); +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "\t\tsubTableSize = %x, padding = %x\n", + current_sub_table_size, padding); +#endif + index_sub_table_offset += current_sub_table_size; + index_sub_table_offset += + new_data->WritePadding(index_sub_table_offset, padding); + } + + // serialize size table + (*size_builder)->SetIndexTableSize( + index_sub_table_offset - current_sub_table_block_start_offset); + WritableFontDataPtr slice_size_table; + slice_size_table.Attach(down_cast<WritableFontData*>( + new_data->Slice(size_table_offset))); + size_table_offset += (*size_builder)->SubSerialize(slice_size_table); + + current_sub_table_block_start_offset = index_sub_table_offset; + } + return size + current_sub_table_block_start_offset; +} + +bool EblcTable::Builder::SubReadyToSerialize() { + if (size_table_builders_.empty()) { + return false; + } + for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(), + e = size_table_builders_.end(); + b != e; b++) { + if (!(*b)->SubReadyToSerialize()) { + return false; + } + } + return true; +} + +int32_t EblcTable::Builder::SubDataSizeToSerialize() { + if (size_table_builders_.empty()) { + return 0; + } + int32_t size = Offset::kHeaderLength; + bool variable = false; +#if defined (SFNTLY_DEBUG_BITMAP) + size_t size_index = 0; +#endif + for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(), + e = size_table_builders_.end(); + b != e; b++) { + int32_t size_builder_size = (*b)->SubDataSizeToSerialize(); +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "sizeIndex = %d, sizeBuilderSize=0x%x (%d)\n", + size_index++, size_builder_size, size_builder_size); +#endif + variable = size_builder_size > 0 ? variable : true; + size += abs(size_builder_size); + } +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "eblc size=%d\n", size); +#endif + return variable ? -size : size; +} + +void EblcTable::Builder::SubDataSet() { + Revert(); +} + +BitmapSizeTableBuilderList* EblcTable::Builder::BitmapSizeBuilders() { + return GetSizeList(); +} + +void EblcTable::Builder::Revert() { + size_table_builders_.clear(); + set_model_changed(false); +} + +void EblcTable::Builder::GenerateLocaList(BitmapLocaList* output) { + assert(output); + BitmapSizeTableBuilderList* size_builder_list = GetSizeList(); + output->clear(); +#if defined (SFNTLY_DEBUG_BITMAP) + int32_t size_index = 0; +#endif + for (BitmapSizeTableBuilderList::iterator b = size_builder_list->begin(), + e = size_builder_list->end(); + b != e; b++) { +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "size table = %d\n", size_index++); +#endif + BitmapGlyphInfoMap loca_map; + (*b)->GenerateLocaMap(&loca_map); + output->push_back(loca_map); + } +} + +CALLER_ATTACH +FontDataTable* EblcTable::Builder::SubBuildTable(ReadableFontData* data) { + Ptr<EblcTable> new_table = new EblcTable(header(), data); + return new_table.Detach(); +} + +// static +CALLER_ATTACH EblcTable::Builder* + EblcTable::Builder::CreateBuilder(Header* header, WritableFontData* data) { + Ptr<EblcTable::Builder> new_builder = new EblcTable::Builder(header, data); + return new_builder.Detach(); +} + +// static +CALLER_ATTACH EblcTable::Builder* + EblcTable::Builder::CreateBuilder(Header* header, ReadableFontData* data) { + Ptr<EblcTable::Builder> new_builder = new EblcTable::Builder(header, data); + return new_builder.Detach(); +} + +BitmapSizeTableBuilderList* EblcTable::Builder::GetSizeList() { + if (size_table_builders_.empty()) { + Initialize(InternalReadData(), &size_table_builders_); + set_model_changed(); + } + return &size_table_builders_; +} + +void EblcTable::Builder::Initialize(ReadableFontData* data, + BitmapSizeTableBuilderList* output) { + assert(output); + if (!data) + return; + + int32_t num_sizes = data->ReadULongAsInt(Offset::kNumSizes); + if (num_sizes > data->Size() / Offset::kBitmapSizeTableLength) + return; + + for (int32_t i = 0; i < num_sizes; ++i) { + ReadableFontDataPtr new_data; + new_data.Attach(down_cast<ReadableFontData*>( + data->Slice(Offset::kBitmapSizeTableArrayStart + + i * Offset::kBitmapSizeTableLength, + Offset::kBitmapSizeTableLength))); + BitmapSizeTableBuilderPtr size_builder; + size_builder.Attach(BitmapSizeTable::Builder::CreateBuilder( + new_data, data)); + output->push_back(size_builder); + } +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/eblc_table.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/eblc_table.h new file mode 100644 index 0000000000..b04338a93b --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/eblc_table.h @@ -0,0 +1,194 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_ + +#include "sfntly/port/lock.h" +#include "sfntly/table/bitmap/big_glyph_metrics.h" +#include "sfntly/table/bitmap/bitmap_glyph.h" +#include "sfntly/table/bitmap/bitmap_size_table.h" +#include "sfntly/table/subtable_container_table.h" + +namespace sfntly { + +class EblcTable : public SubTableContainerTable, + public RefCounted<EblcTable> { + public: + struct Offset { + enum { + // header + kVersion = 0, + kNumSizes = 4, + kHeaderLength = kNumSizes + DataSize::kULONG, + + // bitmapSizeTable + kBitmapSizeTableArrayStart = kHeaderLength, + kBitmapSizeTableLength = 48, + kBitmapSizeTable_indexSubTableArrayOffset = 0, + kBitmapSizeTable_indexTableSize = 4, + kBitmapSizeTable_numberOfIndexSubTables = 8, + kBitmapSizeTable_colorRef = 12, + kBitmapSizeTable_hori = 16, + kBitmapSizeTable_vert = 28, + kBitmapSizeTable_startGlyphIndex = 40, + kBitmapSizeTable_endGlyphIndex = 42, + kBitmapSizeTable_ppemX = 44, + kBitmapSizeTable_ppemY = 45, + kBitmapSizeTable_bitDepth = 46, + kBitmapSizeTable_flags = 47, + + // sbitLineMetrics + kSbitLineMetricsLength = 12, + kSbitLineMetrics_ascender = 0, + kSbitLineMetrics_descender = 1, + kSbitLineMetrics_widthMax = 2, + kSbitLineMetrics_caretSlopeNumerator = 3, + kSbitLineMetrics_caretSlopeDenominator = 4, + kSbitLineMetrics_caretOffset = 5, + kSbitLineMetrics_minOriginSB = 6, + kSbitLineMetrics_minAdvanceSB = 7, + kSbitLineMetrics_maxBeforeBL = 8, + kSbitLineMetrics_minAfterBL = 9, + kSbitLineMetrics_pad1 = 10, + kSbitLineMetrics_pad2 = 11, + + // indexSubTable + kIndexSubTableEntryLength = 8, + kIndexSubTableEntry_firstGlyphIndex = 0, + kIndexSubTableEntry_lastGlyphIndex = 2, + kIndexSubTableEntry_additionalOffsetToIndexSubTable = 4, + + // indexSubHeader + kIndexSubHeaderLength = 8, + kIndexSubHeader_indexFormat = 0, + kIndexSubHeader_imageFormat = 2, + kIndexSubHeader_imageDataOffset = 4, + + // indexSubTable - all offset relative to the subtable start + + // indexSubTable1 + kIndexSubTable1_offsetArray = kIndexSubHeaderLength, + kIndexSubTable1_builderDataSize = kIndexSubHeaderLength, + + // kIndexSubTable2 + kIndexSubTable2Length = kIndexSubHeaderLength + + DataSize::kULONG + + BitmapGlyph::Offset::kBigGlyphMetricsLength, + kIndexSubTable2_imageSize = kIndexSubHeaderLength, + kIndexSubTable2_bigGlyphMetrics = kIndexSubTable2_imageSize + + DataSize::kULONG, + kIndexSubTable2_builderDataSize = kIndexSubTable2_bigGlyphMetrics + + BigGlyphMetrics::Offset::kMetricsLength, + + // kIndexSubTable3 + kIndexSubTable3_offsetArray = kIndexSubHeaderLength, + kIndexSubTable3_builderDataSize = kIndexSubTable3_offsetArray, + + // kIndexSubTable4 + kIndexSubTable4_numGlyphs = kIndexSubHeaderLength, + kIndexSubTable4_glyphArray = kIndexSubTable4_numGlyphs + + DataSize::kULONG, + kIndexSubTable4_codeOffsetPairLength = 2 * DataSize::kUSHORT, + kIndexSubTable4_codeOffsetPair_glyphCode = 0, + kIndexSubTable4_codeOffsetPair_offset = DataSize::kUSHORT, + kIndexSubTable4_builderDataSize = kIndexSubTable4_glyphArray, + + // kIndexSubTable5 + kIndexSubTable5_imageSize = kIndexSubHeaderLength, + kIndexSubTable5_bigGlyphMetrics = kIndexSubTable5_imageSize + + DataSize::kULONG, + kIndexSubTable5_numGlyphs = kIndexSubTable5_bigGlyphMetrics + + BitmapGlyph::Offset::kBigGlyphMetricsLength, + kIndexSubTable5_glyphArray = kIndexSubTable5_numGlyphs + + DataSize::kULONG, + kIndexSubTable5_builderDataSize = kIndexSubTable5_glyphArray, + + // codeOffsetPair + kCodeOffsetPairLength = 2 * DataSize::kUSHORT, + kCodeOffsetPair_glyphCode = 0, + kCodeOffsetPair_offset = DataSize::kUSHORT, + }; + }; + + class Builder : public SubTableContainerTable::Builder, + public RefCounted<Builder> { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + + virtual int32_t SubSerialize(WritableFontData* new_data); + virtual bool SubReadyToSerialize(); + virtual int32_t SubDataSizeToSerialize(); + virtual void SubDataSet(); + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + BitmapSizeTableBuilderList* BitmapSizeBuilders(); + void Revert(); + + // Generates the loca list for the EBDT table. The list is intended to be + // used by the EBDT to allow it to parse the glyph data and generate glyph + // objects. After returning from this method the list belongs to the caller. + // The list entries are in the same order as the size table builders are at + // the time of this call. + // @return the list of loca maps with one for each size table builder + void GenerateLocaList(BitmapLocaList* output); + + // Create a new builder using the header information and data provided. + // @param header the header information + // @param data the data holding the table + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + ReadableFontData* data); + + private: + BitmapSizeTableBuilderList* GetSizeList(); + void Initialize(ReadableFontData* data, BitmapSizeTableBuilderList* output); + + static const int32_t kVersion = 0x00020000; + BitmapSizeTableBuilderList size_table_builders_; + }; + + int32_t Version(); + int32_t NumSizes(); + // UNIMPLEMENTED: toString() + + BitmapSizeTable* GetBitmapSizeTable(int32_t index); + + static const int32_t NOTDEF = -1; + + protected: + EblcTable(Header* header, ReadableFontData* data); + + private: + BitmapSizeTableList* GetBitmapSizeTableList(); + + static void CreateBitmapSizeTable(ReadableFontData* data, + int32_t num_sizes, + BitmapSizeTableList* output); + + Lock bitmap_size_table_lock_; + BitmapSizeTableList bitmap_size_table_; +}; +typedef Ptr<EblcTable> EblcTablePtr; +typedef Ptr<EblcTable::Builder> EblcTableBuilderPtr; +} + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/ebsc_table.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/ebsc_table.cc new file mode 100644 index 0000000000..458c2d49e8 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/ebsc_table.cc @@ -0,0 +1,107 @@ +/* + * 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 "sfntly/table/bitmap/ebsc_table.h" + +namespace sfntly { +/****************************************************************************** + * EbscTable class + ******************************************************************************/ +EbscTable::~EbscTable() { +} + +int32_t EbscTable::Version() { + return data_->ReadFixed(Offset::kVersion); +} + +int32_t EbscTable::NumSizes() { + return data_->ReadULongAsInt(Offset::kNumSizes); +} + +EbscTable::EbscTable(Header* header, ReadableFontData* data) + : Table(header, data) { +} + +/****************************************************************************** + * EbscTable::BitmapScaleTable class + ******************************************************************************/ +EbscTable::BitmapScaleTable::~BitmapScaleTable() { +} + +EbscTable::BitmapScaleTable::BitmapScaleTable(ReadableFontData* data) + : SubTable(data) { +} + +int32_t EbscTable::BitmapScaleTable::PpemX() { + return data_->ReadByte(Offset::kBitmapScaleTable_ppemX); +} + +int32_t EbscTable::BitmapScaleTable::PpemY() { + return data_->ReadByte(Offset::kBitmapScaleTable_ppemY); +} + +int32_t EbscTable::BitmapScaleTable::SubstitutePpemX() { + return data_->ReadByte(Offset::kBitmapScaleTable_substitutePpemX); +} + +int32_t EbscTable::BitmapScaleTable::SubstitutePpemY() { + return data_->ReadByte(Offset::kBitmapScaleTable_substitutePpemY); +} + +/****************************************************************************** + * EbscTable::Builder class + ******************************************************************************/ +EbscTable::Builder::~Builder() { +} + +CALLER_ATTACH EbscTable::Builder* EbscTable::Builder::CreateBuilder( + Header* header, WritableFontData* data) { + EbscTableBuilderPtr builder = new EbscTable::Builder(header, data); + return builder.Detach(); +} + +EbscTable::Builder::Builder(Header* header, WritableFontData* data) + : Table::Builder(header, data) { +} + +EbscTable::Builder::Builder(Header* header, ReadableFontData* data) + : Table::Builder(header, data) { +} + +CALLER_ATTACH +FontDataTable* EbscTable::Builder::SubBuildTable(ReadableFontData* data) { + EbscTablePtr output = new EbscTable(header(), data); + return output.Detach(); +} + +void EbscTable::Builder::SubDataSet() { + // NOP +} + +int32_t EbscTable::Builder::SubDataSizeToSerialize() { + return 0; +} + +bool EbscTable::Builder::SubReadyToSerialize() { + return false; +} + +int32_t EbscTable::Builder::SubSerialize(WritableFontData* new_data) { + UNREFERENCED_PARAMETER(new_data); + return 0; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/ebsc_table.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/ebsc_table.h new file mode 100644 index 0000000000..b79df380df --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/ebsc_table.h @@ -0,0 +1,101 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_ + +#include "sfntly/table/bitmap/eblc_table.h" + +namespace sfntly { + +class EbscTable : public Table, + public RefCounted<EbscTable> { + public: + struct Offset { + enum { + // header + kVersion = 0, + kNumSizes = DataSize::kFixed, + kHeaderLength = kNumSizes + DataSize::kULONG, + kBitmapScaleTableStart = kHeaderLength, + + // bitmapScaleTable + kBitmapScaleTable_hori = 0, + kBitmapScaleTable_vert = EblcTable::Offset::kSbitLineMetricsLength, + kBitmapScaleTable_ppemX = kBitmapScaleTable_vert + + EblcTable::Offset::kSbitLineMetricsLength, + kBitmapScaleTable_ppemY = kBitmapScaleTable_ppemX + DataSize::kBYTE, + kBitmapScaleTable_substitutePpemX = kBitmapScaleTable_ppemY + + DataSize::kBYTE, + kBitmapScaleTable_substitutePpemY = kBitmapScaleTable_substitutePpemX + + DataSize::kBYTE, + kBitmapScaleTableLength = kBitmapScaleTable_substitutePpemY + + DataSize::kBYTE, + }; + }; + + class BitmapScaleTable : public SubTable, + public RefCounted<BitmapScaleTable> { + public: + virtual ~BitmapScaleTable(); + int32_t PpemX(); + int32_t PpemY(); + int32_t SubstitutePpemX(); + int32_t SubstitutePpemY(); + + protected: + // Note: caller to do data->Slice(offset, Offset::kBitmapScaleTableLength) + explicit BitmapScaleTable(ReadableFontData* data); + }; + + // TODO(stuartg): currently the builder just builds from initial data + // - need to make fully working but few if any examples to test with + class Builder : public Table::Builder, + public RefCounted<Builder> { + public: + virtual ~Builder(); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + protected: + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + }; + + virtual ~EbscTable(); + + int32_t Version(); + int32_t NumSizes(); + // Note: renamed from bitmapScaleTable + CALLER_ATTACH BitmapScaleTable* GetBitmapScaleTable(int32_t index); + + private: + EbscTable(Header* header, ReadableFontData* data); + friend class Builder; +}; +typedef Ptr<EbscTable> EbscTablePtr; +typedef Ptr<EbscTable::Builder> EbscTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/glyph_metrics.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/glyph_metrics.cc new file mode 100644 index 0000000000..e91eb9921e --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/glyph_metrics.cc @@ -0,0 +1,39 @@ +/* + * 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 "sfntly/table/bitmap/glyph_metrics.h" + +namespace sfntly { + +GlyphMetrics::~GlyphMetrics() { +} + +GlyphMetrics::GlyphMetrics(ReadableFontData* data) + : SubTable(data) { +} + +GlyphMetrics::Builder::~Builder() { +} + +GlyphMetrics::Builder::Builder(WritableFontData* data) + : SubTable::Builder(data) { +} + +GlyphMetrics::Builder::Builder(ReadableFontData* data) + : SubTable::Builder(data) { +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/glyph_metrics.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/glyph_metrics.h new file mode 100644 index 0000000000..5f16aaa661 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/glyph_metrics.h @@ -0,0 +1,43 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_ + +#include "sfntly/table/subtable.h" + +namespace sfntly { + +class GlyphMetrics : public SubTable { + public: + virtual ~GlyphMetrics(); + + protected: + class Builder : public SubTable::Builder { + public: + virtual ~Builder(); + + protected: + explicit Builder(WritableFontData* data); + explicit Builder(ReadableFontData* data); + }; + + explicit GlyphMetrics(ReadableFontData* data); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table.cc new file mode 100644 index 0000000000..5e29784504 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table.cc @@ -0,0 +1,278 @@ +/* + * 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 "sfntly/table/bitmap/index_sub_table.h" + +#include "sfntly/table/bitmap/eblc_table.h" +#include "sfntly/table/bitmap/index_sub_table_format1.h" +#include "sfntly/table/bitmap/index_sub_table_format2.h" +#include "sfntly/table/bitmap/index_sub_table_format3.h" +#include "sfntly/table/bitmap/index_sub_table_format4.h" +#include "sfntly/table/bitmap/index_sub_table_format5.h" + +namespace sfntly { +/****************************************************************************** + * IndexSubTable class + ******************************************************************************/ +CALLER_ATTACH BitmapGlyphInfo* IndexSubTable::GlyphInfo(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return NULL; + } + if (GlyphStartOffset(glyph_id) == -1) { + return NULL; + } + BitmapGlyphInfoPtr output = new BitmapGlyphInfo(glyph_id, + image_data_offset(), + GlyphStartOffset(glyph_id), + GlyphLength(glyph_id), + image_format()); + return output.Detach(); +} + +int32_t IndexSubTable::GlyphOffset(int32_t glyph_id) { + int32_t glyph_start_offset = GlyphStartOffset(glyph_id); + if (glyph_start_offset == -1) { + return -1; + } + return image_data_offset() + glyph_start_offset; +} + +// static +CALLER_ATTACH IndexSubTable* + IndexSubTable::CreateIndexSubTable(ReadableFontData* data, + int32_t offset_to_index_sub_table_array, + int32_t array_index) { + IndexSubTableBuilderPtr builder; + builder.Attach(IndexSubTable::Builder::CreateBuilder( + data, offset_to_index_sub_table_array, array_index)); + return down_cast<IndexSubTable*>(builder->Build()); +} + +IndexSubTable::IndexSubTable(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : SubTable(data), + first_glyph_index_(first_glyph_index), + last_glyph_index_(last_glyph_index) { + index_format_ = + data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat); + image_format_ = + data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat); + image_data_offset_ = + data_->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset); +} + +int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id) { + return CheckGlyphRange(glyph_id, first_glyph_index(), last_glyph_index()); +} + +// static +int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id, + int32_t first_glyph_id, + int32_t last_glyph_id) { + if (glyph_id < first_glyph_id || glyph_id > last_glyph_id) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException("Glyph ID is outside of the allowed range."); +#endif + return -1; + } + return glyph_id - first_glyph_id; +} + +/****************************************************************************** + * IndexSubTable::Builder class + ******************************************************************************/ +IndexSubTable::Builder::~Builder() { +} + +void IndexSubTable::Builder::Revert() { + set_model_changed(false); + Initialize(InternalReadData()); +} + +CALLER_ATTACH BitmapGlyphInfo* IndexSubTable::Builder::GlyphInfo( + int32_t glyph_id) { + BitmapGlyphInfoPtr glyph_info = + new BitmapGlyphInfo(glyph_id, + image_data_offset(), + GlyphStartOffset(glyph_id), + GlyphLength(glyph_id), + image_format()); + return glyph_info.Detach(); +} + +int32_t IndexSubTable::Builder::GlyphOffset(int32_t glyph_id) { + return image_data_offset() + GlyphStartOffset(glyph_id); +} + +// static +CALLER_ATTACH IndexSubTable::Builder* +IndexSubTable::Builder::CreateBuilder(int32_t index_format) { + switch (index_format) { + case Format::FORMAT_1: + return IndexSubTableFormat1::Builder::CreateBuilder(); + case Format::FORMAT_2: + return IndexSubTableFormat2::Builder::CreateBuilder(); + case Format::FORMAT_3: + return IndexSubTableFormat3::Builder::CreateBuilder(); + case Format::FORMAT_4: + return IndexSubTableFormat4::Builder::CreateBuilder(); + case Format::FORMAT_5: + return IndexSubTableFormat5::Builder::CreateBuilder(); + default: +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalArgumentException("Invalid index subtable format"); +#endif + return NULL; + } +} + +// static +CALLER_ATTACH IndexSubTable::Builder* +IndexSubTable::Builder::CreateBuilder(ReadableFontData* data, + int32_t offset_to_index_sub_table_array, int32_t array_index) { + int32_t index_sub_table_entry_offset = + offset_to_index_sub_table_array + + array_index * EblcTable::Offset::kIndexSubTableEntryLength; + int32_t first_glyph_index = + data->ReadUShort(index_sub_table_entry_offset + + EblcTable::Offset::kIndexSubTableEntry_firstGlyphIndex); + int32_t last_glyph_index = + data->ReadUShort(index_sub_table_entry_offset + + EblcTable::Offset::kIndexSubTableEntry_lastGlyphIndex); + int32_t additional_offset_to_index_subtable = data->ReadULongAsInt( + index_sub_table_entry_offset + + EblcTable::Offset::kIndexSubTableEntry_additionalOffsetToIndexSubTable); + int32_t index_sub_table_offset = offset_to_index_sub_table_array + + additional_offset_to_index_subtable; + int32_t index_format = data->ReadUShort(index_sub_table_offset); + switch (index_format) { + case 1: + return IndexSubTableFormat1::Builder::CreateBuilder( + data, index_sub_table_offset, first_glyph_index, last_glyph_index); + case 2: + return IndexSubTableFormat2::Builder::CreateBuilder( + data, index_sub_table_offset, first_glyph_index, last_glyph_index); + case 3: + return IndexSubTableFormat3::Builder::CreateBuilder( + data, index_sub_table_offset, first_glyph_index, last_glyph_index); + case 4: + return IndexSubTableFormat4::Builder::CreateBuilder( + data, index_sub_table_offset, first_glyph_index, last_glyph_index); + case 5: + return IndexSubTableFormat5::Builder::CreateBuilder( + data, index_sub_table_offset, first_glyph_index, last_glyph_index); + default: + // Unknown format and unable to process. +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalArgumentException("Invalid Index Subtable Format"); +#endif + break; + } + return NULL; +} + +CALLER_ATTACH +FontDataTable* IndexSubTable::Builder::SubBuildTable(ReadableFontData* data) { + UNREFERENCED_PARAMETER(data); + return NULL; +} + +void IndexSubTable::Builder::SubDataSet() { + // NOP +} + +int32_t IndexSubTable::Builder::SubDataSizeToSerialize() { + return 0; +} + +bool IndexSubTable::Builder::SubReadyToSerialize() { + return false; +} + +int32_t IndexSubTable::Builder::SubSerialize(WritableFontData* new_data) { + UNREFERENCED_PARAMETER(new_data); + return 0; +} + +IndexSubTable::Builder::Builder(int32_t data_size, int32_t index_format) + : SubTable::Builder(data_size), + first_glyph_index_(0), + last_glyph_index_(0), + index_format_(index_format), + image_format_(0), + image_data_offset_(0) { +} + +IndexSubTable::Builder::Builder(int32_t index_format, + int32_t image_format, + int32_t image_data_offset, + int32_t data_size) + : SubTable::Builder(data_size), + first_glyph_index_(0), + last_glyph_index_(0), + index_format_(index_format), + image_format_(image_format), + image_data_offset_(image_data_offset) { +} + +IndexSubTable::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : SubTable::Builder(data), + first_glyph_index_(first_glyph_index), + last_glyph_index_(last_glyph_index) { + Initialize(data); +} + +IndexSubTable::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : SubTable::Builder(data), + first_glyph_index_(first_glyph_index), + last_glyph_index_(last_glyph_index) { + Initialize(data); +} + +int32_t IndexSubTable::Builder::CheckGlyphRange(int32_t glyph_id) { + return IndexSubTable::CheckGlyphRange(glyph_id, + first_glyph_index(), + last_glyph_index()); +} + +int32_t IndexSubTable::Builder::SerializeIndexSubHeader( + WritableFontData* data) { + int32_t size = + data->WriteUShort(EblcTable::Offset::kIndexSubHeader_indexFormat, + index_format()); + size += data->WriteUShort(EblcTable::Offset::kIndexSubHeader_imageFormat, + image_format()); + size += data->WriteULong(EblcTable::Offset::kIndexSubHeader_imageDataOffset, + image_data_offset()); + return size; +} + +void IndexSubTable::Builder::Initialize(ReadableFontData* data) { + index_format_ = + data->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat); + image_format_ = + data->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat); + image_data_offset_ = + data->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table.h new file mode 100644 index 0000000000..6d27129ccd --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table.h @@ -0,0 +1,178 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_H_ + +#include <vector> + +#include "sfntly/port/java_iterator.h" +#include "sfntly/table/subtable.h" +#include "sfntly/table/bitmap/bitmap_glyph_info.h" + +namespace sfntly { + +class IndexSubTable : public SubTable { + public: + struct Format { + enum { + FORMAT_1 = 1, + FORMAT_2 = 2, + FORMAT_3 = 3, + FORMAT_4 = 4, + FORMAT_5 = 5, + }; + }; + + class Builder : public SubTable::Builder { + public: + virtual ~Builder(); + + void Revert(); + + int32_t index_format() { return index_format_; } + int32_t first_glyph_index() { return first_glyph_index_; } + void set_first_glyph_index(int32_t v) { first_glyph_index_ = v; } + int32_t last_glyph_index() { return last_glyph_index_; } + void set_last_glyph_index(int32_t v) { last_glyph_index_ = v; } + int32_t image_format() { return image_format_; } + void set_image_format(int32_t v) { image_format_ = v; } + int32_t image_data_offset() { return image_data_offset_; } + void set_image_data_offset(int32_t v) { image_data_offset_ = v; } + + virtual int32_t NumGlyphs() = 0; + + // Gets the glyph info for the specified glyph id. + // @param glyphId the glyph id to look up + // @return the glyph info + CALLER_ATTACH virtual BitmapGlyphInfo* GlyphInfo(int32_t glyph_id); + + // Gets the full offset of the glyph within the EBDT table. + // @param glyphId the glyph id + // @return the glyph offset + virtual int32_t GlyphOffset(int32_t glyph_id); + + // Gets the offset of the glyph relative to the block for this index + // subtable. + // @param glyphId the glyph id + // @return the glyph offset + virtual int32_t GlyphStartOffset(int32_t glyph_id) = 0; + + // Gets the length of the glyph within the EBDT table. + // @param glyphId the glyph id + // @return the glyph offset + virtual int32_t GlyphLength(int32_t glyph_id) = 0; + + // Note: renamed from java iterator() + CALLER_ATTACH virtual Iterator<BitmapGlyphInfo, IndexSubTable::Builder>* + GetIterator() = 0; + + // Static instantiation function. + static CALLER_ATTACH Builder* CreateBuilder(int32_t index_format); + static CALLER_ATTACH Builder* + CreateBuilder(ReadableFontData* data, + int32_t offset_to_index_sub_table_array, + int32_t array_index); + + // The following methods will never be called but they need to be here to + // allow the BitmapSizeTable to see these methods through an abstract + // reference. + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + protected: + Builder(int32_t data_size, int32_t index_format); + Builder(int32_t index_format, + int32_t image_format, + int32_t image_data_offset, + int32_t data_size); + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + + // Checks that the glyph id is within the correct range. If it returns the + // offset of the glyph id from the start of the range. + // @param glyphId + // @return the offset of the glyphId from the start of the glyph range + // @throws IndexOutOfBoundsException if the glyph id is not within the + // correct range + int32_t CheckGlyphRange(int32_t glyph_id); + int32_t SerializeIndexSubHeader(WritableFontData* data); + + private: + void Initialize(ReadableFontData* data); + + int32_t first_glyph_index_; + int32_t last_glyph_index_; + int32_t index_format_; + int32_t image_format_; + int32_t image_data_offset_; + }; + + int32_t index_format() { return index_format_; } + int32_t first_glyph_index() { return first_glyph_index_; } + int32_t last_glyph_index() { return last_glyph_index_; } + int32_t image_format() { return image_format_; } + int32_t image_data_offset() { return image_data_offset_; } + + CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id); + virtual int32_t GlyphOffset(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id) = 0; + virtual int32_t GlyphLength(int32_t glyph_id) = 0; + virtual int32_t NumGlyphs() = 0; + + static CALLER_ATTACH IndexSubTable* + CreateIndexSubTable(ReadableFontData* data, + int32_t offset_to_index_sub_table_array, + int32_t array_index); + + protected: + // Note: the constructor does not implement offset/length form provided in + // Java to avoid heavy lifting in constructors. Callers to call + // GetDataLength() static method of the derived class to get proper + // length and slice ahead. + IndexSubTable(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + + int32_t CheckGlyphRange(int32_t glyph_id); + static int32_t CheckGlyphRange(int32_t glyph_id, + int32_t first_glyph_id, + int32_t last_glyph_id); + + private: + int32_t first_glyph_index_; + int32_t last_glyph_index_; + int32_t index_format_; + int32_t image_format_; + int32_t image_data_offset_; +}; +typedef Ptr<IndexSubTable> IndexSubTablePtr; +typedef std::vector<IndexSubTablePtr> IndexSubTableList; +typedef Ptr<IndexSubTable::Builder> IndexSubTableBuilderPtr; +typedef std::vector<IndexSubTableBuilderPtr> IndexSubTableBuilderList; +typedef Iterator<BitmapGlyphInfo, IndexSubTable::Builder> BitmapGlyphInfoIter; +typedef Ptr<BitmapGlyphInfoIter> BitmapGlyphInfoIterPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format1.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format1.cc new file mode 100644 index 0000000000..42d21ab4ae --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format1.cc @@ -0,0 +1,302 @@ +/* + * 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 "sfntly/table/bitmap/index_sub_table_format1.h" + +#include "sfntly/table/bitmap/eblc_table.h" + +namespace sfntly { +/****************************************************************************** + * IndexSubTableFormat1 class + ******************************************************************************/ +// static +int32_t IndexSubTableFormat1::GetDataLength(ReadableFontData* data, + int32_t offset, + int32_t first, + int32_t last) { + UNREFERENCED_PARAMETER(data); + UNREFERENCED_PARAMETER(offset); + return (last - first + 1 + 1) * DataSize::kULONG; +} + +IndexSubTableFormat1::~IndexSubTableFormat1() { +} + +int32_t IndexSubTableFormat1::NumGlyphs() { + return last_glyph_index() - first_glyph_index() + 1; +} + +int32_t IndexSubTableFormat1::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + return Loca(loca); +} + +int32_t IndexSubTableFormat1::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + return Loca(loca + 1) - Loca(loca); +} + +IndexSubTableFormat1::IndexSubTableFormat1(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable(data, first_glyph_index, last_glyph_index) { +} + +int32_t IndexSubTableFormat1::Loca(int32_t loca) { + return image_data_offset() + + data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable1_offsetArray + + loca * DataSize::kULONG); +} + +/****************************************************************************** + * IndexSubTableFormat1::Builder class + ******************************************************************************/ +IndexSubTableFormat1::Builder::~Builder() { +} + +int32_t IndexSubTableFormat1::Builder::NumGlyphs() { + return GetOffsetArray()->size() - 1; +} + +int32_t IndexSubTableFormat1::Builder::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return 0; + } + std::vector<int32_t>* offset_array = GetOffsetArray(); + return offset_array->at(loca + 1) - offset_array->at(loca); +} + +int32_t IndexSubTableFormat1::Builder::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + return GetOffsetArray()->at(loca); +} + +CALLER_ATTACH IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* + IndexSubTableFormat1::Builder::GetIterator() { + Ptr<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator> it = + new IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator(this); + return it.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat1::Builder* +IndexSubTableFormat1::Builder::CreateBuilder() { + IndexSubTableFormat1BuilderPtr output = new IndexSubTableFormat1::Builder(); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat1::Builder* +IndexSubTableFormat1::Builder::CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + ReadableFontDataPtr new_data; + new_data.Attach(down_cast<ReadableFontData*>( + data->Slice(index_sub_table_offset, length))); + if (new_data == NULL) { + return NULL; + } + IndexSubTableFormat1BuilderPtr output = + new IndexSubTableFormat1::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + + +// static +CALLER_ATTACH IndexSubTableFormat1::Builder* +IndexSubTableFormat1::Builder::CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + WritableFontDataPtr new_data; + new_data.Attach(down_cast<WritableFontData*>( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat1BuilderPtr output = + new IndexSubTableFormat1::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +CALLER_ATTACH FontDataTable* IndexSubTableFormat1::Builder::SubBuildTable( + ReadableFontData* data) { + IndexSubTableFormat1Ptr output = new IndexSubTableFormat1( + data, first_glyph_index(), last_glyph_index()); + return output.Detach(); +} + +void IndexSubTableFormat1::Builder::SubDataSet() { + Revert(); +} + +int32_t IndexSubTableFormat1::Builder::SubDataSizeToSerialize() { + if (offset_array_.empty()) { + return InternalReadData()->Length(); + } + return EblcTable::Offset::kIndexSubHeaderLength + + offset_array_.size() * DataSize::kULONG; +} + +bool IndexSubTableFormat1::Builder::SubReadyToSerialize() { + if (!offset_array_.empty()) { + return true; + } + return false; +} + +int32_t IndexSubTableFormat1::Builder::SubSerialize( + WritableFontData* new_data) { + int32_t size = SerializeIndexSubHeader(new_data); + if (!model_changed()) { + if (InternalReadData() == NULL) { + return size; + } + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( + EblcTable::Offset::kIndexSubTable1_offsetArray))); + target.Attach(down_cast<WritableFontData*>(new_data->Slice( + EblcTable::Offset::kIndexSubTable1_offsetArray))); + size += source->CopyTo(target); + } else { + for (std::vector<int32_t>::iterator b = GetOffsetArray()->begin(), + e = GetOffsetArray()->end(); b != e; b++) { + size += new_data->WriteLong(size, *b); + } + } + return size; +} + +std::vector<int32_t>* IndexSubTableFormat1::Builder::OffsetArray() { + return GetOffsetArray(); +} + +void IndexSubTableFormat1::Builder::SetOffsetArray( + const std::vector<int32_t>& offset_array) { + offset_array_.clear(); + offset_array_ = offset_array; + set_model_changed(); +} + +void IndexSubTableFormat1::Builder::Revert() { + offset_array_.clear(); + IndexSubTable::Builder::Revert(); +} + +IndexSubTableFormat1::Builder::Builder() + : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable1_builderDataSize, + IndexSubTable::Format::FORMAT_1) { +} + +IndexSubTableFormat1::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IndexSubTableFormat1::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +std::vector<int32_t>* IndexSubTableFormat1::Builder::GetOffsetArray() { + if (offset_array_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &offset_array_; +} + +void IndexSubTableFormat1::Builder::Initialize(ReadableFontData* data) { + offset_array_.clear(); + if (data) { + int32_t num_offsets = (last_glyph_index() - first_glyph_index() + 1) + 1; + for (int32_t i = 0; i < num_offsets; ++i) { + offset_array_.push_back(data->ReadULongAsInt( + EblcTable::Offset::kIndexSubTable1_offsetArray + + i * DataSize::kULONG)); + } + } +} + +// static +int32_t IndexSubTableFormat1::Builder::DataLength( + ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + UNREFERENCED_PARAMETER(data); + UNREFERENCED_PARAMETER(index_sub_table_offset); + return EblcTable::Offset::kIndexSubHeaderLength + + (last_glyph_index - first_glyph_index + 1 + 1) * DataSize::kULONG; +} + +/****************************************************************************** + * IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + IndexSubTableFormat1::Builder* container) + : RefIterator<BitmapGlyphInfo, IndexSubTableFormat1::Builder, + IndexSubTable::Builder>(container) { + glyph_id_ = container->first_glyph_index(); +} + +bool IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::HasNext() { + if (glyph_id_ <= container()->last_glyph_index()) { + return true; + } + return false; +} + +CALLER_ATTACH BitmapGlyphInfo* +IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::Next() { + BitmapGlyphInfoPtr output; + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + output = new BitmapGlyphInfo(glyph_id_, + container()->image_data_offset(), + container()->GlyphStartOffset(glyph_id_), + container()->GlyphLength(glyph_id_), + container()->image_format()); + glyph_id_++; + return output.Detach(); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format1.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format1.h new file mode 100644 index 0000000000..58a6ce75c3 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format1.h @@ -0,0 +1,116 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_ + +#include "sfntly/port/java_iterator.h" +#include "sfntly/table/bitmap/index_sub_table.h" + +namespace sfntly { +// Format 1 Index Subtable Entry. +class IndexSubTableFormat1 : public IndexSubTable, + public RefCounted<IndexSubTableFormat1> { + public: + class Builder : public IndexSubTable::Builder, + public RefCounted<Builder> { + public: + class BitmapGlyphInfoIterator + : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + int32_t glyph_id_; + }; + + virtual ~Builder(); + virtual int32_t NumGlyphs(); + virtual int32_t GlyphLength(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + std::vector<int32_t>* OffsetArray(); + void SetOffsetArray(const std::vector<int32_t>& offset_array); + CALLER_ATTACH BitmapGlyphInfoIter* Iterator(); + + static CALLER_ATTACH Builder* CreateBuilder(); + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + protected: + void Revert(); + + private: + Builder(); + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + std::vector<int32_t>* GetOffsetArray(); + void Initialize(ReadableFontData* data); + + static int32_t DataLength(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + std::vector<int32_t> offset_array_; + }; + + virtual ~IndexSubTableFormat1(); + + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + + static int32_t GetDataLength(ReadableFontData* data, + int32_t offset, + int32_t first, + int32_t last); + + private: + IndexSubTableFormat1(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + int32_t Loca(int32_t loca_index); + + friend class Builder; +}; +typedef Ptr<IndexSubTableFormat1> IndexSubTableFormat1Ptr; +typedef Ptr<IndexSubTableFormat1::Builder> IndexSubTableFormat1BuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format2.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format2.cc new file mode 100644 index 0000000000..ce73e9beec --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format2.cc @@ -0,0 +1,275 @@ +/* + * 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 "sfntly/table/bitmap/index_sub_table_format2.h" + +#include "sfntly/table/bitmap/eblc_table.h" + +namespace sfntly { +/****************************************************************************** + * IndexSubTableFormat2 class + ******************************************************************************/ +IndexSubTableFormat2::~IndexSubTableFormat2() { +} + +int32_t IndexSubTableFormat2::ImageSize() { + return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable2_imageSize); +} + +CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat2::BigMetrics() { + ReadableFontDataPtr slice; + slice.Attach(down_cast<ReadableFontData*>( + data_->Slice(EblcTable::Offset::kIndexSubTable2_bigGlyphMetrics, + BigGlyphMetrics::Offset::kMetricsLength))); + BigGlyphMetricsPtr output = new BigGlyphMetrics(slice); + return output.Detach(); +} + +int32_t IndexSubTableFormat2::NumGlyphs() { + return last_glyph_index() - first_glyph_index() + 1; +} + +int32_t IndexSubTableFormat2::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + return loca * image_size_; +} + +int32_t IndexSubTableFormat2::GlyphLength(int32_t glyph_id) { + if (CheckGlyphRange(glyph_id) == -1) { + return 0; + } + return image_size_; +} + +IndexSubTableFormat2::IndexSubTableFormat2(ReadableFontData* data, + int32_t first, + int32_t last) + : IndexSubTable(data, first, last) { + image_size_ = + data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable2_imageSize); +} + +/****************************************************************************** + * IndexSubTableFormat2::Builder class + ******************************************************************************/ +IndexSubTableFormat2::Builder::~Builder() { +} + +int32_t IndexSubTableFormat2::Builder::NumGlyphs() { + return last_glyph_index() - first_glyph_index() + 1; +} + +int32_t IndexSubTableFormat2::Builder::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + return loca * ImageSize(); +} + +int32_t IndexSubTableFormat2::Builder::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return 0; + } + return ImageSize(); +} + +CALLER_ATTACH IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* + IndexSubTableFormat2::Builder::GetIterator() { + Ptr<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator> it = + new IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator(this); + return it.Detach(); +} + +int32_t IndexSubTableFormat2::Builder::ImageSize() { + return InternalReadData()->ReadULongAsInt( + EblcTable::Offset::kIndexSubTable2_imageSize); +} + +void IndexSubTableFormat2::Builder::SetImageSize(int32_t image_size) { + InternalWriteData()->WriteULong(EblcTable::Offset::kIndexSubTable2_imageSize, + image_size); +} + +BigGlyphMetrics::Builder* IndexSubTableFormat2::Builder::BigMetrics() { + if (metrics_ == NULL) { + WritableFontDataPtr data; + data.Attach(down_cast<WritableFontData*>(InternalWriteData()->Slice( + EblcTable::Offset::kIndexSubTable2_bigGlyphMetrics, + BigGlyphMetrics::Offset::kMetricsLength))); + metrics_ = new BigGlyphMetrics::Builder(data); + } + return metrics_; +} + +// static +CALLER_ATTACH IndexSubTableFormat2::Builder* +IndexSubTableFormat2::Builder::CreateBuilder() { + IndexSubTableFormat2BuilderPtr output = new IndexSubTableFormat2::Builder(); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat2::Builder* +IndexSubTableFormat2::Builder::CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + ReadableFontDataPtr new_data; + new_data.Attach(down_cast<ReadableFontData*>( + data->Slice(index_sub_table_offset, length))); + if (new_data == NULL) { + return NULL; + } + IndexSubTableFormat2BuilderPtr output = + new IndexSubTableFormat2::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat2::Builder* +IndexSubTableFormat2::Builder::CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + WritableFontDataPtr new_data; + new_data.Attach(down_cast<WritableFontData*>( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat2BuilderPtr output = + new IndexSubTableFormat2::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +CALLER_ATTACH FontDataTable* IndexSubTableFormat2::Builder::SubBuildTable( + ReadableFontData* data) { + IndexSubTableFormat2Ptr output = new IndexSubTableFormat2( + data, first_glyph_index(), last_glyph_index()); + return output.Detach(); +} + +void IndexSubTableFormat2::Builder::SubDataSet() { + Revert(); +} + +int32_t IndexSubTableFormat2::Builder::SubDataSizeToSerialize() { + return EblcTable::Offset::kIndexSubTable2Length; +} + +bool IndexSubTableFormat2::Builder::SubReadyToSerialize() { + return true; +} + +int32_t IndexSubTableFormat2::Builder::SubSerialize( + WritableFontData* new_data) { + int32_t size = SerializeIndexSubHeader(new_data); + if (metrics_ == NULL) { + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast<ReadableFontData*>( + InternalReadData()->Slice(size))); + target.Attach(down_cast<WritableFontData*>(new_data->Slice(size))); + size += source->CopyTo(target); + } else { + WritableFontDataPtr slice; + size += new_data->WriteLong(EblcTable::Offset::kIndexSubTable2_imageSize, + ImageSize()); + slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size))); + size += metrics_->SubSerialize(slice); + } + return size; +} + +IndexSubTableFormat2::Builder::Builder() + : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable3_builderDataSize, + IndexSubTable::Format::FORMAT_2) { + metrics_.Attach(BigGlyphMetrics::Builder::CreateBuilder()); +} + +IndexSubTableFormat2::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IndexSubTableFormat2::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +// static +int32_t IndexSubTableFormat2::Builder::DataLength( + ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + UNREFERENCED_PARAMETER(data); + UNREFERENCED_PARAMETER(index_sub_table_offset); + UNREFERENCED_PARAMETER(first_glyph_index); + UNREFERENCED_PARAMETER(last_glyph_index); + return EblcTable::Offset::kIndexSubTable2Length; +} + +/****************************************************************************** + * IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + IndexSubTableFormat2::Builder* container) + : RefIterator<BitmapGlyphInfo, IndexSubTableFormat2::Builder, + IndexSubTable::Builder>(container) { + glyph_id_ = container->first_glyph_index(); +} + +bool IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::HasNext() { + if (glyph_id_ <= container()->last_glyph_index()) { + return true; + } + return false; +} + +CALLER_ATTACH BitmapGlyphInfo* +IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::Next() { + BitmapGlyphInfoPtr output; + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + output = new BitmapGlyphInfo(glyph_id_, + container()->image_data_offset(), + container()->GlyphStartOffset(glyph_id_), + container()->GlyphLength(glyph_id_), + container()->image_format()); + glyph_id_++; + return output.Detach(); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format2.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format2.h new file mode 100644 index 0000000000..784e8a39fe --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format2.h @@ -0,0 +1,106 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT2_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT2_H_ + +#include "sfntly/table/bitmap/index_sub_table.h" +#include "sfntly/table/bitmap/big_glyph_metrics.h" + +namespace sfntly { +// Format 2 Index Subtable Entry. +class IndexSubTableFormat2 : public IndexSubTable, + public RefCounted<IndexSubTableFormat2> { + public: + class Builder : public IndexSubTable::Builder, + public RefCounted<Builder> { + public: + class BitmapGlyphInfoIterator + : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + int32_t glyph_id_; + }; + + virtual ~Builder(); + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + int32_t ImageSize(); + void SetImageSize(int32_t image_size); + BigGlyphMetrics::Builder* BigMetrics(); + + static CALLER_ATTACH Builder* CreateBuilder(); + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + private: + Builder(); + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + + static int32_t DataLength(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + BigGlyphMetricsBuilderPtr metrics_; + }; + + virtual ~IndexSubTableFormat2(); + + int32_t ImageSize(); + CALLER_ATTACH BigGlyphMetrics* BigMetrics(); + + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + + private: + IndexSubTableFormat2(ReadableFontData* data, int32_t first, int32_t last); + + int32_t image_size_; + friend class Builder; +}; +typedef Ptr<IndexSubTableFormat2> IndexSubTableFormat2Ptr; +typedef Ptr<IndexSubTableFormat2::Builder> IndexSubTableFormat2BuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format3.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format3.cc new file mode 100644 index 0000000000..abd5517849 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format3.cc @@ -0,0 +1,298 @@ +/* + * 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 "sfntly/table/bitmap/index_sub_table_format3.h" + +#include "sfntly/table/bitmap/eblc_table.h" + +namespace sfntly { +/****************************************************************************** + * IndexSubTableFormat3 class + ******************************************************************************/ +IndexSubTableFormat3::~IndexSubTableFormat3() { +} + +int32_t IndexSubTableFormat3::NumGlyphs() { + return last_glyph_index() - first_glyph_index() + 1; +} + +int32_t IndexSubTableFormat3::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca != -1) { + return Loca(loca); + } + return -1; +} + +int32_t IndexSubTableFormat3::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca != -1) { + return Loca(glyph_id + 1) - Loca(glyph_id); + } + return 0; +} + +// static +int32_t IndexSubTableFormat3::GetDataLength(ReadableFontData* data, + int32_t offset, + int32_t first, + int32_t last) { + UNREFERENCED_PARAMETER(data); + UNREFERENCED_PARAMETER(offset); + return (last - first + 1 + 1) * DataSize::kUSHORT; +} + +IndexSubTableFormat3::IndexSubTableFormat3(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable(data, first_glyph_index, last_glyph_index) { +} + +int32_t IndexSubTableFormat3::Loca(int32_t loca) { + int32_t read_offset = + data_->ReadUShort(EblcTable::Offset::kIndexSubTable3_offsetArray + + loca * DataSize::kUSHORT); + return read_offset; +} + +/****************************************************************************** + * IndexSubTableFormat3::Builder class + ******************************************************************************/ +IndexSubTableFormat3::Builder::~Builder() { +} + +int32_t IndexSubTableFormat3::Builder::NumGlyphs() { + return GetOffsetArray()->size() - 1; +} + +int32_t IndexSubTableFormat3::Builder::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + return GetOffsetArray()->at(loca); +} + +int32_t IndexSubTableFormat3::Builder::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return 0; + } + std::vector<int32_t>* offset_array = GetOffsetArray(); + return offset_array->at(loca + 1) - offset_array->at(loca); +} + +CALLER_ATTACH IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* + IndexSubTableFormat3::Builder::GetIterator() { + Ptr<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator> it = + new IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator(this); + return it.Detach(); +} + +void IndexSubTableFormat3::Builder::Revert() { + offset_array_.clear(); + IndexSubTable::Builder::Revert(); +} + +void IndexSubTableFormat3::Builder::SetOffsetArray( + const std::vector<int32_t>& offset_array) { + offset_array_.clear(); + offset_array_ = offset_array; + set_model_changed(); +} + +// static +CALLER_ATTACH IndexSubTableFormat3::Builder* +IndexSubTableFormat3::Builder::CreateBuilder() { + IndexSubTableFormat3BuilderPtr output = new IndexSubTableFormat3::Builder(); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat3::Builder* +IndexSubTableFormat3::Builder::CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + ReadableFontDataPtr new_data; + new_data.Attach(down_cast<ReadableFontData*>( + data->Slice(index_sub_table_offset, length))); + if (new_data == NULL) { + return NULL; + } + IndexSubTableFormat3BuilderPtr output = + new IndexSubTableFormat3::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat3::Builder* +IndexSubTableFormat3::Builder::CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + WritableFontDataPtr new_data; + new_data.Attach(down_cast<WritableFontData*>( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat3BuilderPtr output = + new IndexSubTableFormat3::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +CALLER_ATTACH FontDataTable* IndexSubTableFormat3::Builder::SubBuildTable( + ReadableFontData* data) { + IndexSubTableFormat3Ptr output = new IndexSubTableFormat3( + data, first_glyph_index(), last_glyph_index()); + return output.Detach(); +} + +void IndexSubTableFormat3::Builder::SubDataSet() { + Revert(); +} + +int32_t IndexSubTableFormat3::Builder::SubDataSizeToSerialize() { + if (offset_array_.empty()) { + return InternalReadData()->Length(); + } + return EblcTable::Offset::kIndexSubHeaderLength + + offset_array_.size() * DataSize::kULONG; +} + +bool IndexSubTableFormat3::Builder::SubReadyToSerialize() { + if (!offset_array_.empty()) { + return true; + } + return false; +} + +int32_t IndexSubTableFormat3::Builder::SubSerialize( + WritableFontData* new_data) { + int32_t size = SerializeIndexSubHeader(new_data); + if (!model_changed()) { + if (InternalReadData() == NULL) { + return size; + } + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( + EblcTable::Offset::kIndexSubTable3_offsetArray))); + target.Attach(down_cast<WritableFontData*>(new_data->Slice( + EblcTable::Offset::kIndexSubTable3_offsetArray))); + size += source->CopyTo(target); + } else { + for (std::vector<int32_t>::iterator b = GetOffsetArray()->begin(), + e = GetOffsetArray()->end(); b != e; b++) { + size += new_data->WriteUShort(size, *b); + } + } + return size; +} + +IndexSubTableFormat3::Builder::Builder() + : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable3_builderDataSize, + IndexSubTable::Format::FORMAT_3) { +} + +IndexSubTableFormat3::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IndexSubTableFormat3::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +std::vector<int32_t>* IndexSubTableFormat3::Builder::GetOffsetArray() { + if (offset_array_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &offset_array_; +} + +void IndexSubTableFormat3::Builder::Initialize(ReadableFontData* data) { + offset_array_.clear(); + if (data) { + int32_t num_offsets = (last_glyph_index() - first_glyph_index() + 1) + 1; + for (int32_t i = 0; i < num_offsets; ++i) { + offset_array_.push_back(data->ReadUShort( + EblcTable::Offset::kIndexSubTable3_offsetArray + + i * DataSize::kUSHORT)); + } + } +} + +// static +int32_t IndexSubTableFormat3::Builder::DataLength( + ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + UNREFERENCED_PARAMETER(data); + UNREFERENCED_PARAMETER(index_sub_table_offset); + return EblcTable::Offset::kIndexSubHeaderLength + + (last_glyph_index - first_glyph_index + 1 + 1) * DataSize::kUSHORT; +} + +/****************************************************************************** + * IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + IndexSubTableFormat3::Builder* container) + : RefIterator<BitmapGlyphInfo, IndexSubTableFormat3::Builder, + IndexSubTable::Builder>(container) { + glyph_id_ = container->first_glyph_index(); +} + +bool IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::HasNext() { + if (glyph_id_ <= container()->last_glyph_index()) { + return true; + } + return false; +} + +CALLER_ATTACH BitmapGlyphInfo* +IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::Next() { + BitmapGlyphInfoPtr output; + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + output = new BitmapGlyphInfo(glyph_id_, + container()->image_data_offset(), + container()->GlyphStartOffset(glyph_id_), + container()->GlyphLength(glyph_id_), + container()->image_format()); + glyph_id_++; + return output.Detach(); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format3.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format3.h new file mode 100644 index 0000000000..1f2f0aa662 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format3.h @@ -0,0 +1,113 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT3_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT3_H_ + +#include "sfntly/table/bitmap/index_sub_table.h" + +namespace sfntly { +// Format 3 Index Subtable Entry. +class IndexSubTableFormat3 : public IndexSubTable, + public RefCounted<IndexSubTableFormat3> { + public: + class Builder : public IndexSubTable::Builder, + public RefCounted<Builder> { + public: + class BitmapGlyphInfoIterator + : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + int32_t glyph_id_; + }; + + virtual ~Builder(); + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + void SetOffsetArray(const std::vector<int32_t>& offset_array); + + static CALLER_ATTACH Builder* CreateBuilder(); + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + protected: + void Revert(); + + private: + Builder(); + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + std::vector<int32_t>* GetOffsetArray(); + void Initialize(ReadableFontData* data); + + static int32_t DataLength(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + std::vector<int32_t> offset_array_; + }; + + virtual ~IndexSubTableFormat3(); + + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + + static int32_t GetDataLength(ReadableFontData* data, + int32_t offset, + int32_t first, + int32_t last); + + private: + IndexSubTableFormat3(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + int32_t Loca(int32_t loca_index); + + friend class Builder; +}; +typedef Ptr<IndexSubTableFormat3> IndexSubTableFormat3Ptr; +typedef Ptr<IndexSubTableFormat3::Builder> IndexSubTableFormat3BuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT3_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format4.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format4.cc new file mode 100644 index 0000000000..5baa2a5e86 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format4.cc @@ -0,0 +1,384 @@ +/* + * 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 "sfntly/table/bitmap/index_sub_table_format4.h" + +#include "sfntly/table/bitmap/eblc_table.h" + +namespace sfntly { +/****************************************************************************** + * IndexSubTableFormat4 class + ******************************************************************************/ +IndexSubTableFormat4::~IndexSubTableFormat4() { +} + +int32_t IndexSubTableFormat4::NumGlyphs() { + return IndexSubTableFormat4::NumGlyphs(data_, 0); +} + +int32_t IndexSubTableFormat4::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + int32_t pair_index = FindCodeOffsetPair(glyph_id); + if (pair_index < 0) { + return -1; + } + return data_->ReadUShort(EblcTable::Offset::kIndexSubTable4_glyphArray + + pair_index * + EblcTable::Offset::kCodeOffsetPairLength + + EblcTable::Offset::kCodeOffsetPair_offset); +} + +int32_t IndexSubTableFormat4::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + + int32_t pair_index = FindCodeOffsetPair(glyph_id); + if (pair_index < 0) { + return -1; + } + return data_->ReadUShort( + EblcTable::Offset::kIndexSubTable4_glyphArray + + (pair_index + 1) * EblcTable::Offset::kCodeOffsetPairLength + + EblcTable::Offset::kCodeOffsetPair_offset) - + data_->ReadUShort( + EblcTable::Offset::kIndexSubTable4_glyphArray + + (pair_index) * EblcTable::Offset::kCodeOffsetPairLength + + EblcTable::Offset::kCodeOffsetPair_offset); +} + +IndexSubTableFormat4::IndexSubTableFormat4(ReadableFontData* data, + int32_t first, + int32_t last) + : IndexSubTable(data, first, last) { +} + +int32_t IndexSubTableFormat4::FindCodeOffsetPair(int32_t glyph_id) { + return data_->SearchUShort(EblcTable::Offset::kIndexSubTable4_glyphArray, + EblcTable::Offset::kCodeOffsetPairLength, + NumGlyphs(), + glyph_id); +} + +int32_t IndexSubTableFormat4::NumGlyphs(ReadableFontData* data, + int32_t table_offset) { + int32_t num_glyphs = data->ReadULongAsInt(table_offset + + EblcTable::Offset::kIndexSubTable4_numGlyphs); + return num_glyphs; +} + +/****************************************************************************** + * IndexSubTableFormat4::CodeOffsetPair related class + ******************************************************************************/ +IndexSubTableFormat4::CodeOffsetPair::CodeOffsetPair(int32_t glyph_code, + int32_t offset) + : glyph_code_(glyph_code), offset_(offset) { +} + +IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder() + : CodeOffsetPair(0, 0) { +} + +IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder( + int32_t glyph_code, int32_t offset) + : CodeOffsetPair(glyph_code, offset) { +} + +bool IndexSubTableFormat4::CodeOffsetPairGlyphCodeComparator::operator()( + const CodeOffsetPair& lhs, const CodeOffsetPair& rhs) { + return lhs.glyph_code() < rhs.glyph_code(); +} + +/****************************************************************************** + * IndexSubTableFormat4::Builder class + ******************************************************************************/ +IndexSubTableFormat4::Builder::~Builder() { +} + +int32_t IndexSubTableFormat4::Builder::NumGlyphs() { + return GetOffsetArray()->size() - 1; +} + +int32_t IndexSubTableFormat4::Builder::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return 0; + } + int32_t pair_index = FindCodeOffsetPair(glyph_id); + if (pair_index == -1) { + return 0; + } + return GetOffsetArray()->at(pair_index + 1).offset() - + GetOffsetArray()->at(pair_index).offset(); +} + +int32_t IndexSubTableFormat4::Builder::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + int32_t pair_index = FindCodeOffsetPair(glyph_id); + if (pair_index == -1) { + return -1; + } + return GetOffsetArray()->at(pair_index).offset(); +} + +CALLER_ATTACH IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* + IndexSubTableFormat4::Builder::GetIterator() { + Ptr<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator> it = + new IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator(this); + return it.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat4::Builder* +IndexSubTableFormat4::Builder::CreateBuilder() { + IndexSubTableFormat4BuilderPtr output = new IndexSubTableFormat4::Builder(); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat4::Builder* +IndexSubTableFormat4::Builder::CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + ReadableFontDataPtr new_data; + new_data.Attach(down_cast<ReadableFontData*>( + data->Slice(index_sub_table_offset, length))); + if (new_data == NULL) { + return NULL; + } + IndexSubTableFormat4BuilderPtr output = + new IndexSubTableFormat4::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat4::Builder* +IndexSubTableFormat4::Builder::CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + WritableFontDataPtr new_data; + new_data.Attach(down_cast<WritableFontData*>( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat4BuilderPtr output = + new IndexSubTableFormat4::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +CALLER_ATTACH FontDataTable* IndexSubTableFormat4::Builder::SubBuildTable( + ReadableFontData* data) { + IndexSubTableFormat4Ptr output = new IndexSubTableFormat4( + data, first_glyph_index(), last_glyph_index()); + return output.Detach(); +} + +void IndexSubTableFormat4::Builder::SubDataSet() { + Revert(); +} + +int32_t IndexSubTableFormat4::Builder::SubDataSizeToSerialize() { + if (offset_pair_array_.empty()) { + return InternalReadData()->Length(); + } + return EblcTable::Offset::kIndexSubHeaderLength + DataSize::kULONG + + GetOffsetArray()->size() * + EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength; +} + +bool IndexSubTableFormat4::Builder::SubReadyToSerialize() { + if (!offset_pair_array_.empty()) { + return true; + } + return false; +} + +int32_t IndexSubTableFormat4::Builder::SubSerialize( + WritableFontData* new_data) { + int32_t size = SerializeIndexSubHeader(new_data); + if (!model_changed()) { + if (InternalReadData() == NULL) { + return size; + } + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( + EblcTable::Offset::kIndexSubTable4_glyphArray))); + target.Attach(down_cast<WritableFontData*>(new_data->Slice( + EblcTable::Offset::kIndexSubTable4_glyphArray))); + size += source->CopyTo(target); + } else { + size += new_data->WriteLong(size, offset_pair_array_.size() - 1); + for (std::vector<CodeOffsetPairBuilder>::iterator + b = GetOffsetArray()->begin(), e = GetOffsetArray()->end(); + b != e; b++) { + size += new_data->WriteUShort(size, b->glyph_code()); + size += new_data->WriteUShort(size, b->offset()); + } + } + return size; +} + +void IndexSubTableFormat4::Builder::Revert() { + offset_pair_array_.clear(); + IndexSubTable::Builder::Revert(); +} + +void IndexSubTableFormat4::Builder::SetOffsetArray( + const std::vector<CodeOffsetPairBuilder>& pair_array) { + offset_pair_array_.clear(); + offset_pair_array_ = pair_array; + set_model_changed(); +} + +IndexSubTableFormat4::Builder::Builder() + : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable4_builderDataSize, + Format::FORMAT_4) { +} + +IndexSubTableFormat4::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IndexSubTableFormat4::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +std::vector<IndexSubTableFormat4::CodeOffsetPairBuilder>* +IndexSubTableFormat4::Builder::GetOffsetArray() { + if (offset_pair_array_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &offset_pair_array_; +} + +void IndexSubTableFormat4::Builder::Initialize(ReadableFontData* data) { + offset_pair_array_.clear(); + if (data) { + int32_t num_pairs = IndexSubTableFormat4::NumGlyphs(data, 0) + 1; + int32_t offset = EblcTable::Offset::kIndexSubTable4_glyphArray; + for (int32_t i = 0; i < num_pairs; ++i) { + int32_t glyph_code = data->ReadUShort(offset + + EblcTable::Offset::kIndexSubTable4_codeOffsetPair_glyphCode); + int32_t glyph_offset = data->ReadUShort(offset + + EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset); + offset += EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength; + CodeOffsetPairBuilder pair_builder(glyph_code, glyph_offset); + offset_pair_array_.push_back(pair_builder); + } + } +} + +int32_t IndexSubTableFormat4::Builder::FindCodeOffsetPair(int32_t glyph_id) { + std::vector<CodeOffsetPairBuilder>* pair_list = GetOffsetArray(); + int32_t location = 0; + int32_t bottom = 0; + int32_t top = pair_list->size(); + while (top != bottom) { + location = (top + bottom) / 2; + CodeOffsetPairBuilder* pair = &(pair_list->at(location)); + if (glyph_id < pair->glyph_code()) { + // location is below current location + top = location; + } else if (glyph_id > pair->glyph_code()) { + // location is above current location + bottom = location + 1; + } else { + return location; + } + } + return -1; +} + +// static +int32_t IndexSubTableFormat4::Builder::DataLength( + ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t num_glyphs = IndexSubTableFormat4::NumGlyphs(data, + index_sub_table_offset); + UNREFERENCED_PARAMETER(first_glyph_index); + UNREFERENCED_PARAMETER(last_glyph_index); + return EblcTable::Offset::kIndexSubTable4_glyphArray + + num_glyphs * EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset; +} + + +/****************************************************************************** + * IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + IndexSubTableFormat4::Builder* container) + : RefIterator<BitmapGlyphInfo, IndexSubTableFormat4::Builder, + IndexSubTable::Builder>(container), + code_offset_pair_index_(0) { +} + +bool IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::HasNext() { + if (code_offset_pair_index_ < + (int32_t)(container()->GetOffsetArray()->size() - 1)) { + return true; + } + return false; +} + +CALLER_ATTACH BitmapGlyphInfo* +IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::Next() { + BitmapGlyphInfoPtr output; + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + std::vector<CodeOffsetPairBuilder>* offset_array = + container()->GetOffsetArray(); + int32_t offset = offset_array->at(code_offset_pair_index_).offset(); + int32_t next_offset = offset_array->at(code_offset_pair_index_ + 1).offset(); + int32_t glyph_code = offset_array->at(code_offset_pair_index_).glyph_code(); + output = new BitmapGlyphInfo(glyph_code, + container()->image_data_offset(), + offset, + next_offset - offset, + container()->image_format()); + code_offset_pair_index_++; + return output.Detach(); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format4.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format4.h new file mode 100644 index 0000000000..efd540f178 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format4.h @@ -0,0 +1,135 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT4_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT4_H_ + +#include "sfntly/table/bitmap/index_sub_table.h" + +namespace sfntly { + +class IndexSubTableFormat4 : public IndexSubTable, + public RefCounted<IndexSubTableFormat4> { + public: + class CodeOffsetPair { + public: + int32_t glyph_code() const { return glyph_code_; } + int32_t offset() const { return offset_; } + + protected: + CodeOffsetPair(int32_t glyph_code, int32_t offset); + + // TODO(arthurhsu): C++ style guide prohibits protected members. + int32_t glyph_code_; + int32_t offset_; + }; + + class CodeOffsetPairBuilder : public CodeOffsetPair { + public: + CodeOffsetPairBuilder(); + CodeOffsetPairBuilder(int32_t glyph_code, int32_t offset); + void set_glyph_code(int32_t v) { glyph_code_ = v; } + void set_offset(int32_t v) { offset_ = v; } + }; + + class CodeOffsetPairGlyphCodeComparator { + public: + bool operator()(const CodeOffsetPair& lhs, const CodeOffsetPair& rhs); + }; + + class Builder : public IndexSubTable::Builder, + public RefCounted<Builder> { + public: + class BitmapGlyphInfoIterator + : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + int32_t code_offset_pair_index_; + }; + + virtual ~Builder(); + virtual int32_t NumGlyphs(); + virtual int32_t GlyphLength(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + void Revert(); + void SetOffsetArray(const std::vector<CodeOffsetPairBuilder>& pair_array); + + static CALLER_ATTACH Builder* CreateBuilder(); + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + private: + Builder(); + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + std::vector<CodeOffsetPairBuilder>* GetOffsetArray(); + void Initialize(ReadableFontData* data); + int32_t FindCodeOffsetPair(int32_t glyph_id); + + static int32_t DataLength(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + std::vector<CodeOffsetPairBuilder> offset_pair_array_; + }; + + virtual ~IndexSubTableFormat4(); + + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + + private: + IndexSubTableFormat4(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + + int32_t FindCodeOffsetPair(int32_t glyph_id); + static int32_t NumGlyphs(ReadableFontData* data, int32_t table_offset); + + friend class Builder; +}; +typedef Ptr<IndexSubTableFormat4> IndexSubTableFormat4Ptr; +typedef Ptr<IndexSubTableFormat4::Builder> IndexSubTableFormat4BuilderPtr; +typedef std::vector<IndexSubTableFormat4::CodeOffsetPairBuilder> + CodeOffsetPairBuilderList; +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT4_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format5.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format5.cc new file mode 100644 index 0000000000..b1f773a3e5 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format5.cc @@ -0,0 +1,347 @@ +/* + * 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 "sfntly/table/bitmap/index_sub_table_format5.h" + +#include <algorithm> + +#include "sfntly/table/bitmap/eblc_table.h" + +namespace sfntly { +/****************************************************************************** + * IndexSubTableFormat5 class + ******************************************************************************/ +IndexSubTableFormat5::~IndexSubTableFormat5() { +} + +int32_t IndexSubTableFormat5::NumGlyphs() { + return NumGlyphs(data_, 0); +} + +int32_t IndexSubTableFormat5::GlyphStartOffset(int32_t glyph_id) { + int32_t check = CheckGlyphRange(glyph_id); + if (check == -1) { + return -1; + } + int32_t loca = ReadFontData()->SearchUShort( + EblcTable::Offset::kIndexSubTable5_glyphArray, + DataSize::kUSHORT, + NumGlyphs(), + glyph_id); + if (loca == -1) { + return loca; + } + return loca * ImageSize(); +} + +int32_t IndexSubTableFormat5::GlyphLength(int32_t glyph_id) { + int32_t check = CheckGlyphRange(glyph_id); + if (check == -1) { + return 0; + } + return image_size_; +} + +int32_t IndexSubTableFormat5::ImageSize() { + return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable5_imageSize); +} + +CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat5::BigMetrics() { + ReadableFontDataPtr data; + data.Attach(down_cast<ReadableFontData*>(data_->Slice( + EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics, + BigGlyphMetrics::Offset::kMetricsLength))); + BigGlyphMetricsPtr output = new BigGlyphMetrics(data); + return output.Detach(); +} + +IndexSubTableFormat5::IndexSubTableFormat5(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable(data, first_glyph_index, last_glyph_index) { + image_size_ = data_->ReadULongAsInt( + EblcTable::Offset::kIndexSubTable5_imageSize); +} + +// static +int32_t IndexSubTableFormat5::NumGlyphs(ReadableFontData* data, + int32_t table_offset) { + int32_t num_glyphs = data->ReadULongAsInt(table_offset + + EblcTable::Offset::kIndexSubTable5_numGlyphs); + return num_glyphs; +} + +/****************************************************************************** + * IndexSubTableFormat5::Builder class + ******************************************************************************/ +IndexSubTableFormat5::Builder::~Builder() { +} + +int32_t IndexSubTableFormat5::Builder::NumGlyphs() { + return GetGlyphArray()->size(); +} + +int32_t IndexSubTableFormat5::Builder::GlyphLength(int32_t glyph_id) { + UNREFERENCED_PARAMETER(glyph_id); + return ImageSize(); +} + +int32_t IndexSubTableFormat5::Builder::GlyphStartOffset(int32_t glyph_id) { + int32_t check = CheckGlyphRange(glyph_id); + if (check == -1) { + return -1; + } + std::vector<int32_t>* glyph_array = GetGlyphArray(); + std::vector<int32_t>::iterator it = std::find(glyph_array->begin(), + glyph_array->end(), + glyph_id); + if (it == glyph_array->end()) { + return -1; + } + return (it - glyph_array->begin()) * ImageSize(); +} + +CALLER_ATTACH IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* + IndexSubTableFormat5::Builder::GetIterator() { + Ptr<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator> it = + new IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator(this); + return it.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat5::Builder* +IndexSubTableFormat5::Builder::CreateBuilder() { + IndexSubTableFormat5BuilderPtr output = new IndexSubTableFormat5::Builder(); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat5::Builder* +IndexSubTableFormat5::Builder::CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + ReadableFontDataPtr new_data; + new_data.Attach(down_cast<ReadableFontData*>( + data->Slice(index_sub_table_offset, length))); + if (new_data == NULL) { + return NULL; + } + IndexSubTableFormat5BuilderPtr output = + new IndexSubTableFormat5::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat5::Builder* +IndexSubTableFormat5::Builder::CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + WritableFontDataPtr new_data; + new_data.Attach(down_cast<WritableFontData*>( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat5BuilderPtr output = + new IndexSubTableFormat5::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +CALLER_ATTACH FontDataTable* IndexSubTableFormat5::Builder::SubBuildTable( + ReadableFontData* data) { + IndexSubTableFormat5Ptr output = new IndexSubTableFormat5( + data, first_glyph_index(), last_glyph_index()); + return output.Detach(); +} + +void IndexSubTableFormat5::Builder::SubDataSet() { + Revert(); +} + +int32_t IndexSubTableFormat5::Builder::SubDataSizeToSerialize() { + if (glyph_array_.empty()) { + return InternalReadData()->Length(); + } + return EblcTable::Offset::kIndexSubTable5_builderDataSize + + glyph_array_.size() * DataSize::kUSHORT; +} + +bool IndexSubTableFormat5::Builder::SubReadyToSerialize() { + if (!glyph_array_.empty()) { + return true; + } + return false; +} + +int32_t IndexSubTableFormat5::Builder::SubSerialize( + WritableFontData* new_data) { + int32_t size = SerializeIndexSubHeader(new_data); + if (!model_changed()) { + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( + EblcTable::Offset::kIndexSubTable5_imageSize))); + target.Attach(down_cast<WritableFontData*>(new_data->Slice( + EblcTable::Offset::kIndexSubTable5_imageSize))); + size += source->CopyTo(target); + } else { + size += new_data->WriteULong(EblcTable::Offset::kIndexSubTable5_imageSize, + ImageSize()); + WritableFontDataPtr slice; + slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size))); + size += BigMetrics()->SubSerialize(slice); + size += new_data->WriteULong(size, glyph_array_.size()); + for (std::vector<int32_t>::iterator b = glyph_array_.begin(), e = glyph_array_.end(); + b != e; b++) { + size += new_data->WriteUShort(size, *b); + } + } + return size; +} + +int32_t IndexSubTableFormat5::Builder::ImageSize() { + return InternalReadData()->ReadULongAsInt( + EblcTable::Offset::kIndexSubTable5_imageSize); +} + +void IndexSubTableFormat5::Builder::SetImageSize(int32_t image_size) { + InternalWriteData()->WriteULong( + EblcTable::Offset::kIndexSubTable5_imageSize, image_size); +} + +BigGlyphMetrics::Builder* IndexSubTableFormat5::Builder::BigMetrics() { + if (metrics_ == NULL) { + WritableFontDataPtr data; + data.Attach(down_cast<WritableFontData*>(InternalWriteData()->Slice( + EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics, + BigGlyphMetrics::Offset::kMetricsLength))); + metrics_ = new BigGlyphMetrics::Builder(data); + set_model_changed(); + } + return metrics_; +} + +std::vector<int32_t>* IndexSubTableFormat5::Builder::GlyphArray() { + return GetGlyphArray(); +} + +void IndexSubTableFormat5::Builder::SetGlyphArray(const std::vector<int32_t>& v) { + glyph_array_.clear(); + glyph_array_ = v; + set_model_changed(); +} + +void IndexSubTableFormat5::Builder::Revert() { + glyph_array_.clear(); + IndexSubTable::Builder::Revert(); +} + +IndexSubTableFormat5::Builder::Builder() + : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable5_builderDataSize, + IndexSubTable::Format::FORMAT_5) { +} + +IndexSubTableFormat5::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IndexSubTableFormat5::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +std::vector<int32_t>* IndexSubTableFormat5::Builder::GetGlyphArray() { + if (glyph_array_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &glyph_array_; +} + +void IndexSubTableFormat5::Builder::Initialize(ReadableFontData* data) { + glyph_array_.clear(); + if (data) { + int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data, 0); + for (int32_t i = 0; i < num_glyphs; ++i) { + glyph_array_.push_back(data->ReadUShort( + EblcTable::Offset::kIndexSubTable5_glyphArray + + i * DataSize::kUSHORT)); + } + } +} + +// static +int32_t IndexSubTableFormat5::Builder::DataLength( + ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data, + index_sub_table_offset); + UNREFERENCED_PARAMETER(first_glyph_index); + UNREFERENCED_PARAMETER(last_glyph_index); + return EblcTable::Offset::kIndexSubTable5_glyphArray + + num_glyphs * DataSize::kUSHORT; +} + +/****************************************************************************** + * IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + IndexSubTableFormat5::Builder* container) + : RefIterator<BitmapGlyphInfo, IndexSubTableFormat5::Builder, + IndexSubTable::Builder>(container), + offset_index_(0) { +} + +bool IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::HasNext() { + if (offset_index_ < (int32_t)(container()->GetGlyphArray()->size())) { + return true; + } + return false; +} + +CALLER_ATTACH BitmapGlyphInfo* +IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::Next() { + BitmapGlyphInfoPtr output; + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + output = new BitmapGlyphInfo(container()->GetGlyphArray()->at(offset_index_), + container()->image_data_offset(), + offset_index_ * container()->ImageSize(), + container()->ImageSize(), + container()->image_format()); + offset_index_++; + return output.Detach(); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format5.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format5.h new file mode 100644 index 0000000000..b6534e7aeb --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/index_sub_table_format5.h @@ -0,0 +1,118 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_ + +#include "sfntly/table/bitmap/big_glyph_metrics.h" +#include "sfntly/table/bitmap/index_sub_table.h" + +namespace sfntly { + +class IndexSubTableFormat5 : public IndexSubTable, + public RefCounted<IndexSubTableFormat5> { + public: + class Builder : public IndexSubTable::Builder, + public RefCounted<Builder> { + public: + class BitmapGlyphInfoIterator + : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + int32_t offset_index_; + }; + virtual ~Builder(); + virtual int32_t NumGlyphs(); + virtual int32_t GlyphLength(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + int32_t ImageSize(); + void SetImageSize(int32_t image_size); + BigGlyphMetrics::Builder* BigMetrics(); + std::vector<int32_t>* GlyphArray(); + void SetGlyphArray(const std::vector<int32_t>& v); + + static CALLER_ATTACH Builder* CreateBuilder(); + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + protected: + void Revert(); + + private: + Builder(); + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + + std::vector<int32_t>* GetGlyphArray(); + void Initialize(ReadableFontData* data); + + static int32_t DataLength(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + std::vector<int32_t> glyph_array_; + BigGlyphMetricsBuilderPtr metrics_; + }; + virtual ~IndexSubTableFormat5(); + + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + + int32_t ImageSize(); + CALLER_ATTACH BigGlyphMetrics* BigMetrics(); + + private: + IndexSubTableFormat5(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + + static int32_t NumGlyphs(ReadableFontData* dta, int32_t table_offset); + + int32_t image_size_; + + friend class Builder; +}; +typedef Ptr<IndexSubTableFormat5> IndexSubTableFormat5Ptr; +typedef Ptr<IndexSubTableFormat5::Builder> IndexSubTableFormat5BuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.cc new file mode 100644 index 0000000000..87031a142b --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.cc @@ -0,0 +1,45 @@ +/* + * 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 "sfntly/table/bitmap/simple_bitmap_glyph.h" + +namespace sfntly { + +SimpleBitmapGlyph::SimpleBitmapGlyph(ReadableFontData* data, int32_t format) + : BitmapGlyph(data, format) { +} + +SimpleBitmapGlyph::~SimpleBitmapGlyph() { +} + +SimpleBitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format) + : BitmapGlyph::Builder(data, format) { +} + +SimpleBitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format) + : BitmapGlyph::Builder(data, format) { +} + +SimpleBitmapGlyph::Builder::~Builder() { +} + +CALLER_ATTACH FontDataTable* +SimpleBitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) { + Ptr<SimpleBitmapGlyph> glyph = new SimpleBitmapGlyph(data, format()); + return glyph.Detach(); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.h new file mode 100644 index 0000000000..56ede10538 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SIMPLE_BITMAP_GLYPH_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SIMPLE_BITMAP_GLYPH_H_ + +#include "sfntly/table/bitmap/bitmap_glyph.h" + +namespace sfntly { + +class SimpleBitmapGlyph : public BitmapGlyph, + public RefCounted<SimpleBitmapGlyph> { + public: + class Builder : public BitmapGlyph::Builder, + public RefCounted<Builder> { + public: + Builder(WritableFontData* data, int32_t format); + Builder(ReadableFontData* data, int32_t format); + virtual ~Builder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + }; + + SimpleBitmapGlyph(ReadableFontData* data, int32_t format); + virtual ~SimpleBitmapGlyph(); +}; +typedef Ptr<SimpleBitmapGlyph> SimpleBitmapGlyphPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SIMPLE_BITMAP_GLYPH_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/small_glyph_metrics.cc b/gfx/sfntly/cpp/src/sfntly/table/bitmap/small_glyph_metrics.cc new file mode 100644 index 0000000000..24ff624c93 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/small_glyph_metrics.cc @@ -0,0 +1,126 @@ +/* + * 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 "sfntly/table/bitmap/small_glyph_metrics.h" + +namespace sfntly { +/****************************************************************************** + * SmallGlyphMetrics class + ******************************************************************************/ +SmallGlyphMetrics::SmallGlyphMetrics(ReadableFontData* data) + : GlyphMetrics(data) { +} + +SmallGlyphMetrics::~SmallGlyphMetrics() { +} + +int32_t SmallGlyphMetrics::Height() { + return data_->ReadByte(Offset::kHeight); +} + +int32_t SmallGlyphMetrics::Width() { + return data_->ReadByte(Offset::kWidth); +} + +int32_t SmallGlyphMetrics::BearingX() { + return data_->ReadByte(Offset::kBearingX); +} + +int32_t SmallGlyphMetrics::BearingY() { + return data_->ReadByte(Offset::kBearingY); +} + +int32_t SmallGlyphMetrics::Advance() { + return data_->ReadByte(Offset::kAdvance); +} + +/****************************************************************************** + * SmallGlyphMetrics::Builder class + ******************************************************************************/ +SmallGlyphMetrics::Builder::Builder(WritableFontData* data) + : GlyphMetrics::Builder(data) { +} + +SmallGlyphMetrics::Builder::Builder(ReadableFontData* data) + : GlyphMetrics::Builder(data) { +} + +SmallGlyphMetrics::Builder::~Builder() { +} + +int32_t SmallGlyphMetrics::Builder::Height() { + return InternalReadData()->ReadByte(Offset::kHeight); +} + +void SmallGlyphMetrics::Builder::SetHeight(uint8_t height) { + InternalWriteData()->WriteByte(Offset::kHeight, height); +} + +int32_t SmallGlyphMetrics::Builder::Width() { + return InternalReadData()->ReadByte(Offset::kWidth); +} + +void SmallGlyphMetrics::Builder::SetWidth(uint8_t width) { + InternalWriteData()->WriteByte(Offset::kWidth, width); +} + +int32_t SmallGlyphMetrics::Builder::BearingX() { + return InternalReadData()->ReadByte(Offset::kBearingX); +} + +void SmallGlyphMetrics::Builder::SetBearingX(uint8_t bearing) { + InternalWriteData()->WriteByte(Offset::kBearingX, bearing); +} + +int32_t SmallGlyphMetrics::Builder::BearingY() { + return InternalReadData()->ReadByte(Offset::kBearingY); +} + +void SmallGlyphMetrics::Builder::SetBearingY(uint8_t bearing) { + InternalWriteData()->WriteByte(Offset::kBearingY, bearing); +} + +int32_t SmallGlyphMetrics::Builder::Advance() { + return InternalReadData()->ReadByte(Offset::kAdvance); +} + +void SmallGlyphMetrics::Builder::SetAdvance(uint8_t advance) { + InternalWriteData()->WriteByte(Offset::kAdvance, advance); +} + +CALLER_ATTACH FontDataTable* + SmallGlyphMetrics::Builder::SubBuildTable(ReadableFontData* data) { + SmallGlyphMetricsPtr output = new SmallGlyphMetrics(data); + return output.Detach(); +} + +void SmallGlyphMetrics::Builder::SubDataSet() { + // NOP. +} + +int32_t SmallGlyphMetrics::Builder::SubDataSizeToSerialize() { + return 0; +} + +bool SmallGlyphMetrics::Builder::SubReadyToSerialize() { + return false; +} + +int32_t SmallGlyphMetrics::Builder::SubSerialize(WritableFontData* new_data) { + return Data()->CopyTo(new_data); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/bitmap/small_glyph_metrics.h b/gfx/sfntly/cpp/src/sfntly/table/bitmap/small_glyph_metrics.h new file mode 100644 index 0000000000..57cc06e2fb --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/bitmap/small_glyph_metrics.h @@ -0,0 +1,79 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_ + +#include "sfntly/port/refcount.h" +#include "sfntly/table/bitmap/glyph_metrics.h" + +namespace sfntly { + +class SmallGlyphMetrics : public GlyphMetrics, + public RefCounted<SmallGlyphMetrics> { + public: + struct Offset { + enum { + kMetricsLength = 5, + kHeight = 0, + kWidth = 1, + kBearingX = 2, + kBearingY = 3, + kAdvance = 4, + }; + }; + + class Builder : public GlyphMetrics::Builder, + public RefCounted<Builder> { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + explicit Builder(WritableFontData* data); + explicit Builder(ReadableFontData* data); + virtual ~Builder(); + + int32_t Height(); + void SetHeight(uint8_t height); + int32_t Width(); + void SetWidth(uint8_t width); + int32_t BearingX(); + void SetBearingX(uint8_t bearing); + int32_t BearingY(); + void SetBearingY(uint8_t bearing); + int32_t Advance(); + void SetAdvance(uint8_t advance); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + }; + + explicit SmallGlyphMetrics(ReadableFontData* data); + virtual ~SmallGlyphMetrics(); + + int32_t Height(); + int32_t Width(); + int32_t BearingX(); + int32_t BearingY(); + int32_t Advance(); +}; +typedef Ptr<SmallGlyphMetrics> SmallGlyphMetricsPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/byte_array_table_builder.cc b/gfx/sfntly/cpp/src/sfntly/table/byte_array_table_builder.cc new file mode 100644 index 0000000000..2fc982f554 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/byte_array_table_builder.cc @@ -0,0 +1,70 @@ +/* + * 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 "sfntly/table/byte_array_table_builder.h" + +namespace sfntly { + +ByteArrayTableBuilder::~ByteArrayTableBuilder() {} + +int32_t ByteArrayTableBuilder::ByteValue(int32_t index) { + ReadableFontDataPtr data = InternalReadData(); + if (data == NULL) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("No font data for the table"); +#endif + return -1; + } + return data->ReadByte(index); +} + +void ByteArrayTableBuilder::SetByteValue(int32_t index, uint8_t b) { + WritableFontDataPtr data = InternalWriteData(); + if (data == NULL) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("No font data for the table"); +#endif + return; + } + data->WriteByte(index, b); +} + +int32_t ByteArrayTableBuilder::ByteCount() { + ReadableFontDataPtr data = InternalReadData(); + if (data == NULL) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("No font data for the table"); +#endif + return 0; + } + return data->Length(); +} + +ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header, + WritableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header, + ReadableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header) + : TableBasedTableBuilder(header) { +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/byte_array_table_builder.h b/gfx/sfntly/cpp/src/sfntly/table/byte_array_table_builder.h new file mode 100644 index 0000000000..a3df0f8522 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/byte_array_table_builder.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ + +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +// An abstract builder base for byte array based tables. +class ByteArrayTableBuilder : public TableBasedTableBuilder { + public: + virtual ~ByteArrayTableBuilder(); + + // Get the byte value at the specified index. The index is relative to the + // start of the table. + // @param index index relative to the start of the table + // @return byte value at the given index + virtual int32_t ByteValue(int32_t index); + + // Set the byte value at the specified index. The index is relative to the + // start of the table. + // @param index index relative to the start of the table + // @param b byte value to set + virtual void SetByteValue(int32_t index, uint8_t b); + + // Get the number of bytes set for this table. It may include padding bytes at + // the end. + virtual int32_t ByteCount(); + + protected: + ByteArrayTableBuilder(Header* header, WritableFontData* data); + ByteArrayTableBuilder(Header* header, ReadableFontData* data); + explicit ByteArrayTableBuilder(Header* header); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/cmap_table.cc b/gfx/sfntly/cpp/src/sfntly/table/core/cmap_table.cc new file mode 100644 index 0000000000..a66df98cc1 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/cmap_table.cc @@ -0,0 +1,1287 @@ +/* + * 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. + */ + +// type.h needs to be included first because of building issues on Windows +// Type aliases we delcare are defined in other headers and make the build +// fail otherwise. +#include "sfntly/port/type.h" +#include "sfntly/table/core/cmap_table.h" + +#include <stdio.h> +#include <stdlib.h> + +#include <utility> + +#include "sfntly/font.h" +#include "sfntly/math/font_math.h" +#include "sfntly/port/endian.h" +#include "sfntly/port/exception_type.h" +#include "sfntly/table/core/name_table.h" + +namespace sfntly { + +const int32_t CMapTable::NOTDEF = 0; + +CMapTable::CMapId CMapTable::WINDOWS_BMP = { + PlatformId::kWindows, + WindowsEncodingId::kUnicodeUCS2 +}; +CMapTable::CMapId CMapTable::WINDOWS_UCS4 = { + PlatformId::kWindows, + WindowsEncodingId::kUnicodeUCS4 +}; +CMapTable::CMapId CMapTable::MAC_ROMAN = { + PlatformId::kWindows, + MacintoshEncodingId::kRoman +}; + +/****************************************************************************** + * CMapTable class + ******************************************************************************/ +CMapTable::CMapTable(Header* header, ReadableFontData* data) + : SubTableContainerTable(header, data) { +} + +CMapTable::~CMapTable() {} + +CALLER_ATTACH CMapTable::CMap* CMapTable::GetCMap(const int32_t index) { + if (index < 0 || index > NumCMaps()) { +#ifndef SFNTLY_NO_EXCEPTION + throw IndexOutOfBoundException("Requested CMap index is out of bounds."); +#else + return NULL; +#endif + } + int32_t platform_id = PlatformId(index); + int32_t encoding_id = EncodingId(index); + CMapId cmap_id = NewCMapId(platform_id, encoding_id); + int32_t offset_ = Offset(index); + Ptr<FontDataTable::Builder> cmap_builder = + (CMap::Builder::GetBuilder(data_, offset_, cmap_id)); + if (!cmap_builder) { +#ifndef SFNTLY_NO_EXCEPTION + throw NoSuchElementException("Cannot find builder for requested CMap."); +#else + return NULL; +#endif + } + return down_cast<CMapTable::CMap*>(cmap_builder->Build()); +} + +CALLER_ATTACH CMapTable::CMap* CMapTable::GetCMap(const int32_t platform_id, + const int32_t encoding_id) { + return GetCMap(NewCMapId(platform_id, encoding_id)); +} + +CALLER_ATTACH CMapTable::CMap* +CMapTable::GetCMap(const CMapTable::CMapId cmap_id) { + CMapIdFilter id_filter(cmap_id); + CMapIterator cmap_iterator(this, &id_filter); + // There can only be one cmap with a particular CMapId + if (cmap_iterator.HasNext()) { + Ptr<CMapTable::CMap> cmap; + cmap.Attach(cmap_iterator.Next()); + return cmap.Detach(); + } +#ifndef SFNTLY_NO_EXCEPTION + throw NoSuchElementException(); +#else + return NULL; +#endif +} + +int32_t CMapTable::Version() { + return data_->ReadUShort(Offset::kVersion); +} + +int32_t CMapTable::NumCMaps() { + return data_->ReadUShort(Offset::kNumTables); +} + +CMapTable::CMapId CMapTable::GetCMapId(int32_t index) { + return NewCMapId(PlatformId(index), EncodingId(index)); +} + +int32_t CMapTable::PlatformId(int32_t index) { + return data_->ReadUShort(Offset::kEncodingRecordPlatformId + + OffsetForEncodingRecord(index)); +} + +int32_t CMapTable::EncodingId(int32_t index) { + return data_->ReadUShort(Offset::kEncodingRecordEncodingId + + OffsetForEncodingRecord(index)); +} + +int32_t CMapTable::Offset(int32_t index) { + return data_->ReadULongAsInt(Offset::kEncodingRecordOffset + + OffsetForEncodingRecord(index)); +} + +int32_t CMapTable::OffsetForEncodingRecord(int32_t index) { + return Offset::kEncodingRecordStart + index * Offset::kEncodingRecordSize; +} + +CMapTable::CMapId CMapTable::NewCMapId(int32_t platform_id, + int32_t encoding_id) { + CMapId result; + result.platform_id = platform_id; + result.encoding_id = encoding_id; + return result; +} + +CMapTable::CMapId CMapTable::NewCMapId(const CMapId& obj) { + CMapId result; + result.platform_id = obj.platform_id; + result.encoding_id = obj.encoding_id; + return result; +} + +/****************************************************************************** + * CMapTable::CMapIterator class + ******************************************************************************/ +CMapTable::CMapIterator::CMapIterator(CMapTable* table, + const CMapFilter* filter) + : table_index_(0), filter_(filter), table_(table) { +} + +bool CMapTable::CMapIterator::HasNext() { + if (!filter_) { + if (table_index_ < table_->NumCMaps()) { + return true; + } + return false; + } + + for (; table_index_ < table_->NumCMaps(); ++table_index_) { + if (filter_->accept(table_->GetCMapId(table_index_))) { + return true; + } + } + return false; +} + +CALLER_ATTACH CMapTable::CMap* CMapTable::CMapIterator::Next() { + if (!HasNext()) { +#ifndef SFNTLY_NO_EXCEPTION + throw NoSuchElementException(); +#else + return NULL; +#endif + } + CMapPtr next_cmap; + next_cmap.Attach(table_->GetCMap(table_index_++)); + if (next_cmap == NULL) { +#ifndef SFNTLY_NO_EXCEPTION + throw NoSuchElementException("Error during the creation of the CMap"); +#else + return NULL; +#endif + } + return next_cmap.Detach(); +} + +/****************************************************************************** + * CMapTable::CMapId class + ******************************************************************************/ + +/****************************************************************************** + * CMapTable::CMapIdComparator class + ******************************************************************************/ + +bool CMapTable::CMapIdComparator::operator()(const CMapId& lhs, + const CMapId& rhs) const { + return ((lhs.platform_id << 8 | lhs.encoding_id) > + (rhs.platform_id << 8 | rhs.encoding_id)); +} + +/****************************************************************************** + * CMapTable::CMapIdFilter class + ******************************************************************************/ +CMapTable::CMapIdFilter::CMapIdFilter(const CMapId wanted_id) + : wanted_id_(wanted_id), + comparator_(NULL) { +} + +CMapTable::CMapIdFilter::CMapIdFilter(const CMapId wanted_id, + const CMapIdComparator* comparator) + : wanted_id_(wanted_id), + comparator_(comparator) { +} + +bool CMapTable::CMapIdFilter::accept(const CMapId& cmap_id) const { + if (!comparator_) + return wanted_id_ == cmap_id; + return (*comparator_)(wanted_id_, cmap_id); +} + +/****************************************************************************** + * CMapTable::CMap class + ******************************************************************************/ +CMapTable::CMap::CMap(ReadableFontData* data, int32_t format, + const CMapId& cmap_id) + : SubTable(data), format_(format), cmap_id_(cmap_id) { +} + +CMapTable::CMap::~CMap() { +} + +/****************************************************************************** + * CMapTable::CMap::Builder class + ******************************************************************************/ +CMapTable::CMap::Builder::~Builder() { +} + +CALLER_ATTACH CMapTable::CMap::Builder* + CMapTable::CMap::Builder::GetBuilder(ReadableFontData* data, int32_t offset, + const CMapId& cmap_id) { + // NOT IMPLEMENTED: Java enum value validation + int32_t format = data->ReadUShort(offset); + CMapBuilderPtr builder; + switch (format) { + case CMapFormat::kFormat0: + builder.Attach(CMapFormat0::Builder::NewInstance(data, offset, cmap_id)); + break; + case CMapFormat::kFormat2: +#if defined (SFNTLY_DEBUG_CMAP) + fprintf(stderr, "Requesting Format2 builder, but it's unsupported; " + "returning NULL\n"); +#endif + break; + case CMapFormat::kFormat4: + builder.Attach(CMapFormat4::Builder::NewInstance(data, offset, cmap_id)); + break; + default: +#ifdef SFNTLY_DEBUG_CMAP + fprintf(stderr, "Unknown builder format requested\n"); +#endif + break; + } + return builder.Detach(); +} + +CALLER_ATTACH CMapTable::CMap::Builder* +CMapTable::CMap::Builder::GetBuilder(int32_t format, const CMapId& cmap_id) { + Ptr<CMapTable::CMap::Builder> builder; + switch (format) { + case CMapFormat::kFormat0: + builder.Attach(CMapFormat0::Builder::NewInstance(cmap_id)); + break; + case CMapFormat::kFormat2: +#if defined (SFNTLY_DEBUG_CMAP) + fprintf(stderr, "Requesting Format2 builder, but it's unsupported; " + "returning NULL\n"); +#endif + break; + case CMapFormat::kFormat4: + builder.Attach(CMapFormat4::Builder::NewInstance(cmap_id)); + break; + default: +#ifdef SFNTLY_DEBUG_CMAP + fprintf(stderr, "Unknown builder format requested\n"); +#endif + break; + } + return builder.Detach(); +} + +CMapTable::CMap::Builder::Builder(ReadableFontData* data, + int32_t format, + const CMapId& cmap_id) + : SubTable::Builder(data), + format_(format), + cmap_id_(cmap_id), + language_(0) { +} + +CMapTable::CMap::Builder::Builder(WritableFontData* data, + int32_t format, + const CMapId& cmap_id) + : SubTable::Builder(data), + format_(format), + cmap_id_(cmap_id), + language_(0) { +} + +int32_t CMapTable::CMap::Builder::SubSerialize(WritableFontData* new_data) { + return InternalReadData()->CopyTo(new_data); +} + +bool CMapTable::CMap::Builder::SubReadyToSerialize() { + return true; +} + +int32_t CMapTable::CMap::Builder::SubDataSizeToSerialize() { + ReadableFontDataPtr read_data = InternalReadData(); + if (!read_data) + return 0; + return read_data->Length(); +} + +void CMapTable::CMap::Builder::SubDataSet() { + // NOP +} + +/****************************************************************************** + * CMapTable::CMapFormat0 + ******************************************************************************/ +CMapTable::CMapFormat0::~CMapFormat0() { +} + +int32_t CMapTable::CMapFormat0::Language() { + return 0; +} + +int32_t CMapTable::CMapFormat0::GlyphId(int32_t character) { + if (character < 0 || character > 255) { + return CMapTable::NOTDEF; + } + return data_->ReadUByte(character + Offset::kFormat0GlyphIdArray); +} + +CMapTable::CMapFormat0::CMapFormat0(ReadableFontData* data, + const CMapId& cmap_id) + : CMap(data, CMapFormat::kFormat0, cmap_id) { +} + +CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat0::Iterator() { + return new CMapTable::CMapFormat0::CharacterIterator(0, 0xff); +} + + +/****************************************************************************** + * CMapTable::CMapFormat0::CharacterIterator + ******************************************************************************/ +CMapTable::CMapFormat0::CharacterIterator::CharacterIterator(int32_t start, + int32_t end) + : character_(start), + max_character_(end) { +} + +CMapTable::CMapFormat0::CharacterIterator::~CharacterIterator() {} + +bool CMapTable::CMapFormat0::CharacterIterator::HasNext() { + return character_ < max_character_; +} + +int32_t CMapTable::CMapFormat0::CharacterIterator::Next() { + if (HasNext()) + return character_++; +#ifndef SFNTLY_NO_EXCEPTION + throw NoSuchElementException("No more characters to iterate."); +#endif + return -1; +} + +/****************************************************************************** + * CMapTable::CMapFormat0::Builder + ******************************************************************************/ +// static +CALLER_ATTACH CMapTable::CMapFormat0::Builder* +CMapTable::CMapFormat0::Builder::NewInstance(WritableFontData* data, + int32_t offset, + const CMapId& cmap_id) { + WritableFontDataPtr wdata; + if (data) { + wdata.Attach(down_cast<WritableFontData*>( + data->Slice(offset, + data->ReadUShort(offset + Offset::kFormat0Length)))); + } + return new Builder(wdata, CMapFormat::kFormat0, cmap_id); +} + +// static +CALLER_ATTACH CMapTable::CMapFormat0::Builder* +CMapTable::CMapFormat0::Builder::NewInstance(ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id) { + ReadableFontDataPtr rdata; + if (data) { + rdata.Attach(down_cast<ReadableFontData*>( + data->Slice(offset, + data->ReadUShort(offset + Offset::kFormat0Length)))); + } + return new Builder(rdata, CMapFormat::kFormat0, cmap_id); +} + +// static +CALLER_ATTACH CMapTable::CMapFormat0::Builder* +CMapTable::CMapFormat0::Builder::NewInstance(const CMapId& cmap_id) { + return new Builder(cmap_id); +} + +// Always call NewInstance instead of the constructor for creating a new builder +// object! This refactoring avoids memory leaks when slicing the font data. +CMapTable::CMapFormat0::Builder::Builder(WritableFontData* data, int32_t offset, + const CMapId& cmap_id) + : CMapTable::CMap::Builder(data, CMapFormat::kFormat0, cmap_id) { + UNREFERENCED_PARAMETER(offset); +} + +CMapTable::CMapFormat0::Builder::Builder( + ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id) + : CMapTable::CMap::Builder(data, CMapFormat::kFormat0, cmap_id) { + UNREFERENCED_PARAMETER(offset); +} + +CMapTable::CMapFormat0::Builder::Builder(const CMapId& cmap_id) + : CMap::Builder(static_cast<ReadableFontData*>(NULL), + CMapFormat::kFormat0, + cmap_id) { +} + +CMapTable::CMapFormat0::Builder::~Builder() { +} + +CALLER_ATTACH FontDataTable* + CMapTable::CMapFormat0::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new CMapFormat0(data, cmap_id()); + return table.Detach(); +} + +/****************************************************************************** + * CMapTable::CMapFormat2 + ******************************************************************************/ +CMapTable::CMapFormat2::~CMapFormat2() { +} + +int32_t CMapTable::CMapFormat2::Language() { + return 0; +} + +int32_t CMapTable::CMapFormat2::GlyphId(int32_t character) { + if (character > 0xffff) { + return CMapTable::NOTDEF; + } + + uint32_t c = ToBE32(character); + uint8_t high_byte = (c >> 8) & 0xff; + uint8_t low_byte = c & 0xff; + int32_t offset = SubHeaderOffset(high_byte); + + if (offset == 0) { + low_byte = high_byte; + high_byte = 0; + } + + int32_t first_code = FirstCode(high_byte); + int32_t entry_count = EntryCount(high_byte); + + if (low_byte < first_code || low_byte >= first_code + entry_count) { + return CMapTable::NOTDEF; + } + + int32_t id_range_offset = IdRangeOffset(high_byte); + + // position of idRangeOffset + value of idRangeOffset + index for low byte + // = firstcode + int32_t p_location = (offset + Offset::kFormat2SubHeader_idRangeOffset) + + id_range_offset + + (low_byte - first_code) * DataSize::kUSHORT; + int p = data_->ReadUShort(p_location); + if (p == 0) { + return CMapTable::NOTDEF; + } + + if (offset == 0) { + return p; + } + int id_delta = IdDelta(high_byte); + return (p + id_delta) % 65536; +} + +int32_t CMapTable::CMapFormat2::BytesConsumed(int32_t character) { + uint32_t c = ToBE32(character); + int32_t high_byte = (c >> 8) & 0xff; + int32_t offset = SubHeaderOffset(high_byte); + return (offset == 0) ? 1 : 2; +} + +CMapTable::CMapFormat2::CMapFormat2(ReadableFontData* data, + const CMapId& cmap_id) + : CMap(data, CMapFormat::kFormat2, cmap_id) { +} + +int32_t CMapTable::CMapFormat2::SubHeaderOffset(int32_t sub_header_index) { + return data_->ReadUShort(Offset::kFormat2SubHeaderKeys + + sub_header_index * DataSize::kUSHORT); +} + +int32_t CMapTable::CMapFormat2::FirstCode(int32_t sub_header_index) { + int32_t sub_header_offset = SubHeaderOffset(sub_header_index); + return data_->ReadUShort(sub_header_offset + + Offset::kFormat2SubHeaderKeys + + Offset::kFormat2SubHeader_firstCode); +} + +int32_t CMapTable::CMapFormat2::EntryCount(int32_t sub_header_index) { + int32_t sub_header_offset = SubHeaderOffset(sub_header_index); + return data_->ReadUShort(sub_header_offset + + Offset::kFormat2SubHeaderKeys + + Offset::kFormat2SubHeader_entryCount); +} + +int32_t CMapTable::CMapFormat2::IdRangeOffset(int32_t sub_header_index) { + int32_t sub_header_offset = SubHeaderOffset(sub_header_index); + return data_->ReadUShort(sub_header_offset + + Offset::kFormat2SubHeaderKeys + + Offset::kFormat2SubHeader_idRangeOffset); +} + +int32_t CMapTable::CMapFormat2::IdDelta(int32_t sub_header_index) { + int32_t sub_header_offset = SubHeaderOffset(sub_header_index); + return data_->ReadUShort(sub_header_offset + + Offset::kFormat2SubHeaderKeys + + Offset::kFormat2SubHeader_idDelta); +} + +CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat2::Iterator() { + // UNIMPLEMENTED + return NULL; +} + +/****************************************************************************** + * CMapTable::CMapFormat2::Builder + ******************************************************************************/ +CMapTable::CMapFormat2::Builder::Builder(WritableFontData* data, + int32_t offset, + const CMapId& cmap_id) + : CMapTable::CMap::Builder(data ? down_cast<WritableFontData*>( + data->Slice(offset, data->ReadUShort( + offset + Offset::kFormat0Length))) + : static_cast<WritableFontData*>(NULL), + CMapFormat::kFormat2, cmap_id) { + // TODO(arthurhsu): FIXIT: heavy lifting and leak, need fix. +} + +CMapTable::CMapFormat2::Builder::Builder(ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id) + : CMapTable::CMap::Builder(data ? down_cast<ReadableFontData*>( + data->Slice(offset, data->ReadUShort( + offset + Offset::kFormat0Length))) + : static_cast<ReadableFontData*>(NULL), + CMapFormat::kFormat2, cmap_id) { + // TODO(arthurhsu): FIXIT: heavy lifting and leak, need fix. +} + +CMapTable::CMapFormat2::Builder::~Builder() { +} + +CALLER_ATTACH FontDataTable* + CMapTable::CMapFormat2::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new CMapFormat2(data, cmap_id()); + return table.Detach(); +} + +/****************************************************************************** + * CMapTable::CMapFormat4 + ******************************************************************************/ +CMapTable::CMapFormat4::CMapFormat4(ReadableFontData* data, + const CMapId& cmap_id) + : CMap(data, CMapFormat::kFormat4, cmap_id), + seg_count_(SegCount(data)), + start_code_offset_(StartCodeOffset(seg_count_)), + id_delta_offset_(IdDeltaOffset(seg_count_)), + glyph_id_array_offset_(GlyphIdArrayOffset(seg_count_)) { +} + +CMapTable::CMapFormat4::~CMapFormat4() { +} + +int32_t CMapTable::CMapFormat4::GlyphId(int32_t character) { + int32_t segment = data_->SearchUShort(StartCodeOffset(seg_count_), + DataSize::kUSHORT, + Offset::kFormat4EndCount, + DataSize::kUSHORT, + seg_count_, + character); + if (segment == -1) { + return CMapTable::NOTDEF; + } + int32_t start_code = StartCode(segment); + return RetrieveGlyphId(segment, start_code, character); +} + +int32_t CMapTable::CMapFormat4::RetrieveGlyphId(int32_t segment, + int32_t start_code, + int32_t character) { + if (character < start_code) { + return CMapTable::NOTDEF; + } + int32_t id_range_offset = IdRangeOffset(segment); + if (id_range_offset == 0) { + return (character + IdDelta(segment)) % 65536; + } + return data_->ReadUShort(id_range_offset + + IdRangeOffsetLocation(segment) + + 2 * (character - start_code)); +} + +int32_t CMapTable::CMapFormat4::seg_count() { + return seg_count_; +} + +int32_t CMapTable::CMapFormat4::Length() { + return Length(data_); +} + +int32_t CMapTable::CMapFormat4::StartCode(int32_t segment) { + if (!IsValidIndex(segment)) { + return -1; + } + return StartCode(data_.p_, seg_count_, segment); +} + +// static +int32_t CMapTable::CMapFormat4::Language(ReadableFontData* data) { + int32_t language = data->ReadUShort(Offset::kFormat4Language); + return language; +} + +// static +int32_t CMapTable::CMapFormat4::Length(ReadableFontData* data) { + int32_t length = data->ReadUShort(Offset::kFormat4Length); + return length; +} + +// static +int32_t CMapTable::CMapFormat4::SegCount(ReadableFontData* data) { + int32_t seg_count = data->ReadUShort(Offset::kFormat4SegCountX2) / 2; + return seg_count; +} + +// static +int32_t CMapTable::CMapFormat4::StartCode(ReadableFontData* data, + int32_t seg_count, + int32_t index) { + int32_t start_code = data->ReadUShort(StartCodeOffset(seg_count) + + index * DataSize::kUSHORT); + return start_code; +} + +// static +int32_t CMapTable::CMapFormat4::StartCodeOffset(int32_t seg_count) { + int32_t start_code_offset = Offset::kFormat4EndCount + + (seg_count + 1) * DataSize::kUSHORT; + return start_code_offset; +} + +// static +int32_t CMapTable::CMapFormat4::EndCode(ReadableFontData* data, + int32_t seg_count, + int32_t index) { + UNREFERENCED_PARAMETER(seg_count); + int32_t end_code = data->ReadUShort(Offset::kFormat4EndCount + + index * DataSize::kUSHORT); + return end_code; +} + +// static +int32_t CMapTable::CMapFormat4::IdDelta(ReadableFontData* data, + int32_t seg_count, + int32_t index) { + int32_t id_delta = data->ReadUShort(IdDeltaOffset(seg_count) + + index * DataSize::kUSHORT); + return id_delta; +} + +// static +int32_t CMapTable::CMapFormat4::IdDeltaOffset(int32_t seg_count) { + int32_t id_delta_offset = + Offset::kFormat4EndCount + (2 * seg_count + 1) * DataSize::kUSHORT; + return id_delta_offset; +} + +// static +int32_t CMapTable::CMapFormat4::IdRangeOffset(ReadableFontData* data, + int32_t seg_count, + int32_t index) { + int32_t id_range_offset = + data->ReadUShort(IdRangeOffsetOffset(seg_count) + + index * DataSize::kUSHORT); + return id_range_offset; +} + +// static +int32_t CMapTable::CMapFormat4::IdRangeOffsetOffset(int32_t seg_count) { + int32_t id_range_offset_offset = + Offset::kFormat4EndCount + (2 * seg_count + 1) * DataSize::kUSHORT + + seg_count * DataSize::kSHORT; + return id_range_offset_offset; +} + +// static +int32_t CMapTable::CMapFormat4::GlyphIdArrayOffset(int32_t seg_count) { + int32_t glyph_id_array_offset = + Offset::kFormat4EndCount + (3 * seg_count + 1) * DataSize::kUSHORT + + seg_count * DataSize::kSHORT; + return glyph_id_array_offset; +} + +int32_t CMapTable::CMapFormat4::EndCode(int32_t segment) { + if (IsValidIndex(segment)) { + return EndCode(data_, seg_count_, segment); + } +#if defined (SFNTLY_NO_EXCEPTION) + return -1; +#else + throw IllegalArgumentException(); +#endif +} + +bool CMapTable::CMapFormat4::IsValidIndex(int32_t segment) { + if (segment < 0 || segment >= seg_count_) { +#if defined (SFNTLY_NO_EXCEPTION) + return false; +#else + throw IllegalArgumentException(); +#endif + } + return true; +} + +int32_t CMapTable::CMapFormat4::IdDelta(int32_t segment) { + if (IsValidIndex(segment)) + return IdDelta(data_, seg_count_, segment); + return -1; +} + +int32_t CMapTable::CMapFormat4::IdRangeOffset(int32_t segment) { + if (IsValidIndex(segment)) + return data_->ReadUShort(IdRangeOffsetLocation(segment)); + return -1; +} + +int32_t CMapTable::CMapFormat4::IdRangeOffsetLocation(int32_t segment) { + if (IsValidIndex(segment)) + return IdRangeOffsetOffset(seg_count_) + segment * DataSize::kUSHORT; + return -1; +} + +int32_t CMapTable::CMapFormat4::GlyphIdArray(int32_t index) { + return data_->ReadUShort(glyph_id_array_offset_ + index * DataSize::kUSHORT); +} + +int32_t CMapTable::CMapFormat4::Language() { + return Language(data_); +} + + +CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat4::Iterator() { + return new CharacterIterator(this); +} + +/****************************************************************************** + * CMapTable::CMapFormat4::CharacterIterator class + ******************************************************************************/ +CMapTable::CMapFormat4::CharacterIterator::CharacterIterator( + CMapFormat4* parent) + : parent_(parent), + segment_index_(0), + first_char_in_segment_(-1), + last_char_in_segment_(-1), + next_char_(-1), + next_char_set_(false) { +} + +bool CMapTable::CMapFormat4::CharacterIterator::HasNext() { + if (next_char_set_) + return true; + while (segment_index_ < parent_->seg_count_) { + if (first_char_in_segment_ < 0) { + first_char_in_segment_ = parent_->StartCode(segment_index_); + last_char_in_segment_ = parent_->EndCode(segment_index_); + next_char_ = first_char_in_segment_; + next_char_set_ = true; + return true; + } + if (next_char_ < last_char_in_segment_) { + next_char_++; + next_char_set_ = true; + return true; + } + segment_index_++; + first_char_in_segment_ = -1; + } + return false; +} + +int32_t CMapTable::CMapFormat4::CharacterIterator::Next() { + if (!next_char_set_) { + if (!HasNext()) { +#if defined (SFNTLY_NO_EXCEPTION) + return -1; +#else + throw NoSuchElementException("No more characters to iterate."); +#endif + } + } + next_char_set_ = false; + return next_char_; +} + +/****************************************************************************** + * CMapTable::CMapFormat4::Builder::Segment class + ******************************************************************************/ +CMapTable::CMapFormat4::Builder::Segment::Segment() {} + +CMapTable::CMapFormat4::Builder::Segment::Segment(Segment* other) + : start_count_(other->start_count_), + end_count_(other->end_count_), + id_delta_(other->id_delta_), + id_range_offset_(other->id_range_offset_) { +} + +CMapTable::CMapFormat4::Builder::Segment::Segment(int32_t start_count, + int32_t end_count, + int32_t id_delta, + int32_t id_range_offset) + : start_count_(start_count), + end_count_(end_count), + id_delta_(id_delta), + id_range_offset_(id_range_offset) { +} + +CMapTable::CMapFormat4::Builder::Segment::~Segment() {} + +int32_t CMapTable::CMapFormat4::Builder::Segment::start_count() { + return start_count_; +} + +void +CMapTable::CMapFormat4::Builder::Segment::set_start_count(int32_t start_count) { + start_count_ = start_count; +} + +int32_t CMapTable::CMapFormat4::Builder::Segment::end_count() { + return end_count_; +} + +void +CMapTable::CMapFormat4::Builder::Segment::set_end_count(int32_t end_count) { + end_count_ = end_count; +} + +int32_t CMapTable::CMapFormat4::Builder::Segment::id_delta() { + return id_delta_; +} + +void +CMapTable::CMapFormat4::Builder::Segment::set_id_delta(int32_t id_delta) { + id_delta_ = id_delta; +} + +int32_t CMapTable::CMapFormat4::Builder::Segment::id_range_offset() { + return id_range_offset_; +} + +void +CMapTable::CMapFormat4::Builder::Segment:: +set_id_range_offset(int32_t id_range_offset) { + id_range_offset_ = id_range_offset; +} + +// static +CALLER_ATTACH SegmentList* +CMapTable::CMapFormat4::Builder::Segment::DeepCopy(SegmentList* original) { + SegmentList* list = new SegmentList; + for (SegmentList::iterator it = original->begin(), + e = original->end(); it != e; ++it) { + list->push_back(*it); + } + return list; +} + +/****************************************************************************** + * CMapTable::CMapFormat4::Builder class + ******************************************************************************/ +CALLER_ATTACH CMapTable::CMapFormat4::Builder* +CMapTable::CMapFormat4::Builder::NewInstance(ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id) { + ReadableFontDataPtr rdata; + if (data) { + rdata.Attach + (down_cast<ReadableFontData*> + (data->Slice(offset, + data->ReadUShort(offset + Offset::kFormat4Length)))); + } + return new Builder(rdata, CMapFormat::kFormat4, cmap_id); +} + +CALLER_ATTACH CMapTable::CMapFormat4::Builder* +CMapTable::CMapFormat4::Builder::NewInstance(WritableFontData* data, + int32_t offset, + const CMapId& cmap_id) { + WritableFontDataPtr wdata; + if (data) { + wdata.Attach + (down_cast<WritableFontData*> + (data->Slice(offset, + data->ReadUShort(offset + Offset::kFormat4Length)))); + } + return new Builder(wdata, CMapFormat::kFormat4, cmap_id); +} + +CALLER_ATTACH CMapTable::CMapFormat4::Builder* +CMapTable::CMapFormat4::Builder::NewInstance(const CMapId& cmap_id) { + return new Builder(cmap_id); +} + +CMapTable::CMapFormat4::Builder::Builder(ReadableFontData* data, int32_t offset, + const CMapId& cmap_id) + : CMap::Builder(data, CMapFormat::kFormat4, cmap_id) { + UNREFERENCED_PARAMETER(offset); +} + +CMapTable::CMapFormat4::Builder::Builder(WritableFontData* data, int32_t offset, + const CMapId& cmap_id) + : CMap::Builder(data, CMapFormat::kFormat4, cmap_id) { + UNREFERENCED_PARAMETER(offset); +} + +CMapTable::CMapFormat4::Builder::Builder(SegmentList* segments, + std::vector<int32_t>* glyph_id_array, + const CMapId& cmap_id) + : CMap::Builder(static_cast<ReadableFontData*>(NULL), + CMapFormat::kFormat4, cmap_id), + segments_(segments->begin(), segments->end()), + glyph_id_array_(glyph_id_array->begin(), glyph_id_array->end()) { + set_model_changed(); +} + +CMapTable::CMapFormat4::Builder::Builder(const CMapId& cmap_id) + : CMap::Builder(static_cast<ReadableFontData*>(NULL), + CMapFormat::kFormat4, cmap_id) { +} + +CMapTable::CMapFormat4::Builder::~Builder() {} + +void CMapTable::CMapFormat4::Builder::Initialize(ReadableFontData* data) { + if (data == NULL || data->Length() == 0) + return; + + // build segments + int32_t seg_count = CMapFormat4::SegCount(data); + for (int32_t index = 0; index < seg_count; ++index) { + Ptr<Segment> segment = new Segment; + segment->set_start_count(CMapFormat4::StartCode(data, seg_count, index)); +#if defined SFNTLY_DEBUG_CMAP + fprintf(stderr, "Segment %d; start %d\n", index, segment->start_count()); +#endif + segment->set_end_count(CMapFormat4::EndCode(data, seg_count, index)); + segment->set_id_delta(CMapFormat4::IdDelta(data, seg_count, index)); + segment->set_id_range_offset(CMapFormat4::IdRangeOffset(data, + seg_count, + index)); + segments_.push_back(segment); + } + + // build glyph id array + int32_t glyph_id_array_offset = CMapFormat4::GlyphIdArrayOffset(seg_count); + int32_t glyph_id_array_length = + (CMapFormat4::Length(data) - glyph_id_array_offset) + / DataSize::kUSHORT; + fprintf(stderr, "id array size %d\n", glyph_id_array_length); + for (int32_t i = 0; i < glyph_id_array_length; i += DataSize::kUSHORT) { + glyph_id_array_.push_back(data->ReadUShort(glyph_id_array_offset + i)); + } +} + +SegmentList* CMapTable::CMapFormat4::Builder::segments() { + if (segments_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &segments_; +} + +void CMapTable::CMapFormat4::Builder::set_segments(SegmentList* segments) { + segments_.assign(segments->begin(), segments->end()); + set_model_changed(); +} + +std::vector<int32_t>* CMapTable::CMapFormat4::Builder::glyph_id_array() { + if (glyph_id_array_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &glyph_id_array_; +} + +void CMapTable::CMapFormat4::Builder:: +set_glyph_id_array(std::vector<int32_t>* glyph_id_array) { + glyph_id_array_.assign(glyph_id_array->begin(), glyph_id_array->end()); + set_model_changed(); +} + +CALLER_ATTACH FontDataTable* +CMapTable::CMapFormat4::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new CMapFormat4(data, cmap_id()); + return table.Detach(); +} + +void CMapTable::CMapFormat4::Builder::SubDataSet() { + segments_.clear(); + glyph_id_array_.clear(); + set_model_changed(); +} + +int32_t CMapTable::CMapFormat4::Builder::SubDataSizeToSerialize() { + if (!model_changed()) { + return CMap::Builder::SubDataSizeToSerialize(); + } + int32_t size = Offset::kFormat4FixedSize + segments_.size() + * (3 * DataSize::kUSHORT + DataSize::kSHORT) + + glyph_id_array_.size() * DataSize::kSHORT; + return size; +} + +bool CMapTable::CMapFormat4::Builder::SubReadyToSerialize() { + if (!model_changed()) { + return CMap::Builder::SubReadyToSerialize(); + } + if (!segments()->empty()) { + return true; + } + return false; +} + +int32_t +CMapTable::CMapFormat4::Builder::SubSerialize(WritableFontData* new_data) { + if (!model_changed()) { + return CMap::Builder::SubSerialize(new_data); + } + int32_t index = 0; + index += new_data->WriteUShort(index, CMapFormat::kFormat4); + index += DataSize::kUSHORT; // length - write this at the end + index += new_data->WriteUShort(index, language()); + + int32_t seg_count = segments_.size(); + index += new_data->WriteUShort(index, seg_count * 2); + int32_t log2_seg_count = FontMath::Log2(seg_count); + int32_t search_range = 1 << (log2_seg_count + 1); + index += new_data->WriteUShort(index, search_range); + int32_t entry_selector = log2_seg_count; + index += new_data->WriteUShort(index, entry_selector); + int32_t range_shift = 2 * seg_count - search_range; + index += new_data->WriteUShort(index, range_shift); + + for (int32_t i = 0; i < seg_count; ++i) { + index += new_data->WriteUShort(index, segments_[i]->end_count()); + } + index += new_data->WriteUShort(index, 0); // reserved ushort + for (int32_t i = 0; i < seg_count; ++i) { +#if defined SFNTLY_DEBUG_CMAP + fprintf(stderr, "Segment %d; start %d\n", i, segments_[i]->start_count()); +#endif + index += new_data->WriteUShort(index, segments_[i]->start_count()); + } + for (int32_t i = 0; i < seg_count; ++i) { + index += new_data->WriteShort(index, segments_[i]->id_delta()); + } + for (int32_t i = 0; i < seg_count; ++i) { + index += new_data->WriteUShort(index, segments_[i]->id_range_offset()); + } + +#if defined SFNTLY_DEBUG_CMAP + fprintf(stderr, "Glyph id array size %lu\n", glyph_id_array_.size()); +#endif + for (size_t i = 0; i < glyph_id_array_.size(); ++i) { + index += new_data->WriteUShort(index, glyph_id_array_[i]); + } + + new_data->WriteUShort(Offset::kFormat4Length, index); + return index; +} + +/****************************************************************************** + * CMapTable::Builder class + ******************************************************************************/ +CMapTable::Builder::Builder(Header* header, WritableFontData* data) + : SubTableContainerTable::Builder(header, data), version_(0) { +} + +CMapTable::Builder::Builder(Header* header, ReadableFontData* data) + : SubTableContainerTable::Builder(header, data), version_(0) { +} + +CMapTable::Builder::~Builder() { +} + +int32_t CMapTable::Builder::SubSerialize(WritableFontData* new_data) { + int32_t size = new_data->WriteUShort(CMapTable::Offset::kVersion, + version_); + size += new_data->WriteUShort(CMapTable::Offset::kNumTables, + GetCMapBuilders()->size()); + + int32_t index_offset = size; + size += GetCMapBuilders()->size() * CMapTable::Offset::kEncodingRecordSize; + for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(), + e = GetCMapBuilders()->end(); it != e; ++it) { + CMapBuilderPtr b = it->second; + // header entry + index_offset += new_data->WriteUShort(index_offset, b->platform_id()); + index_offset += new_data->WriteUShort(index_offset, b->encoding_id()); + index_offset += new_data->WriteULong(index_offset, size); + + // cmap + FontDataPtr slice; + slice.Attach(new_data->Slice(size)); + size += b->SubSerialize(down_cast<WritableFontData*>(slice.p_)); + } + return size; +} + +bool CMapTable::Builder::SubReadyToSerialize() { + if (GetCMapBuilders()->empty()) + return false; + + // check each table + for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(), + e = GetCMapBuilders()->end(); it != e; ++it) { + if (!it->second->SubReadyToSerialize()) + return false; + } + return true; +} + +int32_t CMapTable::Builder::SubDataSizeToSerialize() { + if (GetCMapBuilders()->empty()) + return 0; + + bool variable = false; + int32_t size = CMapTable::Offset::kEncodingRecordStart + + GetCMapBuilders()->size() * CMapTable::Offset::kEncodingRecordSize; + + // calculate size of each table + for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(), + e = GetCMapBuilders()->end(); it != e; ++it) { + int32_t cmap_size = it->second->SubDataSizeToSerialize(); + size += abs(cmap_size); + variable |= cmap_size <= 0; + } + return variable ? -size : size; +} + +void CMapTable::Builder::SubDataSet() { + GetCMapBuilders()->clear(); + Table::Builder::set_model_changed(); +} + +CALLER_ATTACH FontDataTable* + CMapTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new CMapTable(header(), data); + return table.Detach(); +} + +CALLER_ATTACH CMapTable::Builder* + CMapTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr<CMapTable::Builder> builder; + builder = new CMapTable::Builder(header, data); + return builder.Detach(); +} + +// static +CALLER_ATTACH CMapTable::CMap::Builder* + CMapTable::Builder::CMapBuilder(ReadableFontData* data, int32_t index) { + if (index < 0 || index > NumCMaps(data)) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException( + "CMap table is outside of the bounds of the known tables."); +#endif + return NULL; + } + + int32_t platform_id = data->ReadUShort(Offset::kEncodingRecordPlatformId + + OffsetForEncodingRecord(index)); + int32_t encoding_id = data->ReadUShort(Offset::kEncodingRecordEncodingId + + OffsetForEncodingRecord(index)); + int32_t offset = data->ReadULongAsInt(Offset::kEncodingRecordOffset + + OffsetForEncodingRecord(index)); + return CMap::Builder::GetBuilder(data, offset, + NewCMapId(platform_id, encoding_id)); +} + +// static +int32_t CMapTable::Builder::NumCMaps(ReadableFontData* data) { + if (data == NULL) { + return 0; + } + return data->ReadUShort(Offset::kNumTables); +} + +int32_t CMapTable::Builder::NumCMaps() { + return GetCMapBuilders()->size(); +} + +void CMapTable::Builder::Initialize(ReadableFontData* data) { + int32_t num_cmaps = NumCMaps(data); + for (int32_t i = 0; i < num_cmaps; ++i) { + CMapTable::CMap::Builder* cmap_builder = CMapBuilder(data, i); + if (!cmap_builder) + continue; + cmap_builders_[cmap_builder->cmap_id()] = cmap_builder; + } +} + +CMapTable::CMap::Builder* CMapTable::Builder::NewCMapBuilder( + const CMapId& cmap_id, + ReadableFontData* data) { + Ptr<WritableFontData> wfd; + wfd.Attach(WritableFontData::CreateWritableFontData(data->Size())); + data->CopyTo(wfd.p_); + CMapTable::CMapBuilderPtr builder; + builder.Attach(CMap::Builder::GetBuilder(wfd.p_, 0, cmap_id)); + CMapBuilderMap* cmap_builders = CMapTable::Builder::GetCMapBuilders(); + cmap_builders->insert(std::make_pair(cmap_id, builder.p_)); + return builder.Detach(); +} + +CMapTable::CMap::Builder* +CMapTable::Builder::NewCMapBuilder(int32_t format, const CMapId& cmap_id) { + Ptr<CMapTable::CMap::Builder> cmap_builder; + cmap_builder.Attach(CMap::Builder::GetBuilder(format, cmap_id)); + CMapBuilderMap* cmap_builders = CMapTable::Builder::GetCMapBuilders(); + cmap_builders->insert(std::make_pair(cmap_id, cmap_builder.p_)); + return cmap_builder.Detach(); +} + +CMapTable::CMap::Builder* +CMapTable::Builder::CMapBuilder(const CMapId& cmap_id) { + CMapBuilderMap* cmap_builders = this->GetCMapBuilders(); + CMapBuilderMap::iterator builder = cmap_builders->find(cmap_id); + if (builder != cmap_builders->end()) + return builder->second; +#ifndef SFNTLY_NO_EXCEPTION + throw NoSuchElementException("No builder found for cmap_id"); +#else + return NULL; +#endif +} + +CMapTable::CMapBuilderMap* CMapTable::Builder::GetCMapBuilders() { + if (cmap_builders_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &cmap_builders_; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/cmap_table.h b/gfx/sfntly/cpp/src/sfntly/table/core/cmap_table.h new file mode 100644 index 0000000000..81f0a5d477 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/cmap_table.h @@ -0,0 +1,709 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_ + +// type.h needs to be included first because of building issues on Windows +// Type aliases we delcare are defined in other headers and make the build +// fail otherwise. +#include "sfntly/port/type.h" +#include <vector> +#include <map> + +#include "sfntly/port/refcount.h" +#include "sfntly/table/subtable.h" +#include "sfntly/table/subtable_container_table.h" + +namespace sfntly { + +// CMap subtable formats +struct CMapFormat { + enum { + kFormat0 = 0, + kFormat2 = 2, + kFormat4 = 4, + kFormat6 = 6, + kFormat8 = 8, + kFormat10 = 10, + kFormat12 = 12, + kFormat13 = 13, + kFormat14 = 14 + }; +}; + +// A CMap table +class CMapTable : public SubTableContainerTable, public RefCounted<CMapTable> { +public: + // CMapTable::CMapId + struct CMapId { + int32_t platform_id; + int32_t encoding_id; + bool operator==(const CMapId& obj) const { + return platform_id == obj.platform_id && encoding_id == obj.encoding_id; + } + }; + static CMapId WINDOWS_BMP; + static CMapId WINDOWS_UCS4; + static CMapId MAC_ROMAN; + + // CMapTable::CMapIdComparator + class CMapIdComparator { + public: + bool operator()(const CMapId& lhs, const CMapId& rhs) const; + }; + + // A filter on cmap + // CMapTable::CMapFilter + class CMapFilter { + public: + // Test on whether the cmap is acceptable or not + // @param cmap_id the id of the cmap + // @return true if the cmap is acceptable; false otherwise + virtual bool accept(const CMapId& cmap_id) const = 0; + // Make gcc -Wnon-virtual-dtor happy. + virtual ~CMapFilter() {} + }; + + // Filters CMaps by CMapId to implement CMapTable::get() + // wanted_id is the CMap we'd like to find. + // We compare the current CMap to it either by equality (==) or using a + // comparator. + // CMapTable::CMapIdFilter + class CMapIdFilter : public CMapFilter { + public: + explicit CMapIdFilter(const CMapId wanted_id); + CMapIdFilter(const CMapId wanted_id, + const CMapIdComparator* comparator); + ~CMapIdFilter() {} + virtual bool accept(const CMapId& cmap_id) const; + private: + CMapIdFilter& operator=(const CMapIdFilter& that); + const CMapId wanted_id_; + const CMapIdComparator *comparator_; + }; + + // The abstract base class for all cmaps. + // + // CMap equality is based on the equality of the (@link {@link CMapId} that + // defines the CMap. In the cmap table for a font there can only be one cmap + // with a given cmap id (pair of platform and encoding ids) no matter what the + // type of the cmap is. + // + // The cmap offers CharacterIterator to allow iteration over + // characters that are mapped by the cmap. This iteration mostly returns the + // characters mapped by the cmap. It will return all characters mapped by the + // cmap to anything but .notdef <b>but</b> it may return some that are not + // mapped or are mapped to .notdef. Various cmap tables provide ranges and + // such to describe characters for lookup but without going the full way to + // mapping to the glyph id it isn't always possible to tell if a character + // will end up with a valid glyph id. So, some of the characters returned from + // the Iterator may still end up pointing to the .notdef glyph. However, the + // number of such characters should be small in most cases with well designed + // cmaps. + class Builder; + class CMap : public SubTable { + public: + // CMapTable::CMap::Builder + class Builder : public SubTable::Builder { + public: + virtual ~Builder(); + + CALLER_ATTACH static Builder* + GetBuilder(ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id); + CALLER_ATTACH static Builder* + GetBuilder(int32_t format, + const CMapId& cmap_id); + + // Note: yes, an object is returned on stack since it's small enough. + virtual CMapId cmap_id() { return cmap_id_; } + virtual int32_t platform_id() { return cmap_id_.platform_id; } + virtual int32_t encoding_id() { return cmap_id_.encoding_id; } + virtual int32_t format() { return format_; } + virtual int32_t language() { return language_; } + virtual void set_language(int32_t language) { language_ = language; } + + protected: + Builder(ReadableFontData* data, + int32_t format, + const CMapId& cmap_id); + Builder(WritableFontData* data, + int32_t format, + const CMapId& cmap_id); + + virtual int32_t SubSerialize(WritableFontData* new_data); + virtual bool SubReadyToSerialize(); + virtual int32_t SubDataSizeToSerialize(); + virtual void SubDataSet(); + + private: + int32_t format_; + CMapId cmap_id_; + int32_t language_; + + friend class CMapTable::Builder; + }; + // Abstract CMap character iterator + // The fully qualified name is CMapTable::CMap::CharacterIterator + class CharacterIterator { + public: + virtual ~CharacterIterator() {} + virtual bool HasNext() = 0; + // Returns -1 if there are no more characters to iterate through + // and exceptions are turned off + virtual int32_t Next() = 0; + + protected: + // Use the CMap::Iterator method below instead of directly requesting + // a CharacterIterator. + CharacterIterator() {} + }; + + CMap(ReadableFontData* data, int32_t format, const CMapId& cmap_id); + virtual ~CMap(); + + virtual CMap::CharacterIterator* Iterator() = 0; + + virtual int32_t format() { return format_; } + virtual CMapId cmap_id() { return cmap_id_; } + virtual int32_t platform_id() { return cmap_id_.platform_id; } + virtual int32_t encoding_id() { return cmap_id_.encoding_id; } + + // Get the language of the cmap. + // + // Note on the language field in 'cmap' subtables: The language field must + // be set to zero for all cmap subtables whose platform IDs are other than + // Macintosh (platform ID 1). For cmap subtables whose platform IDs are + // Macintosh, set this field to the Macintosh language ID of the cmap + // subtable plus one, or to zero if the cmap subtable is not + // language-specific. For example, a Mac OS Turkish cmap subtable must set + // this field to 18, since the Macintosh language ID for Turkish is 17. A + // Mac OS Roman cmap subtable must set this field to 0, since Mac OS Roman + // is not a language-specific encoding. + // + // @return the language id + virtual int32_t Language() = 0; + + // Gets the glyph id for the character code provided. + // The character code provided must be in the encoding used by the cmap + // table. + virtual int32_t GlyphId(int32_t character) = 0; + + private: + int32_t format_; + CMapId cmap_id_; + }; + typedef Ptr<CMap> CMapPtr; + typedef Ptr<CMap::Builder> CMapBuilderPtr; + typedef std::map<CMapId, CMapBuilderPtr, CMapIdComparator> CMapBuilderMap; + + // A cmap format 0 sub table + class CMapFormat0 : public CMap, public RefCounted<CMapFormat0> { + public: + // The fully qualified name is CMapTable::CMapFormat0::Builder + class Builder : public CMap::Builder, + public RefCounted<Builder> { + public: + CALLER_ATTACH static Builder* NewInstance(ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id); + CALLER_ATTACH static Builder* NewInstance(WritableFontData* data, + int32_t offset, + const CMapId& cmap_id); + CALLER_ATTACH static Builder* NewInstance(const CMapId& cmap_id); + virtual ~Builder(); + + protected: + virtual CALLER_ATTACH FontDataTable* + SubBuildTable(ReadableFontData* data); + + private: + // When creating a new CMapFormat0 Builder, use NewInstance instead of + // the constructors! This avoids a memory leak when slicing the FontData. + Builder(ReadableFontData* data, int32_t offset, const CMapId& cmap_id); + Builder(WritableFontData* data, int32_t offset, const CMapId& cmap_id); + Builder(const CMapId& cmap_id); + }; + + // The fully qualified name is CMapTable::CMapFormat0::CharacterIterator + class CharacterIterator : public CMap::CharacterIterator { + public: + virtual ~CharacterIterator(); + virtual bool HasNext(); + virtual int32_t Next(); + + private: + CharacterIterator(int32_t start, int32_t end); + friend class CMapFormat0; + int32_t character_, max_character_; + }; + + virtual ~CMapFormat0(); + virtual int32_t Language(); + virtual int32_t GlyphId(int32_t character); + CMap::CharacterIterator* Iterator(); + + private: + CMapFormat0(ReadableFontData* data, const CMapId& cmap_id); + }; + + // A cmap format 2 sub table + // The format 2 cmap is used for multi-byte encodings such as SJIS, + // EUC-JP/KR/CN, Big5, etc. + class CMapFormat2 : public CMap, public RefCounted<CMapFormat2> { + public: + // CMapTable::CMapFormat2::Builder + class Builder : public CMap::Builder, + public RefCounted<Builder> { + public: + Builder(ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id); + Builder(WritableFontData* data, + int32_t offset, + const CMapId& cmap_id); + virtual ~Builder(); + + protected: + virtual CALLER_ATTACH FontDataTable* + SubBuildTable(ReadableFontData* data); + }; + // CMapTable::CMapFormat2::CharacterIterator + class CharacterIterator : public CMap::CharacterIterator { + public: + virtual ~CharacterIterator(); + virtual bool hasNext(); + virtual int32_t next(); + + private: + CharacterIterator(); + }; + + virtual int32_t Language(); + virtual int32_t GlyphId(int32_t character); + + // Returns how many bytes would be consumed by a lookup of this character + // with this cmap. This comes about because the cmap format 2 table is + // designed around multi-byte encodings such as SJIS, EUC-JP, Big5, etc. + // return the number of bytes consumed from this "character" - either 1 or 2 + virtual int32_t BytesConsumed(int32_t character); + + virtual ~CMapFormat2(); + + private: + CMapFormat2(ReadableFontData* data, const CMapId& cmap_id); + + int32_t SubHeaderOffset(int32_t sub_header_index); + int32_t FirstCode(int32_t sub_header_index); + int32_t EntryCount(int32_t sub_header_index); + int32_t IdRangeOffset(int32_t sub_header_index); + int32_t IdDelta(int32_t sub_header_index); + CMap::CharacterIterator* Iterator(); + }; + + // CMapTable::CMapFormat4 + class CMapFormat4 : public CMap, + public RefCounted<CMapFormat4> { + public: + // CMapTable::CMapFormat4::Builder + class Builder : public CMap::Builder, + public RefCounted<Builder> { + public: + // CMapTable::CMapFormat4::Builder::Segment + class Segment : public RefCounted<Segment> { + public: + Segment(); + explicit Segment(Segment* other); + Segment(int32_t start_count, + int32_t end_count, + int32_t id_delta, + int32_t id_range_offset); + ~Segment(); + + // @return the startCount + int32_t start_count(); + // @param startCount the startCount to set + void set_start_count(int32_t start_count); + // @return the endCount + int32_t end_count(); + // @param endcount the endCount to set + void set_end_count(int32_t end_count); + // @return the idDelta + int32_t id_delta(); + // @param idDelta the idDelta to set + void set_id_delta(int32_t id_delta); + // @return the idRangeOffset + int32_t id_range_offset(); + // @param idRangeOffset the idRangeOffset to set + void set_id_range_offset(int32_t id_range_offset); + + static CALLER_ATTACH + std::vector<Ptr<Segment> >* + DeepCopy(std::vector<Ptr<Segment> >* original); + + private: + int32_t start_count_; + int32_t end_count_; + int32_t id_delta_; + int32_t id_range_offset_; + }; + typedef std::vector<Ptr<Segment> > SegmentList; + + static CALLER_ATTACH Builder* NewInstance(WritableFontData* data, + int32_t offset, + const CMapId& cmap_id); + static CALLER_ATTACH Builder* NewInstance(ReadableFontData* data, + int32_t offset, + const CMapId& cmap_id); + static CALLER_ATTACH Builder* NewInstance(const CMapId& cmap_id); + virtual ~Builder(); + SegmentList* segments(); + void set_segments(SegmentList* segments); + std::vector<int32_t>* glyph_id_array(); + void set_glyph_id_array(std::vector<int32_t>* glyph_id_array); + + protected: + Builder(WritableFontData* data, int32_t offset, const CMapId& cmap_id); + Builder(ReadableFontData* data, int32_t offset, const CMapId& cmap_id); + Builder(SegmentList* segments, std::vector<int32_t>* glyph_id_array, + const CMapId& cmap_id); + explicit Builder(const CMapId& cmap_id); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable( + ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + private: + void Initialize(ReadableFontData* data); + + SegmentList segments_; + std::vector<int32_t> glyph_id_array_; + }; + + CMap::CharacterIterator* Iterator(); + // CMapTable::CMapFormat4::CharacterIterator + class CharacterIterator : public CMap::CharacterIterator { + public: + bool HasNext(); + int32_t Next(); + virtual ~CharacterIterator() {} + + private: + explicit CharacterIterator(CMapFormat4 *parent); + friend CMap::CharacterIterator* CMapFormat4::Iterator(); + + CMapFormat4* parent_; + int32_t segment_index_; + int32_t first_char_in_segment_; + int32_t last_char_in_segment_; + int32_t next_char_; + bool next_char_set_; + }; + + virtual int32_t GlyphId(int32_t character); + + // Lower level glyph code retrieval that requires processing the Format 4 + // segments to use. + // @param segment the cmap segment + // @param startCode the start code for the segment + // @param character the character to be looked up + // @return the glyph id for the character; CMapTable.NOTDEF if not found + int32_t RetrieveGlyphId(int32_t segment, + int32_t start_count, + int32_t character); + virtual int32_t Language(); + + // Get the count of the number of segments in this cmap. + // @return the number of segments + int32_t seg_count(); + int32_t Length(); + // Get the start code for a segment. + // @param segment the segment in the lookup table + // @return the start code for a segment + int32_t StartCode(int32_t segment); + // Get the end code for a segment. + // @param segment the segment in the look up table + // @return the end code for the segment + int32_t EndCode(int32_t segment); + // Get the id delta for a segment + // @param segment the segment in the look up table + // @return the id delta for the segment + int32_t IdDelta(int32_t segment); + // Get the id range offset for a segment + // @param segment the segment in the look up table + // @return the id range offset for the segment + int32_t IdRangeOffset(int32_t segment); + // Get the location of the id range offset for a segment + // @param segment the segment in the look up table + // @return the location of the id range offset for the segment + int32_t IdRangeOffsetLocation(int32_t segment); + // Declared above to allow friending inside CharacterIterator class. + // CMap::CharacterIterator* Iterator(); + virtual ~CMapFormat4(); + + protected: + CMapFormat4(ReadableFontData* data, const CMapId& cmap_id); + + private: + static int32_t Language(ReadableFontData* data); + static int32_t Length(ReadableFontData* data); + static int32_t SegCount(ReadableFontData* data); + static int32_t StartCode(ReadableFontData* data, + int32_t seg_count, + int32_t index); + static int32_t StartCodeOffset(int32_t seg_count); + static int32_t EndCode(ReadableFontData* data, + int32_t seg_count, + int32_t index); + static int32_t IdDelta(ReadableFontData* data, + int32_t seg_count, + int32_t index); + static int32_t IdDeltaOffset(int32_t seg_count); + static int32_t IdRangeOffset(ReadableFontData* data, + int32_t seg_count, + int32_t index); + static int32_t IdRangeOffsetOffset(int32_t seg_count); + static int32_t GlyphIdArrayOffset(int32_t seg_count); + // Refactored void to bool to work without exceptions. + bool IsValidIndex(int32_t segment); + int32_t GlyphIdArray(int32_t index); + + int32_t seg_count_; + int32_t start_code_offset_; + int32_t id_delta_offset_; + int32_t glyph_id_array_offset_; + }; + + // CMapTable::Builder + class Builder : public SubTableContainerTable::Builder, + public RefCounted<Builder> { + public: + // Constructor scope is public because C++ does not allow base class to + // instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + + virtual int32_t SubSerialize(WritableFontData* new_data); + virtual bool SubReadyToSerialize(); + virtual int32_t SubDataSizeToSerialize(); + virtual void SubDataSet(); + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + CMap::Builder* NewCMapBuilder(const CMapId& cmap_id, + ReadableFontData* data); + // Create a new empty CMapBuilder of the type specified in the id. + CMap::Builder* NewCMapBuilder(int32_t format, const CMapId& cmap_id); + CMap::Builder* CMapBuilder(const CMapId& cmap_id); + + int32_t NumCMaps(); + void SetVersion(int32_t version); + + CMapBuilderMap* GetCMapBuilders(); + + protected: + static CALLER_ATTACH CMap::Builder* CMapBuilder(ReadableFontData* data, + int32_t index); + + private: + void Initialize(ReadableFontData* data); + static int32_t NumCMaps(ReadableFontData* data); + + int32_t version_; + CMapBuilderMap cmap_builders_; + }; + typedef Ptr<Builder> CMapTableBuilderPtr; + + class CMapIterator { + public: + // If filter is NULL, filter through all tables. + CMapIterator(CMapTable* table, const CMapFilter* filter); + bool HasNext(); + CMap* Next(); + + private: + int32_t table_index_; + const CMapFilter* filter_; + CMapTable* table_; + }; + + // Make a CMapId from a platform_id, encoding_id pair + static CMapId NewCMapId(int32_t platform_id, int32_t encoding_id); + // Make a CMapId from another CMapId + static CMapId NewCMapId(const CMapId& obj); + + // Get the CMap with the specified parameters if it exists. + // Returns NULL otherwise. + CALLER_ATTACH CMap* GetCMap(const int32_t index); + CALLER_ATTACH CMap* GetCMap(const int32_t platform_id, + const int32_t encoding_id); + CALLER_ATTACH CMap* GetCMap(const CMapId GetCMap_id); + + // Get the table version. + virtual int32_t Version(); + + // Get the number of cmaps within the CMap table. + virtual int32_t NumCMaps(); + + // Get the cmap id for the cmap with the given index. + // Note: yes, an object is returned on stack since it's small enough. + // This function is renamed from cmapId to GetCMapId(). + virtual CMapId GetCMapId(int32_t index); + + virtual int32_t PlatformId(int32_t index); + virtual int32_t EncodingId(int32_t index); + + // Get the offset in the table data for the cmap table with the given index. + // The offset is from the beginning of the table. + virtual int32_t Offset(int32_t index); + + virtual ~CMapTable(); + + static const int32_t NOTDEF; + + private: + // Offsets to specific elements in the underlying data. These offsets are + // relative to the start of the table or the start of sub-blocks within + // the table. + struct Offset { + enum { + kVersion = 0, + kNumTables = 2, + kEncodingRecordStart = 4, + + // offsets relative to the encoding record + kEncodingRecordPlatformId = 0, + kEncodingRecordEncodingId = 2, + kEncodingRecordOffset = 4, + kEncodingRecordSize = 8, + + kFormat = 0, + + // Format 0: Byte encoding table + kFormat0Format = 0, + kFormat0Length = 2, + kFormat0Language = 4, + kFormat0GlyphIdArray = 6, + + // Format 2: High-byte mapping through table + kFormat2Format = 0, + kFormat2Length = 2, + kFormat2Language = 4, + kFormat2SubHeaderKeys = 6, + kFormat2SubHeaders = 518, + // offset relative to the subHeader structure + kFormat2SubHeader_firstCode = 0, + kFormat2SubHeader_entryCount = 2, + kFormat2SubHeader_idDelta = 4, + kFormat2SubHeader_idRangeOffset = 6, + kFormat2SubHeader_structLength = 8, + + // Format 4: Segment mapping to delta values + kFormat4Format = 0, + kFormat4Length = 2, + kFormat4Language = 4, + kFormat4SegCountX2 = 6, + kFormat4SearchRange = 8, + kFormat4EntrySelector = 10, + kFormat4RangeShift = 12, + kFormat4EndCount = 14, + kFormat4FixedSize = 16, + + // format 6: Trimmed table mapping + kFormat6Format = 0, + kFormat6Length = 2, + kFormat6Language = 4, + kFormat6FirstCode = 6, + kFormat6EntryCount = 8, + kFormat6GlyphIdArray = 10, + + // Format 8: mixed 16-bit and 32-bit coverage + kFormat8Format = 0, + kFormat8Length = 4, + kFormat8Language = 8, + kFormat8Is32 = 12, + kFormat8nGroups204 = 8204, + kFormat8Groups208 = 8208, + // offset relative to the group structure + kFormat8Group_startCharCode = 0, + kFormat8Group_endCharCode = 4, + kFormat8Group_startGlyphId = 8, + kFormat8Group_structLength = 12, + + // Format 10: Trimmed array + kFormat10Format = 0, + kFormat10Length = 4, + kFormat10Language = 8, + kFormat10StartCharCode = 12, + kFormat10NumChars = 16, + kFormat10Glyphs0 = 20, + + // Format 12: Segmented coverage + kFormat12Format = 0, + kFormat12Length = 4, + kFormat12Language = 8, + kFormat12nGroups = 12, + kFormat12Groups = 16, + kFormat12Groups_structLength = 12, + // offsets within the group structure + kFormat12_startCharCode = 0, + kFormat12_endCharCode = 4, + kFormat12_startGlyphId = 8, + + // Format 13: Last Resort Font + kFormat13Format = 0, + kFormat13Length = 4, + kFormat13Language = 8, + kFormat13nGroups = 12, + kFormat13Groups = 16, + kFormat13Groups_structLength = 12, + // offsets within the group structure + kFormat13_startCharCode = 0, + kFormat13_endCharCode = 4, + kFormat13_glyphId = 8, + + // Format 14: Unicode Variation Sequences + kFormat14Format = 0, + kFormat14Length = 2, + + // TODO(stuartg): finish tables + // Default UVS Table + + // Non-default UVS Table + kLast = -1 + }; + }; + + CMapTable(Header* header, ReadableFontData* data); + + // Get the offset in the table data for the encoding record for the cmap with + // the given index. The offset is from the beginning of the table. + static int32_t OffsetForEncodingRecord(int32_t index); +}; +typedef std::vector<CMapTable::CMapId> CMapIdList; +typedef Ptr<CMapTable> CMapTablePtr; +typedef std::vector<Ptr<CMapTable::CMapFormat4::Builder::Segment> > SegmentList; +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/font_header_table.cc b/gfx/sfntly/cpp/src/sfntly/table/core/font_header_table.cc new file mode 100644 index 0000000000..e089c7e9ba --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/font_header_table.cc @@ -0,0 +1,268 @@ +/* + * 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 "sfntly/table/core/font_header_table.h" + +namespace sfntly { +/****************************************************************************** + * FontHeaderTable class + ******************************************************************************/ +FontHeaderTable::~FontHeaderTable() {} + +int32_t FontHeaderTable::TableVersion() { + return data_->ReadFixed(Offset::kTableVersion); +} + +int32_t FontHeaderTable::FontRevision() { + return data_->ReadFixed(Offset::kFontRevision); +} + +int64_t FontHeaderTable::ChecksumAdjustment() { + return data_->ReadULong(Offset::kCheckSumAdjustment); +} + +int64_t FontHeaderTable::MagicNumber() { + return data_->ReadULong(Offset::kMagicNumber); +} + +int32_t FontHeaderTable::FlagsAsInt() { + return data_->ReadUShort(Offset::kFlags); +} + +int32_t FontHeaderTable::UnitsPerEm() { + return data_->ReadUShort(Offset::kUnitsPerEm); +} + +int64_t FontHeaderTable::Created() { + return data_->ReadDateTimeAsLong(Offset::kCreated); +} + +int64_t FontHeaderTable::Modified() { + return data_->ReadDateTimeAsLong(Offset::kModified); +} + +int32_t FontHeaderTable::XMin() { + return data_->ReadUShort(Offset::kXMin); +} + +int32_t FontHeaderTable::YMin() { + return data_->ReadUShort(Offset::kYMin); +} + +int32_t FontHeaderTable::XMax() { + return data_->ReadUShort(Offset::kXMax); +} + +int32_t FontHeaderTable::YMax() { + return data_->ReadUShort(Offset::kYMax); +} + +int32_t FontHeaderTable::MacStyleAsInt() { + return data_->ReadUShort(Offset::kMacStyle); +} + +int32_t FontHeaderTable::LowestRecPPEM() { + return data_->ReadUShort(Offset::kLowestRecPPEM); +} + +int32_t FontHeaderTable::FontDirectionHint() { + return data_->ReadShort(Offset::kFontDirectionHint); +} + +int32_t FontHeaderTable::IndexToLocFormat() { + return data_->ReadShort(Offset::kIndexToLocFormat); +} + +int32_t FontHeaderTable::GlyphDataFormat() { + return data_->ReadShort(Offset::kGlyphDataFormat); +} + +FontHeaderTable::FontHeaderTable(Header* header, ReadableFontData* data) + : Table(header, data) { + std::vector<int32_t> checksum_ranges; + checksum_ranges.push_back(0); + checksum_ranges.push_back(Offset::kCheckSumAdjustment); + checksum_ranges.push_back(Offset::kMagicNumber); + data_->SetCheckSumRanges(checksum_ranges); +} + +/****************************************************************************** + * FontHeaderTable::Builder class + ******************************************************************************/ +FontHeaderTable::Builder::Builder(Header* header, WritableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +FontHeaderTable::Builder::Builder(Header* header, ReadableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +FontHeaderTable::Builder::~Builder() {} + +CALLER_ATTACH FontDataTable* FontHeaderTable::Builder::SubBuildTable( + ReadableFontData* data) { + FontDataTablePtr table = new FontHeaderTable(header(), data); + return table.Detach(); +} + +int32_t FontHeaderTable::Builder::TableVersion() { + return down_cast<FontHeaderTable*>(GetTable())->TableVersion(); +} + +void FontHeaderTable::Builder::SetTableVersion(int32_t version) { + InternalWriteData()->WriteFixed(Offset::kTableVersion, version); +} + +int32_t FontHeaderTable::Builder::FontRevision() { + return down_cast<FontHeaderTable*>(GetTable())->FontRevision(); +} + +void FontHeaderTable::Builder::SetFontRevision(int32_t revision) { + InternalWriteData()->WriteFixed(Offset::kFontRevision, revision); +} + +int64_t FontHeaderTable::Builder::ChecksumAdjustment() { + return down_cast<FontHeaderTable*>(GetTable())->ChecksumAdjustment(); +} + +void FontHeaderTable::Builder::SetChecksumAdjustment(int64_t adjustment) { + InternalWriteData()->WriteULong(Offset::kCheckSumAdjustment, adjustment); +} + +int64_t FontHeaderTable::Builder::MagicNumber() { + return down_cast<FontHeaderTable*>(GetTable())->MagicNumber(); +} + +void FontHeaderTable::Builder::SetMagicNumber(int64_t magic_number) { + InternalWriteData()->WriteULong(Offset::kMagicNumber, magic_number); +} + +int32_t FontHeaderTable::Builder::FlagsAsInt() { + return down_cast<FontHeaderTable*>(GetTable())->FlagsAsInt(); +} + +void FontHeaderTable::Builder::SetFlagsAsInt(int32_t flags) { + InternalWriteData()->WriteUShort(Offset::kFlags, flags); +} + +int32_t FontHeaderTable::Builder::UnitsPerEm() { + return down_cast<FontHeaderTable*>(GetTable())->UnitsPerEm(); +} + +void FontHeaderTable::Builder::SetUnitsPerEm(int32_t units) { + InternalWriteData()->WriteUShort(Offset::kUnitsPerEm, units); +} + +int64_t FontHeaderTable::Builder::Created() { + return down_cast<FontHeaderTable*>(GetTable())->Created(); +} + +void FontHeaderTable::Builder::SetCreated(int64_t date) { + InternalWriteData()->WriteDateTime(Offset::kCreated, date); +} + +int64_t FontHeaderTable::Builder::Modified() { + return down_cast<FontHeaderTable*>(GetTable())->Modified(); +} + +void FontHeaderTable::Builder::SetModified(int64_t date) { + InternalWriteData()->WriteDateTime(Offset::kModified, date); +} + +int32_t FontHeaderTable::Builder::XMin() { + return down_cast<FontHeaderTable*>(GetTable())->XMin(); +} + +void FontHeaderTable::Builder::SetXMin(int32_t xmin) { + InternalWriteData()->WriteShort(Offset::kXMin, xmin); +} + +int32_t FontHeaderTable::Builder::YMin() { + return down_cast<FontHeaderTable*>(GetTable())->YMin(); +} + +void FontHeaderTable::Builder::SetYMin(int32_t ymin) { + InternalWriteData()->WriteShort(Offset::kYMin, ymin); +} + +int32_t FontHeaderTable::Builder::XMax() { + return down_cast<FontHeaderTable*>(GetTable())->XMax(); +} + +void FontHeaderTable::Builder::SetXMax(int32_t xmax) { + InternalWriteData()->WriteShort(Offset::kXMax, xmax); +} + +int32_t FontHeaderTable::Builder::YMax() { + return down_cast<FontHeaderTable*>(GetTable())->YMax(); +} + +void FontHeaderTable::Builder::SetYMax(int32_t ymax) { + InternalWriteData()->WriteShort(Offset::kYMax, ymax); +} + +int32_t FontHeaderTable::Builder::MacStyleAsInt() { + return down_cast<FontHeaderTable*>(GetTable())->MacStyleAsInt(); +} + +void FontHeaderTable::Builder::SetMacStyleAsInt(int32_t style) { + InternalWriteData()->WriteUShort(Offset::kMacStyle, style); +} + +int32_t FontHeaderTable::Builder::LowestRecPPEM() { + return down_cast<FontHeaderTable*>(GetTable())->LowestRecPPEM(); +} + +void FontHeaderTable::Builder::SetLowestRecPPEM(int32_t size) { + InternalWriteData()->WriteUShort(Offset::kLowestRecPPEM, size); +} + +int32_t FontHeaderTable::Builder::FontDirectionHint() { + return down_cast<FontHeaderTable*>(GetTable())->FontDirectionHint(); +} + +void FontHeaderTable::Builder::SetFontDirectionHint(int32_t hint) { + InternalWriteData()->WriteShort(Offset::kFontDirectionHint, hint); +} + +int32_t FontHeaderTable::Builder::IndexToLocFormat() { + Table* table = GetTable(); + if (!table) + return IndexToLocFormat::kInvalidOffset; + return down_cast<FontHeaderTable*>(table)->IndexToLocFormat(); +} + +void FontHeaderTable::Builder::SetIndexToLocFormat(int32_t format) { + InternalWriteData()->WriteShort(Offset::kIndexToLocFormat, format); +} + +int32_t FontHeaderTable::Builder::GlyphDataFormat() { + return down_cast<FontHeaderTable*>(GetTable())->GlyphDataFormat(); +} + +void FontHeaderTable::Builder::SetGlyphDataFormat(int32_t format) { + InternalWriteData()->WriteShort(Offset::kGlyphDataFormat, format); +} + +CALLER_ATTACH FontHeaderTable::Builder* + FontHeaderTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr<FontHeaderTable::Builder> builder; + builder = new FontHeaderTable::Builder(header, data); + return builder.Detach(); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/font_header_table.h b/gfx/sfntly/cpp/src/sfntly/table/core/font_header_table.h new file mode 100644 index 0000000000..4851775dc0 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/font_header_table.h @@ -0,0 +1,169 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_FONT_HEADER_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_FONT_HEADER_TABLE_H_ + +#include "sfntly/table/table.h" +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +struct IndexToLocFormat { + enum { + kInvalidOffset = -1, + kShortOffset = 0, + kLongOffset = 1 + }; +}; + +struct FontDirectionHint { + enum { + kFullyMixed = 0, + kOnlyStrongLTR = 1, + kStrongLTRAndNeutral = 2, + kOnlyStrongRTL = -1, + kStrongRTLAndNeutral = -2 + }; +}; + +class FontHeaderTable : public Table, public RefCounted<FontHeaderTable> { + public: + class Builder : public TableBasedTableBuilder, public RefCounted<Builder> { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + virtual int32_t TableVersion(); + virtual void SetTableVersion(int32_t version); + virtual int32_t FontRevision(); + virtual void SetFontRevision(int32_t revision); + virtual int64_t ChecksumAdjustment(); + virtual void SetChecksumAdjustment(int64_t adjustment); + virtual int64_t MagicNumber(); + virtual void SetMagicNumber(int64_t magic_number); + virtual int32_t FlagsAsInt(); + virtual void SetFlagsAsInt(int32_t flags); + // TODO(arthurhsu): IMPLEMENT EnumSet<Flags> Flags() + // TODO(arthurhsu): IMPLEMENT setFlags(EnumSet<Flags> flags) + virtual int32_t UnitsPerEm(); + virtual void SetUnitsPerEm(int32_t units); + virtual int64_t Created(); + virtual void SetCreated(int64_t date); + virtual int64_t Modified(); + virtual void SetModified(int64_t date); + virtual int32_t XMin(); + virtual void SetXMin(int32_t xmin); + virtual int32_t YMin(); + virtual void SetYMin(int32_t ymin); + virtual int32_t XMax(); + virtual void SetXMax(int32_t xmax); + virtual int32_t YMax(); + virtual void SetYMax(int32_t ymax); + virtual int32_t MacStyleAsInt(); + virtual void SetMacStyleAsInt(int32_t style); + // TODO(arthurhsu): IMPLEMENT EnumSet<MacStyle> macStyle() + // TODO(arthurhsu): IMPLEMENT setMacStyle(EnumSet<MacStyle> style) + virtual int32_t LowestRecPPEM(); + virtual void SetLowestRecPPEM(int32_t size); + virtual int32_t FontDirectionHint(); + virtual void SetFontDirectionHint(int32_t hint); + virtual int32_t IndexToLocFormat(); + virtual void SetIndexToLocFormat(int32_t format); + virtual int32_t GlyphDataFormat(); + virtual void SetGlyphDataFormat(int32_t format); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + }; + + virtual ~FontHeaderTable(); + int32_t TableVersion(); + int32_t FontRevision(); + + // Get the checksum adjustment. To compute: set it to 0, sum the entire font + // as ULONG, then store 0xB1B0AFBA - sum. + int64_t ChecksumAdjustment(); + + // Get the magic number. Set to 0x5F0F3CF5. + int64_t MagicNumber(); + + // TODO(arthurhsu): IMPLEMENT: EnumSet<Flags> + int32_t FlagsAsInt(); + // TODO(arthurhsu): IMPLEMENT: Flags() returning EnumSet<Flags> + + int32_t UnitsPerEm(); + + // Get the created date. Number of seconds since 12:00 midnight, January 1, + // 1904. 64-bit integer. + int64_t Created(); + // Get the modified date. Number of seconds since 12:00 midnight, January 1, + // 1904. 64-bit integer. + int64_t Modified(); + + // Get the x min. For all glyph bounding boxes. + int32_t XMin(); + // Get the y min. For all glyph bounding boxes. + int32_t YMin(); + // Get the x max. For all glyph bounding boxes. + int32_t XMax(); + // Get the y max. For all glyph bounding boxes. + int32_t YMax(); + + // TODO(arthurhsu): IMPLEMENT: EnumSet<MacStyle> + int32_t MacStyleAsInt(); + // TODO(arthurhsu): IMPLEMENT: macStyle() returning EnumSet<MacStyle> + + int32_t LowestRecPPEM(); + int32_t FontDirectionHint(); // Note: no AsInt() form, already int + int32_t IndexToLocFormat(); // Note: no AsInt() form, already int + int32_t GlyphDataFormat(); + + private: + struct Offset { + enum { + kTableVersion = 0, + kFontRevision = 4, + kCheckSumAdjustment = 8, + kMagicNumber = 12, + kFlags = 16, + kUnitsPerEm = 18, + kCreated = 20, + kModified = 28, + kXMin = 36, + kYMin = 38, + kXMax = 40, + kYMax = 42, + kMacStyle = 44, + kLowestRecPPEM = 46, + kFontDirectionHint = 48, + kIndexToLocFormat = 50, + kGlyphDataFormat = 52 + }; + }; + + FontHeaderTable(Header* header, ReadableFontData* data); +}; +typedef Ptr<FontHeaderTable> FontHeaderTablePtr; +typedef Ptr<FontHeaderTable::Builder> FontHeaderTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_FONT_HEADER_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_device_metrics_table.cc b/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_device_metrics_table.cc new file mode 100644 index 0000000000..50b0cf579d --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_device_metrics_table.cc @@ -0,0 +1,124 @@ +/* + * 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 "sfntly/table/core/horizontal_device_metrics_table.h" + +namespace sfntly { +/****************************************************************************** + * HorizontalDeviceMetricsTable class + ******************************************************************************/ +HorizontalDeviceMetricsTable:: ~HorizontalDeviceMetricsTable() {} + +int32_t HorizontalDeviceMetricsTable::Version() { + return data_->ReadUShort(Offset::kVersion); +} + +int32_t HorizontalDeviceMetricsTable::NumRecords() { + return data_->ReadShort(Offset::kNumRecords); +} + +int32_t HorizontalDeviceMetricsTable::RecordSize() { + return data_->ReadLong(Offset::kSizeDeviceRecord); +} + +int32_t HorizontalDeviceMetricsTable::PixelSize(int32_t record_index) { + if (record_index < 0 || record_index >= NumRecords()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException(); +#endif + return -1; + } + return data_->ReadUByte(Offset::kRecords + record_index * RecordSize() + + Offset::kDeviceRecordPixelSize); +} + +int32_t HorizontalDeviceMetricsTable::MaxWidth(int32_t record_index) { + if (record_index < 0 || record_index >= NumRecords()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException(); +#endif + return -1; + } + return data_->ReadUByte(Offset::kRecords + record_index * RecordSize() + + Offset::kDeviceRecordMaxWidth); +} + +int32_t HorizontalDeviceMetricsTable::Width(int32_t record_index, + int32_t glyph_num) { + if (record_index < 0 || record_index >= NumRecords() || + glyph_num < 0 || glyph_num >= num_glyphs_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException(); +#endif + return -1; + } + return data_->ReadUByte(Offset::kRecords + record_index * RecordSize() + + Offset::kDeviceRecordWidths + glyph_num); +} + +HorizontalDeviceMetricsTable::HorizontalDeviceMetricsTable( + Header* header, + ReadableFontData* data, + int32_t num_glyphs) + : Table(header, data), num_glyphs_(num_glyphs) { +} + +/****************************************************************************** + * HorizontalDeviceMetricsTable::Builder class + ******************************************************************************/ +HorizontalDeviceMetricsTable::Builder::Builder(Header* header, + WritableFontData* data) + : TableBasedTableBuilder(header, data), num_glyphs_(-1) { +} + +HorizontalDeviceMetricsTable::Builder::Builder(Header* header, + ReadableFontData* data) + : TableBasedTableBuilder(header, data), num_glyphs_(-1) { +} + +HorizontalDeviceMetricsTable::Builder::~Builder() {} + +CALLER_ATTACH FontDataTable* +HorizontalDeviceMetricsTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new HorizontalDeviceMetricsTable(header(), data, + num_glyphs_); + return table.Detach(); +} + +void HorizontalDeviceMetricsTable::Builder::SetNumGlyphs(int32_t num_glyphs) { + if (num_glyphs < 0) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalArgumentException("Number of glyphs can't be negative."); +#endif + return; + } + num_glyphs_ = num_glyphs; + HorizontalDeviceMetricsTable* table = + down_cast<HorizontalDeviceMetricsTable*>(GetTable()); + if (table) { + table->num_glyphs_ = num_glyphs; + } +} + +CALLER_ATTACH HorizontalDeviceMetricsTable::Builder* +HorizontalDeviceMetricsTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr<HorizontalDeviceMetricsTable::Builder> builder; + builder = new HorizontalDeviceMetricsTable::Builder(header, data); + return builder.Detach(); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_device_metrics_table.h b/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_device_metrics_table.h new file mode 100644 index 0000000000..4a27ba0964 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_device_metrics_table.h @@ -0,0 +1,82 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_DEVICE_METRICS_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_DEVICE_METRICS_TABLE_H_ + +#include "sfntly/table/table.h" +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +// A Horizontal Device Metrics table - 'hdmx' +class HorizontalDeviceMetricsTable + : public Table, + public RefCounted<HorizontalDeviceMetricsTable> { + public: + class Builder : public TableBasedTableBuilder, public RefCounted<Builder> { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + void SetNumGlyphs(int32_t num_glyphs); + + private: + int32_t num_glyphs_; + }; + + virtual ~HorizontalDeviceMetricsTable(); + + int32_t Version(); + int32_t NumRecords(); + int32_t RecordSize(); + int32_t PixelSize(int32_t record_index); + int32_t MaxWidth(int32_t record_index); + int32_t Width(int32_t record_index, int32_t glyph_num); + + private: + struct Offset { + enum { + kVersion = 0,
+ kNumRecords = 2,
+ kSizeDeviceRecord = 4,
+ kRecords = 8,
+
+ // Offsets within a device record
+ kDeviceRecordPixelSize = 0,
+ kDeviceRecordMaxWidth = 1,
+ kDeviceRecordWidths = 2, + }; + }; + HorizontalDeviceMetricsTable(Header* header, + ReadableFontData* data, + int32_t num_glyphs); + + int32_t num_glyphs_; +}; +typedef Ptr<HorizontalDeviceMetricsTable> HorizontalDeviceMetricsTablePtr; +typedef Ptr<HorizontalDeviceMetricsTable::Builder> + HorizontalDeviceMetricsTableBuilderPtr; +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_DEVICE_METRICS_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_header_table.cc b/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_header_table.cc new file mode 100644 index 0000000000..43c20585d3 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_header_table.cc @@ -0,0 +1,213 @@ +/* + * 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 "sfntly/table/core/horizontal_header_table.h" + +namespace sfntly { +/****************************************************************************** + * HorizontalHeaderTable class + ******************************************************************************/ +HorizontalHeaderTable:: ~HorizontalHeaderTable() {} + +int32_t HorizontalHeaderTable::TableVersion() { + return data_->ReadFixed(Offset::kVersion); +} + +int32_t HorizontalHeaderTable::Ascender() { + return data_->ReadShort(Offset::kAscender); +} + +int32_t HorizontalHeaderTable::Descender() { + return data_->ReadShort(Offset::kDescender); +} + +int32_t HorizontalHeaderTable::LineGap() { + return data_->ReadShort(Offset::kLineGap); +} + +int32_t HorizontalHeaderTable::AdvanceWidthMax() { + return data_->ReadUShort(Offset::kAdvanceWidthMax); +} + +int32_t HorizontalHeaderTable::MinLeftSideBearing() { + return data_->ReadShort(Offset::kMinLeftSideBearing); +} + +int32_t HorizontalHeaderTable::MinRightSideBearing() { + return data_->ReadShort(Offset::kMinRightSideBearing); +} + +int32_t HorizontalHeaderTable::XMaxExtent() { + return data_->ReadShort(Offset::kXMaxExtent); +} + +int32_t HorizontalHeaderTable::CaretSlopeRise() { + return data_->ReadShort(Offset::kCaretSlopeRise); +} + +int32_t HorizontalHeaderTable::CaretSlopeRun() { + return data_->ReadShort(Offset::kCaretSlopeRun); +} + +int32_t HorizontalHeaderTable::CaretOffset() { + return data_->ReadShort(Offset::kCaretOffset); +} + +int32_t HorizontalHeaderTable::MetricDataFormat() { + return data_->ReadShort(Offset::kMetricDataFormat); +} + +int32_t HorizontalHeaderTable::NumberOfHMetrics() { + return data_->ReadUShort(Offset::kNumberOfHMetrics); +} + +HorizontalHeaderTable:: HorizontalHeaderTable(Header* header, + ReadableFontData* data) + : Table(header, data) { +} + +/****************************************************************************** + * HorizontalHeaderTable::Builder class + ******************************************************************************/ +HorizontalHeaderTable::Builder::Builder(Header* header, WritableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +HorizontalHeaderTable::Builder::Builder(Header* header, ReadableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +HorizontalHeaderTable::Builder::~Builder() {} + +CALLER_ATTACH FontDataTable* + HorizontalHeaderTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new HorizontalHeaderTable(header(), data); + return table.Detach(); +} + +CALLER_ATTACH HorizontalHeaderTable::Builder* + HorizontalHeaderTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr<HorizontalHeaderTable::Builder> builder; + builder = new HorizontalHeaderTable::Builder(header, data); + return builder.Detach(); +} + +int32_t HorizontalHeaderTable::Builder::TableVersion() { + return InternalReadData()->ReadFixed(Offset::kVersion); +} + +void HorizontalHeaderTable::Builder::SetTableVersion(int32_t version) { + InternalWriteData()->WriteFixed(Offset::kVersion, version); +} + +int32_t HorizontalHeaderTable::Builder::Ascender() { + return InternalReadData()->ReadShort(Offset::kAscender); +} + +void HorizontalHeaderTable::Builder::SetAscender(int32_t ascender) { + InternalWriteData()->WriteShort(Offset::kVersion, ascender); +} + +int32_t HorizontalHeaderTable::Builder::Descender() { + return InternalReadData()->ReadShort(Offset::kDescender); +} + +void HorizontalHeaderTable::Builder::SetDescender(int32_t descender) { + InternalWriteData()->WriteShort(Offset::kDescender, descender); +} + +int32_t HorizontalHeaderTable::Builder::LineGap() { + return InternalReadData()->ReadShort(Offset::kLineGap); +} + +void HorizontalHeaderTable::Builder::SetLineGap(int32_t line_gap) { + InternalWriteData()->WriteShort(Offset::kLineGap, line_gap); +} + +int32_t HorizontalHeaderTable::Builder::AdvanceWidthMax() { + return InternalReadData()->ReadUShort(Offset::kAdvanceWidthMax); +} + +void HorizontalHeaderTable::Builder::SetAdvanceWidthMax(int32_t value) { + InternalWriteData()->WriteUShort(Offset::kAdvanceWidthMax, value); +} + +int32_t HorizontalHeaderTable::Builder::MinLeftSideBearing() { + return InternalReadData()->ReadShort(Offset::kMinLeftSideBearing); +} + +void HorizontalHeaderTable::Builder::SetMinLeftSideBearing(int32_t value) { + InternalWriteData()->WriteShort(Offset::kMinLeftSideBearing, value); +} + +int32_t HorizontalHeaderTable::Builder::MinRightSideBearing() { + return InternalReadData()->ReadShort(Offset::kMinRightSideBearing); +} + +void HorizontalHeaderTable::Builder::SetMinRightSideBearing(int32_t value) { + InternalWriteData()->WriteShort(Offset::kMinRightSideBearing, value); +} + +int32_t HorizontalHeaderTable::Builder::XMaxExtent() { + return InternalReadData()->ReadShort(Offset::kXMaxExtent); +} + +void HorizontalHeaderTable::Builder::SetXMaxExtent(int32_t value) { + InternalWriteData()->WriteShort(Offset::kXMaxExtent, value); +} + +int32_t HorizontalHeaderTable::Builder::CaretSlopeRise() { + return InternalReadData()->ReadUShort(Offset::kCaretSlopeRise); +} + +void HorizontalHeaderTable::Builder::SetCaretSlopeRise(int32_t value) { + InternalWriteData()->WriteUShort(Offset::kCaretSlopeRise, value); +} + +int32_t HorizontalHeaderTable::Builder::CaretSlopeRun() { + return InternalReadData()->ReadUShort(Offset::kCaretSlopeRun); +} + +void HorizontalHeaderTable::Builder::SetCaretSlopeRun(int32_t value) { + InternalWriteData()->WriteUShort(Offset::kCaretSlopeRun, value); +} + +int32_t HorizontalHeaderTable::Builder::CaretOffset() { + return InternalReadData()->ReadUShort(Offset::kCaretOffset); +} + +void HorizontalHeaderTable::Builder::SetCaretOffset(int32_t value) { + InternalWriteData()->WriteUShort(Offset::kCaretOffset, value); +} + +int32_t HorizontalHeaderTable::Builder::MetricDataFormat() { + return InternalReadData()->ReadUShort(Offset::kMetricDataFormat); +} + +void HorizontalHeaderTable::Builder::SetMetricDataFormat(int32_t value) { + InternalWriteData()->WriteUShort(Offset::kMetricDataFormat, value); +} + +int32_t HorizontalHeaderTable::Builder::NumberOfHMetrics() { + return InternalReadData()->ReadUShort(Offset::kNumberOfHMetrics); +} + +void HorizontalHeaderTable::Builder::SetNumberOfHMetrics(int32_t value) { + InternalWriteData()->WriteUShort(Offset::kNumberOfHMetrics, value); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_header_table.h b/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_header_table.h new file mode 100644 index 0000000000..71f30b4475 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_header_table.h @@ -0,0 +1,111 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_HEADER_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_HEADER_TABLE_H_ + +#include "sfntly/table/table.h" +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +// A Horizontal Header table - 'hhea'. +class HorizontalHeaderTable : public Table, + public RefCounted<HorizontalHeaderTable> { + public: + // Builder for a Horizontal Header table - 'hhea'. + class Builder : public TableBasedTableBuilder, public RefCounted<Builder> { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + int32_t TableVersion(); + void SetTableVersion(int32_t version); + int32_t Ascender(); + void SetAscender(int32_t ascender); + int32_t Descender(); + void SetDescender(int32_t descender); + int32_t LineGap(); + void SetLineGap(int32_t line_gap); + int32_t AdvanceWidthMax(); + void SetAdvanceWidthMax(int32_t value); + int32_t MinLeftSideBearing(); + void SetMinLeftSideBearing(int32_t value); + int32_t MinRightSideBearing(); + void SetMinRightSideBearing(int32_t value); + int32_t XMaxExtent(); + void SetXMaxExtent(int32_t value); + int32_t CaretSlopeRise(); + void SetCaretSlopeRise(int32_t value); + int32_t CaretSlopeRun(); + void SetCaretSlopeRun(int32_t value); + int32_t CaretOffset(); + void SetCaretOffset(int32_t value); + int32_t MetricDataFormat(); + void SetMetricDataFormat(int32_t value); + int32_t NumberOfHMetrics(); + void SetNumberOfHMetrics(int32_t value); + }; + + virtual ~HorizontalHeaderTable(); + int32_t TableVersion(); + int32_t Ascender(); + int32_t Descender(); + int32_t LineGap(); + int32_t AdvanceWidthMax(); + int32_t MinLeftSideBearing(); + int32_t MinRightSideBearing(); + int32_t XMaxExtent(); + int32_t CaretSlopeRise(); + int32_t CaretSlopeRun(); + int32_t CaretOffset(); + int32_t MetricDataFormat(); + int32_t NumberOfHMetrics(); + + private: + struct Offset { + enum { + kVersion = 0, + kAscender = 4, + kDescender = 6, + kLineGap = 8, + kAdvanceWidthMax = 10, + kMinLeftSideBearing = 12, + kMinRightSideBearing = 14, + kXMaxExtent = 16, + kCaretSlopeRise = 18, + kCaretSlopeRun = 20, + kCaretOffset = 22, + kMetricDataFormat = 32, + kNumberOfHMetrics = 34, + }; + }; + + HorizontalHeaderTable(Header* header, ReadableFontData* data); +}; +typedef Ptr<HorizontalHeaderTable> HorizontalHeaderTablePtr; +typedef Ptr<HorizontalHeaderTable::Builder> HorizontalHeaderTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_HEADER_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_metrics_table.cc b/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_metrics_table.cc new file mode 100644 index 0000000000..156387daaf --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_metrics_table.cc @@ -0,0 +1,138 @@ +/* + * 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 "sfntly/table/core/horizontal_metrics_table.h" +#include "sfntly/port/exception_type.h" + +namespace sfntly { +/****************************************************************************** + * HorizontalMetricsTable class + ******************************************************************************/ +HorizontalMetricsTable::~HorizontalMetricsTable() {} + +int32_t HorizontalMetricsTable::NumberOfHMetrics() { + return num_hmetrics_; +} + +int32_t HorizontalMetricsTable::NumberOfLSBs() { + return num_glyphs_ - num_hmetrics_; +} + +int32_t HorizontalMetricsTable::HMetricAdvanceWidth(int32_t entry) { + if (entry > num_hmetrics_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#endif + return 0; + } + int32_t offset = Offset::kHMetricsStart + (entry * Offset::kHMetricsSize) + + Offset::kHMetricsAdvanceWidth; + return data_->ReadUShort(offset); +} + +int32_t HorizontalMetricsTable::HMetricLSB(int32_t entry) { + if (entry > num_hmetrics_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#endif + return 0; + } + int32_t offset = Offset::kHMetricsStart + (entry * Offset::kHMetricsSize) + + Offset::kHMetricsLeftSideBearing; + return data_->ReadShort(offset); +} + +int32_t HorizontalMetricsTable::LsbTableEntry(int32_t entry) { + if (entry > num_hmetrics_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#endif + return 0; + } + int32_t offset = Offset::kHMetricsStart + (entry * Offset::kHMetricsSize) + + Offset::kLeftSideBearingSize; + return data_->ReadShort(offset); +} + +int32_t HorizontalMetricsTable::AdvanceWidth(int32_t glyph_id) { + if (glyph_id < num_hmetrics_) { + return HMetricAdvanceWidth(glyph_id); + } + return HMetricAdvanceWidth(glyph_id - num_hmetrics_); +} + +int32_t HorizontalMetricsTable::LeftSideBearing(int32_t glyph_id) { + if (glyph_id < num_hmetrics_) { + return HMetricLSB(glyph_id); + } + return LsbTableEntry(glyph_id - num_hmetrics_); +} + +HorizontalMetricsTable::HorizontalMetricsTable(Header* header, + ReadableFontData* data, + int32_t num_hmetrics, + int32_t num_glyphs) + : Table(header, data), + num_hmetrics_(num_hmetrics), + num_glyphs_(num_glyphs) { +} + +/****************************************************************************** + * HorizontalMetricsTable::Builder class + ******************************************************************************/ +HorizontalMetricsTable::Builder::Builder(Header* header, WritableFontData* data) + : TableBasedTableBuilder(header, data), num_hmetrics_(-1), num_glyphs_(-1) { +} + +HorizontalMetricsTable::Builder::Builder(Header* header, ReadableFontData* data) + : TableBasedTableBuilder(header, data), num_hmetrics_(-1), num_glyphs_(-1) { +} + +HorizontalMetricsTable::Builder::~Builder() {} + +CALLER_ATTACH FontDataTable* + HorizontalMetricsTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = + new HorizontalMetricsTable(header(), data, num_hmetrics_, num_glyphs_); + return table.Detach(); +} + +CALLER_ATTACH HorizontalMetricsTable::Builder* + HorizontalMetricsTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr<HorizontalMetricsTable::Builder> builder; + builder = new HorizontalMetricsTable::Builder(header, data); + return builder.Detach(); +} + +void HorizontalMetricsTable::Builder::SetNumberOfHMetrics( + int32_t num_hmetrics) { + assert(num_hmetrics >= 0); + num_hmetrics_ = num_hmetrics; + HorizontalMetricsTable* table = + down_cast<HorizontalMetricsTable*>(this->GetTable()); + table->num_hmetrics_ = num_hmetrics; +} + +void HorizontalMetricsTable::Builder::SetNumGlyphs(int32_t num_glyphs) { + assert(num_glyphs >= 0); + num_glyphs_ = num_glyphs; + HorizontalMetricsTable* table = + down_cast<HorizontalMetricsTable*>(this->GetTable()); + table->num_glyphs_ = num_glyphs; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_metrics_table.h b/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_metrics_table.h new file mode 100644 index 0000000000..44b51f2d79 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/horizontal_metrics_table.h @@ -0,0 +1,87 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_METRICS_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_METRICS_TABLE_H_ + +#include "sfntly/table/table.h" +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +// A Horizontal Metrics table - 'hmtx'. +class HorizontalMetricsTable : public Table, + public RefCounted<HorizontalMetricsTable> { + public: + // Builder for a Horizontal Metrics Table - 'hmtx'. + class Builder : public TableBasedTableBuilder, public RefCounted<Builder> { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + void SetNumberOfHMetrics(int32_t num_hmetrics); + void SetNumGlyphs(int32_t num_glyphs); + + private: + int32_t num_hmetrics_; + int32_t num_glyphs_; + }; + + virtual ~HorizontalMetricsTable(); + int32_t NumberOfHMetrics(); + int32_t NumberOfLSBs(); + int32_t HMetricAdvanceWidth(int32_t entry); + int32_t HMetricLSB(int32_t entry); + int32_t LsbTableEntry(int32_t entry); + int32_t AdvanceWidth(int32_t glyph_id); + int32_t LeftSideBearing(int32_t glyph_id); + + private: + struct Offset { + enum { + // hMetrics + kHMetricsStart = 0, + kHMetricsSize = 4, + + // Offset within an hMetric + kHMetricsAdvanceWidth = 0, + kHMetricsLeftSideBearing = 2, + + kLeftSideBearingSize = 2 + }; + }; + + HorizontalMetricsTable(Header* header, + ReadableFontData* data, + int32_t num_hmetrics, + int32_t num_glyphs); + + int32_t num_hmetrics_; + int32_t num_glyphs_; +}; +typedef Ptr<HorizontalMetricsTable> HorizontalMetricsTablePtr; +typedef Ptr<HorizontalMetricsTable::Builder> HorizontalMetricsTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_METRICS_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/maximum_profile_table.cc b/gfx/sfntly/cpp/src/sfntly/table/core/maximum_profile_table.cc new file mode 100644 index 0000000000..a8ac3bc93a --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/maximum_profile_table.cc @@ -0,0 +1,240 @@ +/* + * 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 "sfntly/table/core/maximum_profile_table.h" + +namespace sfntly { +/****************************************************************************** + * MaximumProfileTable class + ******************************************************************************/ +MaximumProfileTable::~MaximumProfileTable() {} + +int32_t MaximumProfileTable::TableVersion() { + return data_->ReadFixed(Offset::kVersion); +} + +int32_t MaximumProfileTable::NumGlyphs() { + return data_->ReadUShort(Offset::kNumGlyphs); +} + +int32_t MaximumProfileTable::MaxPoints() { + return data_->ReadUShort(Offset::kMaxPoints); +} + +int32_t MaximumProfileTable::MaxContours() { + return data_->ReadUShort(Offset::kMaxContours); +} + +int32_t MaximumProfileTable::MaxCompositePoints() { + return data_->ReadUShort(Offset::kMaxCompositePoints); +} + +int32_t MaximumProfileTable::MaxCompositeContours() { + return data_->ReadUShort(Offset::kMaxCompositeContours); +} + +int32_t MaximumProfileTable::MaxZones() { + return data_->ReadUShort(Offset::kMaxZones); +} + +int32_t MaximumProfileTable::MaxTwilightPoints() { + return data_->ReadUShort(Offset::kMaxTwilightPoints); +} + +int32_t MaximumProfileTable::MaxStorage() { + return data_->ReadUShort(Offset::kMaxStorage); +} + +int32_t MaximumProfileTable::MaxFunctionDefs() { + return data_->ReadUShort(Offset::kMaxFunctionDefs); +} + +int32_t MaximumProfileTable::MaxStackElements() { + return data_->ReadUShort(Offset::kMaxStackElements); +} + +int32_t MaximumProfileTable::MaxSizeOfInstructions() { + return data_->ReadUShort(Offset::kMaxSizeOfInstructions); +} + +int32_t MaximumProfileTable::MaxComponentElements() { + return data_->ReadUShort(Offset::kMaxComponentElements); +} + +int32_t MaximumProfileTable::MaxComponentDepth() { + return data_->ReadUShort(Offset::kMaxComponentDepth); +} + +MaximumProfileTable::MaximumProfileTable(Header* header, + ReadableFontData* data) + : Table(header, data) { +} + +/****************************************************************************** + * MaximumProfileTable::Builder class + ******************************************************************************/ +MaximumProfileTable::Builder::Builder(Header* header, WritableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +MaximumProfileTable::Builder::Builder(Header* header, ReadableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +MaximumProfileTable::Builder::~Builder() {} + +CALLER_ATTACH FontDataTable* + MaximumProfileTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new MaximumProfileTable(header(), data); + return table.Detach(); +} + +CALLER_ATTACH MaximumProfileTable::Builder* + MaximumProfileTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr<MaximumProfileTable::Builder> builder; + builder = new MaximumProfileTable::Builder(header, data); + return builder.Detach(); +} + +int32_t MaximumProfileTable::Builder::TableVersion() { + return InternalReadData()->ReadUShort(Offset::kVersion); +} + +void MaximumProfileTable::Builder::SetTableVersion(int32_t version) { + InternalWriteData()->WriteUShort(Offset::kVersion, version); +} + +int32_t MaximumProfileTable::Builder::NumGlyphs() { + return InternalReadData()->ReadUShort(Offset::kNumGlyphs); +} + +void MaximumProfileTable::Builder::SetNumGlyphs(int32_t num_glyphs) { + InternalWriteData()->WriteUShort(Offset::kNumGlyphs, num_glyphs); +} + +int32_t MaximumProfileTable::Builder::MaxPoints() { + return InternalReadData()->ReadUShort(Offset::kMaxPoints); +} + +void MaximumProfileTable::Builder::SetMaxPoints(int32_t max_points) { + InternalWriteData()->WriteUShort(Offset::kMaxPoints, max_points); +} + +int32_t MaximumProfileTable::Builder::MaxContours() { + return InternalReadData()->ReadUShort(Offset::kMaxContours); +} + +void MaximumProfileTable::Builder::SetMaxContours(int32_t max_contours) { + InternalWriteData()->WriteUShort(Offset::kMaxContours, max_contours); +} + +int32_t MaximumProfileTable::Builder::MaxCompositePoints() { + return InternalReadData()->ReadUShort(Offset::kMaxCompositePoints); +} + +void MaximumProfileTable::Builder::SetMaxCompositePoints( + int32_t max_composite_points) { + InternalWriteData()->WriteUShort(Offset::kMaxCompositePoints, + max_composite_points); +} + +int32_t MaximumProfileTable::Builder::MaxCompositeContours() { + return InternalReadData()->ReadUShort(Offset::kMaxCompositeContours); +} + +void MaximumProfileTable::Builder::SetMaxCompositeContours( + int32_t max_composite_contours) { + InternalWriteData()->WriteUShort(Offset::kMaxCompositeContours, + max_composite_contours); +} + +int32_t MaximumProfileTable::Builder::MaxZones() { + return InternalReadData()->ReadUShort(Offset::kMaxZones); +} + +void MaximumProfileTable::Builder::SetMaxZones(int32_t max_zones) { + InternalWriteData()->WriteUShort(Offset::kMaxZones, max_zones); +} + +int32_t MaximumProfileTable::Builder::MaxTwilightPoints() { + return InternalReadData()->ReadUShort(Offset::kMaxTwilightPoints); +} + +void MaximumProfileTable::Builder::SetMaxTwilightPoints( + int32_t max_twilight_points) { + InternalWriteData()->WriteUShort(Offset::kMaxTwilightPoints, + max_twilight_points); +} + +int32_t MaximumProfileTable::Builder::MaxStorage() { + return InternalReadData()->ReadUShort(Offset::kMaxStorage); +} + +void MaximumProfileTable::Builder::SetMaxStorage(int32_t max_storage) { + InternalWriteData()->WriteUShort(Offset::kMaxStorage, max_storage); +} + +int32_t MaximumProfileTable::Builder::MaxFunctionDefs() { + return InternalReadData()->ReadUShort(Offset::kMaxFunctionDefs); +} + +void MaximumProfileTable::Builder::SetMaxFunctionDefs( + int32_t max_function_defs) { + InternalWriteData()->WriteUShort(Offset::kMaxFunctionDefs, max_function_defs); +} + +int32_t MaximumProfileTable::Builder::MaxStackElements() { + return InternalReadData()->ReadUShort(Offset::kMaxStackElements); +} + +void MaximumProfileTable::Builder::SetMaxStackElements( + int32_t max_stack_elements) { + InternalWriteData()->WriteUShort(Offset::kMaxStackElements, + max_stack_elements); +} + +int32_t MaximumProfileTable::Builder::MaxSizeOfInstructions() { + return InternalReadData()->ReadUShort(Offset::kMaxSizeOfInstructions); +} + +void MaximumProfileTable::Builder::SetMaxSizeOfInstructions( + int32_t max_size_of_instructions) { + InternalWriteData()->WriteUShort(Offset::kMaxSizeOfInstructions, + max_size_of_instructions); +} + +int32_t MaximumProfileTable::Builder::MaxComponentElements() { + return InternalReadData()->ReadUShort(Offset::kMaxComponentElements); +} + +void MaximumProfileTable::Builder::SetMaxComponentElements( + int32_t max_component_elements) { + InternalWriteData()->WriteUShort(Offset::kMaxComponentElements, + max_component_elements); +} + +int32_t MaximumProfileTable::Builder::MaxComponentDepth() { + return InternalReadData()->ReadUShort(Offset::kMaxComponentDepth); +} + +void MaximumProfileTable::Builder::SetMaxComponentDepth( + int32_t max_component_depth) { + InternalWriteData()->WriteUShort(Offset::kMaxComponentDepth, + max_component_depth); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/maximum_profile_table.h b/gfx/sfntly/cpp/src/sfntly/table/core/maximum_profile_table.h new file mode 100644 index 0000000000..e7c5abb3ff --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/maximum_profile_table.h @@ -0,0 +1,120 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_MAXIMUM_PROFILE_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_MAXIMUM_PROFILE_TABLE_H_ + +#include "sfntly/port/refcount.h" +#include "sfntly/table/table.h" +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +// A Maximum Profile table - 'maxp'. +class MaximumProfileTable : public Table, + public RefCounted<MaximumProfileTable> { + public: + // Builder for a Maximum Profile table - 'maxp'. + class Builder : public TableBasedTableBuilder, public RefCounted<Builder> { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + int32_t TableVersion(); + void SetTableVersion(int32_t version); + int32_t NumGlyphs(); + void SetNumGlyphs(int32_t num_glyphs); + int32_t MaxPoints(); + void SetMaxPoints(int32_t max_points); + int32_t MaxContours(); + void SetMaxContours(int32_t max_contours); + int32_t MaxCompositePoints(); + void SetMaxCompositePoints(int32_t max_composite_points); + int32_t MaxCompositeContours(); + void SetMaxCompositeContours(int32_t max_composite_contours); + int32_t MaxZones(); + void SetMaxZones(int32_t max_zones); + int32_t MaxTwilightPoints(); + void SetMaxTwilightPoints(int32_t max_twilight_points); + int32_t MaxStorage(); + void SetMaxStorage(int32_t max_storage); + int32_t MaxFunctionDefs(); + void SetMaxFunctionDefs(int32_t max_function_defs); + int32_t MaxStackElements(); + void SetMaxStackElements(int32_t max_stack_elements); + int32_t MaxSizeOfInstructions(); + void SetMaxSizeOfInstructions(int32_t max_size_of_instructions); + int32_t MaxComponentElements(); + void SetMaxComponentElements(int32_t max_component_elements); + int32_t MaxComponentDepth(); + void SetMaxComponentDepth(int32_t max_component_depth); + }; + + virtual ~MaximumProfileTable(); + int32_t TableVersion(); + int32_t NumGlyphs(); + int32_t MaxPoints(); + int32_t MaxContours(); + int32_t MaxCompositePoints(); + int32_t MaxCompositeContours(); + int32_t MaxZones(); + int32_t MaxTwilightPoints(); + int32_t MaxStorage(); + int32_t MaxFunctionDefs(); + int32_t MaxStackElements(); + int32_t MaxSizeOfInstructions(); + int32_t MaxComponentElements(); + int32_t MaxComponentDepth(); + + private: + struct Offset { + enum { + // version 0.5 and 1.0 + kVersion = 0, + kNumGlyphs = 4, + + // version 1.0 + kMaxPoints = 6, + kMaxContours = 8, + kMaxCompositePoints = 10, + kMaxCompositeContours = 12, + kMaxZones = 14, + kMaxTwilightPoints = 16, + kMaxStorage = 18, + kMaxFunctionDefs = 20, + kMaxInstructionDefs = 22, + kMaxStackElements = 24, + kMaxSizeOfInstructions = 26, + kMaxComponentElements = 28, + kMaxComponentDepth = 30, + }; + }; + + MaximumProfileTable(Header* header, ReadableFontData* data); +}; +typedef Ptr<MaximumProfileTable> MaximumProfileTablePtr; +typedef Ptr<MaximumProfileTable::Builder> MaximumProfileTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_MAXIMUM_PROFILE_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/name_table.cc b/gfx/sfntly/cpp/src/sfntly/table/core/name_table.cc new file mode 100644 index 0000000000..0e1fff9e0a --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/name_table.cc @@ -0,0 +1,727 @@ +/* + * 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 "sfntly/table/core/name_table.h" + +#include <stdio.h> +#include <string.h> + +#include "sfntly/font.h" +#include "sfntly/port/exception_type.h" + +namespace sfntly { +/****************************************************************************** + * NameTable::NameEntryId class + ******************************************************************************/ +NameTable::NameEntryId::NameEntryId() + : platform_id_(0), + encoding_id_(0), + language_id_(0), + name_id_(0) { +} + +NameTable::NameEntryId::NameEntryId(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) + : platform_id_(platform_id), + encoding_id_(encoding_id), + language_id_(language_id), + name_id_(name_id) { +} + +NameTable::NameEntryId::NameEntryId(const NameTable::NameEntryId& rhs) { + *this = rhs; +} + +const NameTable::NameEntryId& + NameTable::NameEntryId::operator=(const NameTable::NameEntryId& rhs) const { + platform_id_ = rhs.platform_id_; + encoding_id_ = rhs.encoding_id_; + language_id_ = rhs.language_id_; + name_id_ = rhs.name_id_; + return *this; +} + +bool NameTable::NameEntryId::operator==(const NameEntryId& rhs) const { + return platform_id_ == rhs.platform_id_ && + encoding_id_ == rhs.encoding_id_ && + language_id_ == rhs.language_id_ && + name_id_ == rhs.name_id_; +} + +bool NameTable::NameEntryId::operator<(const NameEntryId& rhs) const { + if (platform_id_ != rhs.platform_id_) return platform_id_ < rhs.platform_id_; + if (encoding_id_ != rhs.encoding_id_) return encoding_id_ < rhs.encoding_id_; + if (language_id_ != rhs.language_id_) return language_id_ < rhs.language_id_; + return name_id_ < rhs.name_id_; +} + +/****************************************************************************** + * NameTable::NameEntry class + ******************************************************************************/ +NameTable::NameEntry::NameEntry() { + Init(0, 0, 0, 0, NULL); +} + +NameTable::NameEntry::NameEntry(const NameEntryId& name_entry_id, + const std::vector<uint8_t>& name_bytes) { + Init(name_entry_id.platform_id(), + name_entry_id.encoding_id(), + name_entry_id.language_id(), + name_entry_id.name_id(), + &name_bytes); +} + +NameTable::NameEntry::NameEntry(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id, + const std::vector<uint8_t>& name_bytes) { + Init(platform_id, encoding_id, language_id, name_id, &name_bytes); +} + +NameTable::NameEntry::~NameEntry() {} + +std::vector<uint8_t>* NameTable::NameEntry::NameAsBytes() { + return &name_bytes_; +} + +int32_t NameTable::NameEntry::NameBytesLength() { + return name_bytes_.size(); +} + +UChar* NameTable::NameEntry::Name() { + return NameTable::ConvertFromNameBytes(&name_bytes_, + platform_id(), + encoding_id()); +} + +bool NameTable::NameEntry::operator==(const NameEntry& rhs) const { + return (name_entry_id_ == rhs.name_entry_id_ && + name_bytes_ == rhs.name_bytes_); +} + +void NameTable::NameEntry::Init(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id, + const std::vector<uint8_t>* name_bytes) { + name_entry_id_ = NameEntryId(platform_id, encoding_id, language_id, name_id); + if (name_bytes) { + name_bytes_ = *name_bytes; + } else { + name_bytes_.clear(); + } +} + +/****************************************************************************** + * NameTable::NameEntryBuilder class + ******************************************************************************/ +NameTable::NameEntryBuilder::NameEntryBuilder() { + Init(0, 0, 0, 0, NULL); +} + +NameTable::NameEntryBuilder::NameEntryBuilder(const NameEntryId& name_entry_id, + const std::vector<uint8_t>& name_bytes) { + Init(name_entry_id.platform_id(), + name_entry_id.encoding_id(), + name_entry_id.language_id(), + name_entry_id.name_id(), + &name_bytes); +} + +NameTable::NameEntryBuilder::NameEntryBuilder( + const NameEntryId& name_entry_id) { + Init(name_entry_id.platform_id(), + name_entry_id.encoding_id(), + name_entry_id.language_id(), + name_entry_id.name_id(), + NULL); +} + +NameTable::NameEntryBuilder::NameEntryBuilder(NameEntry* b) { + Init(b->platform_id(), + b->encoding_id(), + b->language_id(), + b->name_id(), + b->NameAsBytes()); +} + +NameTable::NameEntryBuilder::~NameEntryBuilder() {} + +void NameTable::NameEntryBuilder::SetName(const UChar* name) { + if (name == NULL) { + name_entry_->name_bytes_.clear(); + return; + } + NameTable::ConvertToNameBytes(name, + name_entry_->platform_id(), + name_entry_->encoding_id(), + &name_entry_->name_bytes_); +} + +void NameTable::NameEntryBuilder::SetName(const std::vector<uint8_t>& name_bytes) { + name_entry_->name_bytes_.clear(); + std::copy(name_bytes.begin(), + name_bytes.end(), + name_entry_->name_bytes_.begin()); +} + +void NameTable::NameEntryBuilder::SetName(const std::vector<uint8_t>& name_bytes, + int32_t offset, + int32_t length) { + name_entry_->name_bytes_.clear(); + std::copy(name_bytes.begin() + offset, + name_bytes.begin() + offset + length, + name_entry_->name_bytes_.begin()); +} + +void NameTable::NameEntryBuilder::Init(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id, + const std::vector<uint8_t>* name_bytes) { + name_entry_ = new NameEntry(); + name_entry_->Init(platform_id, encoding_id, language_id, name_id, name_bytes); +} + +/****************************************************************************** + * NameTable::NameEntryFilterInPlace class (C++ port only) + ******************************************************************************/ +NameTable::NameEntryFilterInPlace::NameEntryFilterInPlace(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) + : platform_id_(platform_id), + encoding_id_(encoding_id), + language_id_(language_id), + name_id_(name_id) { +} + +bool NameTable::NameEntryFilterInPlace::Accept(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) { + return (platform_id_ == platform_id && + encoding_id_ == encoding_id && + language_id_ == language_id && + name_id_ == name_id); +} + +/****************************************************************************** + * NameTable::NameEntryIterator class + ******************************************************************************/ +NameTable::NameEntryIterator::NameEntryIterator(NameTable* table) + : RefIterator<NameEntry, NameTable>(table), + name_index_(0), + filter_(NULL) { +} + +NameTable::NameEntryIterator::NameEntryIterator(NameTable* table, + NameEntryFilter* filter) + : RefIterator<NameEntry, NameTable>(table), + name_index_(0), + filter_(filter) { +} + +bool NameTable::NameEntryIterator::HasNext() { + if (!filter_) { + if (name_index_ < container()->NameCount()) { + return true; + } + return false; + } + for (; name_index_ < container()->NameCount(); ++name_index_) { + if (filter_->Accept(container()->PlatformId(name_index_), + container()->EncodingId(name_index_), + container()->LanguageId(name_index_), + container()->NameId(name_index_))) { + return true; + } + } + return false; +} + +CALLER_ATTACH NameTable::NameEntry* NameTable::NameEntryIterator::Next() { + if (!HasNext()) + return NULL; + return container()->GetNameEntry(name_index_++); +} + +/****************************************************************************** + * NameTable::Builder class + ******************************************************************************/ +NameTable::Builder::Builder(Header* header, WritableFontData* data) + : SubTableContainerTable::Builder(header, data) { +} + +NameTable::Builder::Builder(Header* header, ReadableFontData* data) + : SubTableContainerTable::Builder(header, data) { +} + +CALLER_ATTACH NameTable::Builder* + NameTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr<NameTable::Builder> builder; + builder = new NameTable::Builder(header, data); + return builder.Detach(); +} + +void NameTable::Builder::RevertNames() { + name_entry_map_.clear(); + set_model_changed(false); +} + +int32_t NameTable::Builder::BuilderCount() { + GetNameBuilders(); // Ensure name_entry_map_ is built. + return (int32_t)name_entry_map_.size(); +} + +bool NameTable::Builder::Has(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) { + NameEntryId probe(platform_id, encoding_id, language_id, name_id); + GetNameBuilders(); // Ensure name_entry_map_ is built. + return (name_entry_map_.find(probe) != name_entry_map_.end()); +} + +CALLER_ATTACH NameTable::NameEntryBuilder* + NameTable::Builder::NameBuilder(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) { + NameEntryId probe(platform_id, encoding_id, language_id, name_id); + NameEntryBuilderMap builders; + GetNameBuilders(); // Ensure name_entry_map_ is built. + if (name_entry_map_.find(probe) != name_entry_map_.end()) { + return name_entry_map_[probe]; + } + NameEntryBuilderPtr builder = new NameEntryBuilder(probe); + name_entry_map_[probe] = builder; + return builder.Detach(); +} + +bool NameTable::Builder::Remove(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) { + NameEntryId probe(platform_id, encoding_id, language_id, name_id); + GetNameBuilders(); // Ensure name_entry_map_ is built. + NameEntryBuilderMap::iterator position = name_entry_map_.find(probe); + if (position != name_entry_map_.end()) { + name_entry_map_.erase(position); + return true; + } + return false; +} + +CALLER_ATTACH FontDataTable* + NameTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new NameTable(header(), data); + return table.Detach(); +} + +void NameTable::Builder::SubDataSet() { + name_entry_map_.clear(); + set_model_changed(false); +} + +int32_t NameTable::Builder::SubDataSizeToSerialize() { + if (name_entry_map_.empty()) { + return 0; + } + + int32_t size = NameTable::Offset::kNameRecordStart + + name_entry_map_.size() * NameTable::Offset::kNameRecordSize; + for (NameEntryBuilderMap::iterator b = name_entry_map_.begin(), + end = name_entry_map_.end(); + b != end; ++b) { + NameEntryBuilderPtr p = b->second; + NameEntry* entry = p->name_entry(); + size += entry->NameBytesLength(); + } + return size; +} + +bool NameTable::Builder::SubReadyToSerialize() { + return !name_entry_map_.empty(); +} + +int32_t NameTable::Builder::SubSerialize(WritableFontData* new_data) { + int32_t string_table_start_offset = + NameTable::Offset::kNameRecordStart + + name_entry_map_.size() * NameTable::Offset::kNameRecordSize; + + // Header + new_data->WriteUShort(NameTable::Offset::kFormat, 0); + new_data->WriteUShort(NameTable::Offset::kCount, name_entry_map_.size()); + new_data->WriteUShort(NameTable::Offset::kStringOffset, + string_table_start_offset); + int32_t name_record_offset = NameTable::Offset::kNameRecordStart; + int32_t string_offset = 0; + // Note: we offered operator< in NameEntryId, which will be used by std::less, + // and therefore our map will act like TreeMap in Java to provide + // sorted key set. + for (NameEntryBuilderMap::iterator b = name_entry_map_.begin(), + end = name_entry_map_.end(); + b != end; ++b) { + new_data->WriteUShort( + name_record_offset + NameTable::Offset::kNameRecordPlatformId, + b->first.platform_id()); + new_data->WriteUShort( + name_record_offset + NameTable::Offset::kNameRecordEncodingId, + b->first.encoding_id()); + new_data->WriteUShort( + name_record_offset + NameTable::Offset::kNameRecordLanguageId, + b->first.language_id()); + new_data->WriteUShort( + name_record_offset + NameTable::Offset::kNameRecordNameId, + b->first.name_id()); + NameEntry* builder_entry = b->second->name_entry(); + new_data->WriteUShort( + name_record_offset + NameTable::Offset::kNameRecordStringLength, + builder_entry->NameBytesLength()); + new_data->WriteUShort( + name_record_offset + NameTable::Offset::kNameRecordStringOffset, + string_offset); + name_record_offset += NameTable::Offset::kNameRecordSize; + string_offset += new_data->WriteBytes( + string_offset + string_table_start_offset, + builder_entry->NameAsBytes()); + } + + return string_offset + string_table_start_offset; +} + +void NameTable::Builder::Initialize(ReadableFontData* data) { + if (data) { + NameTablePtr table = new NameTable(header(), data); + Ptr<NameEntryIterator> name_iter; + name_iter.Attach(table->Iterator()); + while (name_iter->HasNext()) { + NameEntryPtr name_entry; + name_entry.Attach(name_iter->Next()); + NameEntryBuilderPtr name_entry_builder = new NameEntryBuilder(name_entry); + NameEntry* builder_entry = name_entry_builder->name_entry(); + NameEntryId probe = builder_entry->name_entry_id(); + name_entry_map_[probe] = name_entry_builder; + } + } +} + +NameTable::NameEntryBuilderMap* NameTable::Builder::GetNameBuilders() { + if (name_entry_map_.empty()) { + Initialize(InternalReadData()); + } + set_model_changed(); + return &name_entry_map_; +} + +/****************************************************************************** + * NameTable class + ******************************************************************************/ +NameTable::~NameTable() {} + +int32_t NameTable::Format() { + return data_->ReadUShort(Offset::kFormat); +} + +int32_t NameTable::NameCount() { + return data_->ReadUShort(Offset::kCount); +} + +int32_t NameTable::PlatformId(int32_t index) { + return data_->ReadUShort(Offset::kNameRecordPlatformId + + OffsetForNameRecord(index)); +} + +int32_t NameTable::EncodingId(int32_t index) { + return data_->ReadUShort(Offset::kNameRecordEncodingId + + OffsetForNameRecord(index)); +} + +int32_t NameTable::LanguageId(int32_t index) { + return data_->ReadUShort(Offset::kNameRecordLanguageId + + OffsetForNameRecord(index)); +} + +int32_t NameTable::NameId(int32_t index) { + return data_->ReadUShort(Offset::kNameRecordNameId + + OffsetForNameRecord(index)); +} + +void NameTable::NameAsBytes(int32_t index, std::vector<uint8_t>* b) { + assert(b); + b->clear(); + + int32_t length = NameLength(index); + if (length <= 0) + return; + + int32_t offset = NameOffset(index); + if (offset < 0) + return; + + b->resize(length); + data_->ReadBytes(offset, &((*b)[0]), 0, length); +} + +void NameTable::NameAsBytes(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id, + std::vector<uint8_t>* b) { + assert(b); + NameEntryPtr entry; + entry.Attach(GetNameEntry(platform_id, encoding_id, language_id, name_id)); + if (entry) { + std::vector<uint8_t>* name = entry->NameAsBytes(); + std::copy(name->begin(), name->end(), b->begin()); + } +} + +UChar* NameTable::Name(int32_t index) { + std::vector<uint8_t> b; + NameAsBytes(index, &b); + return ConvertFromNameBytes(&b, PlatformId(index), EncodingId(index)); +} + +UChar* NameTable::Name(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) { + NameEntryPtr entry; + entry.Attach(GetNameEntry(platform_id, encoding_id, language_id, name_id)); + if (entry) { + return entry->Name(); + } + return NULL; +} + +CALLER_ATTACH NameTable::NameEntry* NameTable::GetNameEntry(int32_t index) { + std::vector<uint8_t> b; + NameAsBytes(index, &b); + NameEntryPtr instance = new NameEntry(PlatformId(index), + EncodingId(index), + LanguageId(index), + NameId(index), b); + return instance.Detach(); +} + +CALLER_ATTACH NameTable::NameEntry* NameTable::GetNameEntry(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) { + NameTable::NameEntryFilterInPlace + filter(platform_id, encoding_id, language_id, name_id); + Ptr<NameTable::NameEntryIterator> name_entry_iter; + name_entry_iter.Attach(Iterator(&filter)); + NameEntryPtr result; + if (name_entry_iter->HasNext()) { + result = name_entry_iter->Next(); + } + return result; +} + +CALLER_ATTACH NameTable::NameEntryIterator* NameTable::Iterator() { + Ptr<NameEntryIterator> output = new NameTable::NameEntryIterator(this); + return output.Detach(); +} + +CALLER_ATTACH +NameTable::NameEntryIterator* NameTable::Iterator(NameEntryFilter* filter) { + Ptr<NameEntryIterator> output = + new NameTable::NameEntryIterator(this, filter); + return output.Detach(); +} + +NameTable::NameTable(Header* header, ReadableFontData* data) + : SubTableContainerTable(header, data) {} + +int32_t NameTable::StringOffset() { + return data_->ReadUShort(Offset::kStringOffset); +} + +int32_t NameTable::OffsetForNameRecord(int32_t index) { + return Offset::kNameRecordStart + index * Offset::kNameRecordSize; +} + +int32_t NameTable::NameLength(int32_t index) { + return data_->ReadUShort(Offset::kNameRecordStringLength + + OffsetForNameRecord(index)); +} + +int32_t NameTable::NameOffset(int32_t index) { + return data_->ReadUShort(Offset::kNameRecordStringOffset + + OffsetForNameRecord(index)) + StringOffset(); +} + +const char* NameTable::GetEncodingName(int32_t platform_id, + int32_t encoding_id) { + switch (platform_id) { + case PlatformId::kUnicode: + return "UTF-16BE"; + case PlatformId::kMacintosh: + switch (encoding_id) { + case MacintoshEncodingId::kRoman: + return "MacRoman"; + case MacintoshEncodingId::kJapanese: + return "Shift-JIS"; + case MacintoshEncodingId::kChineseTraditional: + return "Big5"; + case MacintoshEncodingId::kKorean: + return "EUC-KR"; + case MacintoshEncodingId::kArabic: + return "MacArabic"; + case MacintoshEncodingId::kHebrew: + return "MacHebrew"; + case MacintoshEncodingId::kGreek: + return "MacGreek"; + case MacintoshEncodingId::kRussian: + return "MacCyrillic"; + case MacintoshEncodingId::kRSymbol: + return "MacSymbol"; + case MacintoshEncodingId::kThai: + return "MacThai"; + case MacintoshEncodingId::kChineseSimplified: + return "EUC-CN"; + default: // Note: unknown/unconfirmed cases are not ported. + break; + } + break; + case PlatformId::kISO: + break; + case PlatformId::kWindows: + switch (encoding_id) { + case WindowsEncodingId::kSymbol: + case WindowsEncodingId::kUnicodeUCS2: + return "UTF-16BE"; + case WindowsEncodingId::kShiftJIS: + return "windows-933"; + case WindowsEncodingId::kPRC: + return "windows-936"; + case WindowsEncodingId::kBig5: + return "windows-950"; + case WindowsEncodingId::kWansung: + return "windows-949"; + case WindowsEncodingId::kJohab: + return "ms1361"; + case WindowsEncodingId::kUnicodeUCS4: + return "UCS-4"; + } + break; + case PlatformId::kCustom: + break; + default: + break; + } + return NULL; +} + +UConverter* NameTable::GetCharset(int32_t platform_id, int32_t encoding_id) { + UErrorCode error_code = U_ZERO_ERROR; + UConverter* conv = ucnv_open(GetEncodingName(platform_id, encoding_id), + &error_code); + if (U_SUCCESS(error_code)) { + return conv; + } + + if (conv) { + ucnv_close(conv); + } + return NULL; +} + +void NameTable::ConvertToNameBytes(const UChar* name, + int32_t platform_id, + int32_t encoding_id, + std::vector<uint8_t>* b) { + assert(b); + assert(name); + b->clear(); + UConverter* cs = GetCharset(platform_id, encoding_id); + if (cs == NULL) { + return; + } + + // Preflight to get buffer size. + UErrorCode error_code = U_ZERO_ERROR; + int32_t length = ucnv_fromUChars(cs, NULL, 0, name, -1, &error_code); + b->resize(length + 4); // The longest termination "\0" is 4 bytes. + memset(&((*b)[0]), 0, length + 4); + error_code = U_ZERO_ERROR; + ucnv_fromUChars(cs, + reinterpret_cast<char*>(&((*b)[0])), + length + 4, + name, + -1, + &error_code); + if (!U_SUCCESS(error_code)) { + b->clear(); + } + ucnv_close(cs); +} + +UChar* NameTable::ConvertFromNameBytes(std::vector<uint8_t>* name_bytes, + int32_t platform_id, + int32_t encoding_id) { + if (name_bytes == NULL || name_bytes->size() == 0) { + return NULL; + } + UConverter* cs = GetCharset(platform_id, encoding_id); + UErrorCode error_code = U_ZERO_ERROR; + if (cs == NULL) { + char buffer[11] = {0}; +#if defined (WIN32) + _itoa_s(platform_id, buffer, 16); +#else + snprintf(buffer, sizeof(buffer), "%x", platform_id); +#endif + UChar* result = new UChar[12]; + memset(result, 0, sizeof(UChar) * 12); + cs = ucnv_open("utf-8", &error_code); + if (U_SUCCESS(error_code)) { + ucnv_toUChars(cs, result, 12, buffer, 11, &error_code); + ucnv_close(cs); + if (U_SUCCESS(error_code)) { + return result; + } + } + delete[] result; + return NULL; + } + + // No preflight needed here, we will be bigger. + UChar* output_buffer = new UChar[name_bytes->size() + 1]; + memset(output_buffer, 0, sizeof(UChar) * (name_bytes->size() + 1)); + int32_t length = ucnv_toUChars(cs, + output_buffer, + name_bytes->size(), + reinterpret_cast<char*>(&((*name_bytes)[0])), + name_bytes->size(), + &error_code); + ucnv_close(cs); + if (length > 0) { + return output_buffer; + } + + delete[] output_buffer; + return NULL; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/name_table.h b/gfx/sfntly/cpp/src/sfntly/table/core/name_table.h new file mode 100644 index 0000000000..ac109df156 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/name_table.h @@ -0,0 +1,743 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_NAME_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_NAME_TABLE_H_ + +// Must include this before ICU to avoid stdint redefinition issue. +#include "sfntly/port/type.h" + +#include <unicode/ucnv.h> +#include <unicode/ustring.h> + +#include <map> +#include <utility> + +#include "sfntly/port/java_iterator.h" +#include "sfntly/table/subtable_container_table.h" + +namespace sfntly { + +// The following code implements the name table defined in TTF/OTF spec, which +// can be found at http://www.microsoft.com/typography/otspec/name.htm. + +// Name IDs defined in TTF/OTF spec. +struct NameId { + enum { + kUnknown = -1, + kCopyrightNotice = 0, + kFontFamilyName = 1, + kFontSubfamilyName = 2, + kUniqueFontIdentifier = 3, + kFullFontName = 4, + kVersionString = 5, + kPostscriptName = 6, + kTrademark = 7, + kManufacturerName = 8, + kDesigner = 9, + kDescription = 10, + kVendorURL = 11, + kDesignerURL = 12, + kLicenseDescription = 13, + kLicenseInfoURL = 14, + kReserved15 = 15, + kPreferredFamily = 16, + kPreferredSubfamily = 17, + kCompatibleFullName = 18, + kSampleText = 19, + kPostscriptCID = 20, + kWWSFamilyName = 21, + kWWSSubfamilyName = 22 + }; +}; + +// Unicode language IDs used in Name Records. +struct UnicodeLanguageId { + enum { + kUnknown = -1, + kAll = 0 + }; +}; + +// Macintosh Language IDs (platform ID = 1) +struct MacintoshLanguageId { + enum { + kUnknown = -1, + kEnglish = 0, + kFrench = 1, + kGerman = 2, + kItalian = 3, + kDutch = 4, + kSwedish = 5, + kSpanish = 6, + kDanish = 7, + kPortuguese = 8, + kNorwegian = 9, + kHebrew = 10, + kJapanese = 11, + kArabic = 12, + kFinnish = 13, + kGreek = 14, + kIcelandic = 15, + kMaltese = 16, + kTurkish = 17, + kCroatian = 18, + kChinese_Traditional = 19, + kUrdu = 20, + kHindi = 21, + kThai = 22, + kKorean = 23, + kLithuanian = 24, + kPolish = 25, + kHungarian = 26, + kEstonian = 27, + kLatvian = 28, + kSami = 29, + kFaroese = 30, + kFarsiPersian = 31, + kRussian = 32, + kChinese_Simplified = 33, + kFlemish = 34, + kIrishGaelic = 35, + kAlbanian = 36, + kRomanian = 37, + kCzech = 38, + kSlovak = 39, + kSlovenian = 40, + kYiddish = 41, + kSerbian = 42, + kMacedonian = 43, + kBulgarian = 44, + kUkrainian = 45, + kByelorussian = 46, + kUzbek = 47, + kKazakh = 48, + kAzerbaijani_Cyrillic = 49, + kAzerbaijani_Arabic = 50, + kArmenian = 51, + kGeorgian = 52, + kMoldavian = 53, + kKirghiz = 54, + kTajiki = 55, + kTurkmen = 56, + kMongolian_Mongolian = 57, + kMongolian_Cyrillic = 58, + kPashto = 59, + kKurdish = 60, + kKashmiri = 61, + kSindhi = 62, + kTibetan = 63, + kNepali = 64, + kSanskrit = 65, + kMarathi = 66, + kBengali = 67, + kAssamese = 68, + kGujarati = 69, + kPunjabi = 70, + kOriya = 71, + kMalayalam = 72, + kKannada = 73, + kTamil = 74, + kTelugu = 75, + kSinhalese = 76, + kBurmese = 77, + kKhmer = 78, + kLao = 79, + kVietnamese = 80, + kIndonesian = 81, + kTagalong = 82, + kMalay_Roman = 83, + kMalay_Arabic = 84, + kAmharic = 85, + kTigrinya = 86, + kGalla = 87, + kSomali = 88, + kSwahili = 89, + kKinyarwandaRuanda = 90, + kRundi = 91, + kNyanjaChewa = 92, + kMalagasy = 93, + kEsperanto = 94, + kWelsh = 128, + kBasque = 129, + kCatalan = 130, + kLatin = 131, + kQuenchua = 132, + kGuarani = 133, + kAymara = 134, + kTatar = 135, + kUighur = 136, + kDzongkha = 137, + kJavanese_Roman = 138, + kSundanese_Roman = 139, + kGalician = 140, + kAfrikaans = 141, + kBreton = 142, + kInuktitut = 143, + kScottishGaelic = 144, + kManxGaelic = 145, + kIrishGaelic_WithDotAbove = 146, + kTongan = 147, + kGreek_Polytonic = 148, + kGreenlandic = 149, + kAzerbaijani_Roman = 150 + }; +}; + +// Windows Language IDs (platformID = 3) +struct WindowsLanguageId { + enum { + kUnknown = -1, + kAfrikaans_SouthAfrica = 0x0436, + kAlbanian_Albania = 0x041C, + kAlsatian_France = 0x0484, + kAmharic_Ethiopia = 0x045E, + kArabic_Algeria = 0x1401, + kArabic_Bahrain = 0x3C01, + kArabic_Egypt = 0x0C01, + kArabic_Iraq = 0x0801, + kArabic_Jordan = 0x2C01, + kArabic_Kuwait = 0x3401, + kArabic_Lebanon = 0x3001, + kArabic_Libya = 0x1001, + kArabic_Morocco = 0x1801, + kArabic_Oman = 0x2001, + kArabic_Qatar = 0x4001, + kArabic_SaudiArabia = 0x0401, + kArabic_Syria = 0x2801, + kArabic_Tunisia = 0x1C01, + kArabic_UAE = 0x3801, + kArabic_Yemen = 0x2401, + kArmenian_Armenia = 0x042B, + kAssamese_India = 0x044D, + kAzeri_Cyrillic_Azerbaijan = 0x082C, + kAzeri_Latin_Azerbaijan = 0x042C, + kBashkir_Russia = 0x046D, + kBasque_Basque = 0x042D, + kBelarusian_Belarus = 0x0423, + kBengali_Bangladesh = 0x0845, + kBengali_India = 0x0445, + kBosnian_Cyrillic_BosniaAndHerzegovina = 0x201A, + kBosnian_Latin_BosniaAndHerzegovina = 0x141A, + kBreton_France = 0x047E, + kBulgarian_Bulgaria = 0x0402, + kCatalan_Catalan = 0x0403, + kChinese_HongKongSAR = 0x0C04, + kChinese_MacaoSAR = 0x1404, + kChinese_PeoplesRepublicOfChina = 0x0804, + kChinese_Singapore = 0x1004, + kChinese_Taiwan = 0x0404, + kCorsican_France = 0x0483, + kCroatian_Croatia = 0x041A, + kCroatian_Latin_BosniaAndHerzegovina = 0x101A, + kCzech_CzechRepublic = 0x0405, + kDanish_Denmark = 0x0406, + kDari_Afghanistan = 0x048C, + kDivehi_Maldives = 0x0465, + kDutch_Belgium = 0x0813, + kDutch_Netherlands = 0x0413, + kEnglish_Australia = 0x0C09, + kEnglish_Belize = 0x2809, + kEnglish_Canada = 0x1009, + kEnglish_Caribbean = 0x2409, + kEnglish_India = 0x4009, + kEnglish_Ireland = 0x1809, + kEnglish_Jamaica = 0x2009, + kEnglish_Malaysia = 0x4409, + kEnglish_NewZealand = 0x1409, + kEnglish_RepublicOfThePhilippines = 0x3409, + kEnglish_Singapore = 0x4809, + kEnglish_SouthAfrica = 0x1C09, + kEnglish_TrinidadAndTobago = 0x2C09, + kEnglish_UnitedKingdom = 0x0809, + kEnglish_UnitedStates = 0x0409, + kEnglish_Zimbabwe = 0x3009, + kEstonian_Estonia = 0x0425, + kFaroese_FaroeIslands = 0x0438, + kFilipino_Philippines = 0x0464, + kFinnish_Finland = 0x040B, + kFrench_Belgium = 0x080C, + kFrench_Canada = 0x0C0C, + kFrench_France = 0x040C, + kFrench_Luxembourg = 0x140c, + kFrench_PrincipalityOfMonoco = 0x180C, + kFrench_Switzerland = 0x100C, + kFrisian_Netherlands = 0x0462, + kGalician_Galician = 0x0456, + kGeorgian_Georgia = 0x0437, + kGerman_Austria = 0x0C07, + kGerman_Germany = 0x0407, + kGerman_Liechtenstein = 0x1407, + kGerman_Luxembourg = 0x1007, + kGerman_Switzerland = 0x0807, + kGreek_Greece = 0x0408, + kGreenlandic_Greenland = 0x046F, + kGujarati_India = 0x0447, + kHausa_Latin_Nigeria = 0x0468, + kHebrew_Israel = 0x040D, + kHindi_India = 0x0439, + kHungarian_Hungary = 0x040E, + kIcelandic_Iceland = 0x040F, + kIgbo_Nigeria = 0x0470, + kIndonesian_Indonesia = 0x0421, + kInuktitut_Canada = 0x045D, + kInuktitut_Latin_Canada = 0x085D, + kIrish_Ireland = 0x083C, + kisiXhosa_SouthAfrica = 0x0434, + kisiZulu_SouthAfrica = 0x0435, + kItalian_Italy = 0x0410, + kItalian_Switzerland = 0x0810, + kJapanese_Japan = 0x0411, + kKannada_India = 0x044B, + kKazakh_Kazakhstan = 0x043F, + kKhmer_Cambodia = 0x0453, + kKiche_Guatemala = 0x0486, + kKinyarwanda_Rwanda = 0x0487, + kKiswahili_Kenya = 0x0441, + kKonkani_India = 0x0457, + kKorean_Korea = 0x0412, + kKyrgyz_Kyrgyzstan = 0x0440, + kLao_LaoPDR = 0x0454, + kLatvian_Latvia = 0x0426, + kLithuanian_Lithuania = 0x0427, + kLowerSorbian_Germany = 0x082E, + kLuxembourgish_Luxembourg = 0x046E, + kMacedonian_FYROM_FormerYugoslavRepublicOfMacedonia = 0x042F, + kMalay_BruneiDarussalam = 0x083E, + kMalay_Malaysia = 0x043E, + kMalayalam_India = 0x044C, + kMaltese_Malta = 0x043A, + kMaori_NewZealand = 0x0481, + kMapudungun_Chile = 0x047A, + kMarathi_India = 0x044E, + kMohawk_Mohawk = 0x047C, + kMongolian_Cyrillic_Mongolia = 0x0450, + kMongolian_Traditional_PeoplesRepublicOfChina = 0x0850, + kNepali_Nepal = 0x0461, + kNorwegian_Bokmal_Norway = 0x0414, + kNorwegian_Nynorsk_Norway = 0x0814, + kOccitan_France = 0x0482, + kOriya_India = 0x0448, + kPashto_Afghanistan = 0x0463, + kPolish_Poland = 0x0415, + kPortuguese_Brazil = 0x0416, + kPortuguese_Portugal = 0x0816, + kPunjabi_India = 0x0446, + kQuechua_Bolivia = 0x046B, + kQuechua_Ecuador = 0x086B, + kQuechua_Peru = 0x0C6B, + kRomanian_Romania = 0x0418, + kRomansh_Switzerland = 0x0417, + kRussian_Russia = 0x0419, + kSami_Inari_Finland = 0x243B, + kSami_Lule_Norway = 0x103B, + kSami_Lule_Sweden = 0x143B, + kSami_Northern_Finland = 0x0C3B, + kSami_Northern_Norway = 0x043B, + kSami_Northern_Sweden = 0x083B, + kSami_Skolt_Finland = 0x203B, + kSami_Southern_Norway = 0x183B, + kSami_Southern_Sweden = 0x1C3B, + kSanskrit_India = 0x044F, + kSerbian_Cyrillic_BosniaAndHerzegovina = 0x1C1A, + kSerbian_Cyrillic_Serbia = 0x0C1A, + kSerbian_Latin_BosniaAndHerzegovina = 0x181A, + kSerbian_Latin_Serbia = 0x081A, + kSesothoSaLeboa_SouthAfrica = 0x046C, + kSetswana_SouthAfrica = 0x0432, + kSinhala_SriLanka = 0x045B, + kSlovak_Slovakia = 0x041B, + kSlovenian_Slovenia = 0x0424, + kSpanish_Argentina = 0x2C0A, + kSpanish_Bolivia = 0x400A, + kSpanish_Chile = 0x340A, + kSpanish_Colombia = 0x240A, + kSpanish_CostaRica = 0x140A, + kSpanish_DominicanRepublic = 0x1C0A, + kSpanish_Ecuador = 0x300A, + kSpanish_ElSalvador = 0x440A, + kSpanish_Guatemala = 0x100A, + kSpanish_Honduras = 0x480A, + kSpanish_Mexico = 0x080A, + kSpanish_Nicaragua = 0x4C0A, + kSpanish_Panama = 0x180A, + kSpanish_Paraguay = 0x3C0A, + kSpanish_Peru = 0x280A, + kSpanish_PuertoRico = 0x500A, + kSpanish_ModernSort_Spain = 0x0C0A, + kSpanish_TraditionalSort_Spain = 0x040A, + kSpanish_UnitedStates = 0x540A, + kSpanish_Uruguay = 0x380A, + kSpanish_Venezuela = 0x200A, + kSweden_Finland = 0x081D, + kSwedish_Sweden = 0x041D, + kSyriac_Syria = 0x045A, + kTajik_Cyrillic_Tajikistan = 0x0428, + kTamazight_Latin_Algeria = 0x085F, + kTamil_India = 0x0449, + kTatar_Russia = 0x0444, + kTelugu_India = 0x044A, + kThai_Thailand = 0x041E, + kTibetan_PRC = 0x0451, + kTurkish_Turkey = 0x041F, + kTurkmen_Turkmenistan = 0x0442, + kUighur_PRC = 0x0480, + kUkrainian_Ukraine = 0x0422, + kUpperSorbian_Germany = 0x042E, + kUrdu_IslamicRepublicOfPakistan = 0x0420, + kUzbek_Cyrillic_Uzbekistan = 0x0843, + kUzbek_Latin_Uzbekistan = 0x0443, + kVietnamese_Vietnam = 0x042A, + kWelsh_UnitedKingdom = 0x0452, + kWolof_Senegal = 0x0448, + kYakut_Russia = 0x0485, + kYi_PRC = 0x0478, + kYoruba_Nigeria = 0x046A + }; +}; + +class NameTable : public SubTableContainerTable, public RefCounted<NameTable> { + public: + // Unique identifier for a given name record. + class NameEntryId { + public: + NameEntryId(); // C++ port only, must provide default constructor. + NameEntryId(int32_t platform_id, int32_t encoding_id, int32_t language_id, + int32_t name_id); + NameEntryId(const NameEntryId&); + // Make gcc -Wnon-virtual-dtor happy. + virtual ~NameEntryId() {} + + int32_t platform_id() const { return platform_id_; } + int32_t encoding_id() const { return encoding_id_; } + int32_t language_id() const { return language_id_; } + int32_t name_id() const { return name_id_; } + + const NameEntryId& operator=(const NameEntryId& rhs) const; + bool operator==(const NameEntryId& rhs) const; + bool operator<(const NameEntryId& rhs) const; + + // UNIMPLEMENTED: int hashCode() + // String toString() + + private: + mutable int32_t platform_id_; + mutable int32_t encoding_id_; + mutable int32_t language_id_; + mutable int32_t name_id_; + }; + + class NameEntryBuilder; + + // Class to represent a name entry in the name table. + class NameEntry : public RefCounted<NameEntry> { + public: + NameEntry(); + NameEntry(const NameEntryId& name_entry_id, const std::vector<uint8_t>& name_bytes); + NameEntry(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id, + const std::vector<uint8_t>& name_bytes); + virtual ~NameEntry(); + + NameEntryId& name_entry_id() { return name_entry_id_; } + int32_t platform_id() const { return name_entry_id_.platform_id(); } + int32_t encoding_id() const { return name_entry_id_.encoding_id(); } + int32_t language_id() const { return name_entry_id_.language_id(); } + int32_t name_id() const { return name_entry_id_.name_id(); } + + // Get the bytes for name. Returned pointer is the address of private + // member of this class, do not attempt to delete. + std::vector<uint8_t>* NameAsBytes(); + + // C++ port only: get the length of NameAsBytes. + int32_t NameBytesLength(); + + // Returns the name in Unicode as UChar array. + // Note: ICU UChar* convention requires caller to delete[] it. + UChar* Name(); + bool operator==(const NameEntry& rhs) const; + + // UNIMPLEMENTED: String toString() + // int hashCode() + + private: + void Init(int32_t platform_id, int32_t encoding_id, int32_t language_id, + int32_t name_id, const std::vector<uint8_t>* name_bytes); + + NameEntryId name_entry_id_; + std::vector<uint8_t> name_bytes_; + + friend class NameEntryBuilder; + }; + + // Builder of a name entry. + // C++ port: original Java hierarchy inherits from NameEntry. In C++ port, we + // opted not doing so to avoid ref count issues and nasty protected members. + class NameEntryBuilder : public RefCounted<NameEntryBuilder> { + public: + NameEntryBuilder(); + NameEntryBuilder(const NameEntryId& name_entry_id, + const std::vector<uint8_t>& name_bytes); + explicit NameEntryBuilder(const NameEntryId& name_entry_id); + explicit NameEntryBuilder(NameEntry* entry); + virtual ~NameEntryBuilder(); + + virtual void SetName(const UChar* name); + virtual void SetName(const std::vector<uint8_t>& name_bytes); + virtual void SetName(const std::vector<uint8_t>& name_bytes, + int32_t offset, + int32_t length); + + // C++ port only. CALLER_ATTACH is not added because the lifetime shall be + // controlled by this class, therefore the caller shall not increase the ref + // count. + NameEntry* name_entry() { return name_entry_; } + + private: + void Init(int32_t platform_id, int32_t encoding_id, int32_t language_id, + int32_t name_id, const std::vector<uint8_t>* name_bytes); + + Ptr<NameEntry> name_entry_; + }; + typedef std::map<NameEntryId, Ptr<NameEntryBuilder> > NameEntryBuilderMap; + + // An interface for a filter to use with the name entry iterator. This allows + // name entries to be iterated and only those acceptable to the filter will be + // returned. + class NameEntryFilter { + public: + virtual bool Accept(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id) = 0; + // Make gcc -Wnon-virtual-dtor happy. + virtual ~NameEntryFilter() {} + }; + + // C++ port only: an in-place filter to mimic Java Iterator's filtering. + class NameEntryFilterInPlace : public NameEntryFilter { + public: + NameEntryFilterInPlace(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id); + // Make gcc -Wnon-virtual-dtor happy. + virtual ~NameEntryFilterInPlace() {} + + virtual bool Accept(int32_t platform_id, + int32_t encoding_id, + int32_t language_id, + int32_t name_id); + + private: + int32_t platform_id_; + int32_t encoding_id_; + int32_t language_id_; + int32_t name_id_; + }; + + class NameEntryIterator : public RefIterator<NameEntry, NameTable> { + public: + // If filter is NULL, filter through all tables. + explicit NameEntryIterator(NameTable* table); + NameEntryIterator(NameTable* table, NameEntryFilter* filter); + virtual ~NameEntryIterator() {} + + virtual bool HasNext(); + virtual CALLER_ATTACH NameEntry* Next(); + + private: + int32_t name_index_; + NameEntryFilter* filter_; + }; + + // The builder to construct name table for outputting. + class Builder : public SubTableContainerTable::Builder, + public RefCounted<Builder> { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + // Revert the name builders for the name table to the last version that came + // from data. + void RevertNames(); + + // Number of name entry builders contained. + int32_t BuilderCount(); + + // Note: For C++ port, clear() is not implemented. The clear() function + // implies completely remove name entry builders, which is easy in + // Java but will take a lot of efforts in C++ to release the builders + // nicely and correctly. + // TODO(arthurhsu): IMPLEMENT + // Clear the name builders for the name table. + // void clear(); + + // Check the existance of a name entry builder by key. + bool Has(int32_t platform_id, int32_t encoding_id, int32_t language_id, + int32_t name_id); + + // Get name entry builder by key. + CALLER_ATTACH NameEntryBuilder* NameBuilder(int32_t platform_id, + int32_t encoding_id, int32_t language_id, int32_t name_id); + + // Remove name entry builder by key. + bool Remove(int32_t platform_id, int32_t encoding_id, int32_t language_id, + int32_t name_id); + + // FontDataTable::Builder API implementation + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + private: + void Initialize(ReadableFontData* data); + NameEntryBuilderMap* GetNameBuilders(); + + // Note: callers should use the getter funtion provided above to ensure that + // this is lazily initialized instead of accessing directly. + NameEntryBuilderMap name_entry_map_; + }; + + /**************************************************************************** + * public methods of NameTable class + ****************************************************************************/ + virtual ~NameTable(); + + // Get the format used in the name table. + virtual int32_t Format(); + + // Get the number of names in the name table. + virtual int32_t NameCount(); + + // Get the platform id for the given name record. + virtual int32_t PlatformId(int32_t index); + + // Get the encoding id for the given name record. + // see MacintoshEncodingId, WindowsEncodingId, UnicodeEncodingId + virtual int32_t EncodingId(int32_t index); + + // Get the language id for the given name record. + virtual int32_t LanguageId(int32_t index); + + // Get the name id for given name record. + virtual int32_t NameId(int32_t index); + + // Get the name as bytes for the specified name. If there is no entry for the + // requested name, then empty vector is returned. + virtual void NameAsBytes(int32_t index, std::vector<uint8_t>* b); + virtual void NameAsBytes(int32_t platform_id, int32_t encoding_id, + int32_t language_id, int32_t name_id, + std::vector<uint8_t>* b); + + // Get the name as a UChar* for the given name record. If there is no + // encoding conversion available for the name record then a best attempt + // UChar* will be returned. + // Note: ICU UChar* convention requires caller to delete[] it. + virtual UChar* Name(int32_t index); + + // Get the name as a UChar* for the specified name. If there is no entry for + // the requested name then NULL is returned. If there is no encoding + // conversion available for the name then a best attempt UChar* will be + // returned. + // Note: ICU UChar* convention requires caller to delete[] it. + virtual UChar* Name(int32_t platform_id, int32_t encoding_id, + int32_t language_id, int32_t name_id); + + // Note: These functions are renamed in C++ port. Their original Java name is + // nameEntry(). + virtual CALLER_ATTACH NameEntry* GetNameEntry(int32_t index); + virtual CALLER_ATTACH NameEntry* GetNameEntry(int32_t platform_id, + int32_t encoding_id, int32_t language_id, int32_t name_id); + + // Note: Not implemented in C++ port due to complexity and low usage. + // virtual void names(std::set<NameEntryPtr>*); + + // Get the iterator to iterate through all name entries. + virtual CALLER_ATTACH NameEntryIterator* Iterator(); + virtual CALLER_ATTACH NameEntryIterator* Iterator(NameEntryFilter* filter); + + private: + struct Offset { + enum { + kFormat = 0, + kCount = 2, + kStringOffset = 4, + kNameRecordStart = 6, + + // Format 1 - offset from the end of the name records + kLangTagCount = 0, + kLangTagRecord = 2, + + kNameRecordSize = 12, + // Name Records + kNameRecordPlatformId = 0, + kNameRecordEncodingId = 2, + kNameRecordLanguageId = 4, + kNameRecordNameId = 6, + kNameRecordStringLength = 8, + kNameRecordStringOffset = 10 + }; + }; + + // The table shall be constructed using Builder, no direct instantiation. + NameTable(Header* header, ReadableFontData* data); + + // Get the offset to the string data in the name table. + int32_t StringOffset(); + + // Get the offset for the given name record. + int32_t OffsetForNameRecord(int32_t index); + + // Get the length of the string data for the given name record. + int32_t NameLength(int32_t index); + + // Get the offset of the string data for the given name record. + int32_t NameOffset(int32_t index); + + // Note: string literals are returned. Caller shall not attempt to manipulate + // the returned pointer. + static const char* GetEncodingName(int32_t platform_id, int32_t encoding_id); + + // Note: ICU UConverter* convention requires caller to ucnv_close() it. + static UConverter* GetCharset(int32_t platform_id, int32_t encoding_id); + + // Note: Output will be stored in std::vector<uint8_t>* b. Original data in b will be + // erased and replaced with converted name bytes. + static void ConvertToNameBytes(const UChar* name, int32_t platform_id, + int32_t encoding_id, std::vector<uint8_t>* b); + + // Note: ICU UChar* convention requires caller to delete[] it. + static UChar* ConvertFromNameBytes(std::vector<uint8_t>* name_bytes, + int32_t platform_id, int32_t encoding_id); +}; // class NameTable +typedef Ptr<NameTable> NameTablePtr; +typedef Ptr<NameTable::NameEntry> NameEntryPtr; +typedef Ptr<NameTable::Builder> NameTableBuilderPtr; +typedef Ptr<NameTable::NameEntryBuilder> NameEntryBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_NAME_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/os2_table.cc b/gfx/sfntly/cpp/src/sfntly/table/core/os2_table.cc new file mode 100644 index 0000000000..0d37db166f --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/os2_table.cc @@ -0,0 +1,610 @@ +/* + * 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 "sfntly/table/core/os2_table.h" + +#include <algorithm> + +namespace sfntly { +/****************************************************************************** + * Constants + ******************************************************************************/ +const int64_t CodePageRange::kLatin1_1252 = (int64_t)1 << 0; +const int64_t CodePageRange::kLatin2_1250 = (int64_t)1 << (int64_t)1; +const int64_t CodePageRange::kCyrillic_1251 = (int64_t)1 << 2; +const int64_t CodePageRange::kGreek_1253 = (int64_t)1 << 3; +const int64_t CodePageRange::kTurkish_1254 = (int64_t)1 << 4; +const int64_t CodePageRange::kHebrew_1255 = (int64_t)1 << 5; +const int64_t CodePageRange::kArabic_1256 = (int64_t)1 << 6; +const int64_t CodePageRange::kWindowsBaltic_1257 = (int64_t)1 << 7; +const int64_t CodePageRange::kVietnamese_1258 = (int64_t)1 << 8; +const int64_t CodePageRange::kAlternateANSI9 = (int64_t)1 << 9; +const int64_t CodePageRange::kAlternateANSI10 = (int64_t)1 << 10; +const int64_t CodePageRange::kAlternateANSI11 = (int64_t)1 << 11; +const int64_t CodePageRange::kAlternateANSI12 = (int64_t)1 << 12; +const int64_t CodePageRange::kAlternateANSI13 = (int64_t)1 << 13; +const int64_t CodePageRange::kAlternateANSI14 = (int64_t)1 << 14; +const int64_t CodePageRange::kAlternateANSI15 = (int64_t)1 << 15; +const int64_t CodePageRange::kThai_874 = (int64_t)1 << 16; +const int64_t CodePageRange::kJapanJIS_932 = (int64_t)1 << 17; +const int64_t CodePageRange::kChineseSimplified_936 = (int64_t)1 << 18; +const int64_t CodePageRange::kKoreanWansung_949 = (int64_t)1 << 19; +const int64_t CodePageRange::kChineseTraditional_950 = (int64_t)1 << 20; +const int64_t CodePageRange::kKoreanJohab_1361 = (int64_t)1 << 21; +const int64_t CodePageRange::kAlternateANSI22 = (int64_t)1 << 22; +const int64_t CodePageRange::kAlternateANSI23 = (int64_t)1 << 23; +const int64_t CodePageRange::kAlternateANSI24 = (int64_t)1 << 24; +const int64_t CodePageRange::kAlternateANSI25 = (int64_t)1 << 25; +const int64_t CodePageRange::kAlternateANSI26 = (int64_t)1 << 26; +const int64_t CodePageRange::kAlternateANSI27 = (int64_t)1 << 27; +const int64_t CodePageRange::kAlternateANSI28 = (int64_t)1 << 28; +const int64_t CodePageRange::kMacintoshCharacterSet = (int64_t)1 << 29; +const int64_t CodePageRange::kOEMCharacterSet = (int64_t)1 << 30; +const int64_t CodePageRange::kSymbolCharacterSet = (int64_t)1 << 31; +const int64_t CodePageRange::kReservedForOEM32 = (int64_t)1 << 32; +const int64_t CodePageRange::kReservedForOEM33 = (int64_t)1 << 33; +const int64_t CodePageRange::kReservedForOEM34 = (int64_t)1 << 34; +const int64_t CodePageRange::kReservedForOEM35 = (int64_t)1 << 35; +const int64_t CodePageRange::kReservedForOEM36 = (int64_t)1 << 36; +const int64_t CodePageRange::kReservedForOEM37 = (int64_t)1 << 37; +const int64_t CodePageRange::kReservedForOEM38 = (int64_t)1 << 38; +const int64_t CodePageRange::kReservedForOEM39 = (int64_t)1 << 39; +const int64_t CodePageRange::kReservedForOEM40 = (int64_t)1 << 40; +const int64_t CodePageRange::kReservedForOEM41 = (int64_t)1 << 41; +const int64_t CodePageRange::kReservedForOEM42 = (int64_t)1 << 42; +const int64_t CodePageRange::kReservedForOEM43 = (int64_t)1 << 43; +const int64_t CodePageRange::kReservedForOEM44 = (int64_t)1 << 44; +const int64_t CodePageRange::kReservedForOEM45 = (int64_t)1 << 45; +const int64_t CodePageRange::kReservedForOEM46 = (int64_t)1 << 46; +const int64_t CodePageRange::kReservedForOEM47 = (int64_t)1 << 47; +const int64_t CodePageRange::kIBMGreek_869 = (int64_t)1 << 48; +const int64_t CodePageRange::kMSDOSRussion_866 = (int64_t)1 << 49; +const int64_t CodePageRange::kMSDOSNordic_865 = (int64_t)1 << 50; +const int64_t CodePageRange::kArabic_864 = (int64_t)1 << 51; +const int64_t CodePageRange::kMSDOSCanadianFrench_863 = (int64_t)1 << 52; +const int64_t CodePageRange::kHebrew_862 = (int64_t)1 << 53; +const int64_t CodePageRange::kMSDOSIcelandic_861 = (int64_t)1 << 54; +const int64_t CodePageRange::kMSDOSPortugese_860 = (int64_t)1 << 55; +const int64_t CodePageRange::kIBMTurkish_857 = (int64_t)1 << 56; +const int64_t CodePageRange::kIBMCyrillic_855 = (int64_t)1 << 57; +const int64_t CodePageRange::kLatin2_852 = (int64_t)1 << 58; +const int64_t CodePageRange::kMSDOSBaltic_775 = (int64_t)1 << 59; +const int64_t CodePageRange::kGreek_737 = (int64_t)1 << 60; +const int64_t CodePageRange::kArabic_708 = (int64_t)1 << 61; +const int64_t CodePageRange::kLatin1_850 = (int64_t)1 << 62; +const int64_t CodePageRange::kUS_437 = (int64_t)1 << 63; + +/****************************************************************************** + * struct UnicodeRange + ******************************************************************************/ +int32_t UnicodeRange::range(int32_t bit) { + if (bit < 0 || bit > kLast) { + return -1; + } + return bit; +} + +/****************************************************************************** + * class OS2Table + ******************************************************************************/ +OS2Table::~OS2Table() {} + +int32_t OS2Table::TableVersion() { + return data_->ReadUShort(Offset::kVersion); +} + +int32_t OS2Table::XAvgCharWidth() { + return data_->ReadShort(Offset::kXAvgCharWidth); +} + +int32_t OS2Table::UsWeightClass() { + return data_->ReadUShort(Offset::kUsWeightClass); +} + +int32_t OS2Table::UsWidthClass() { + return data_->ReadUShort(Offset::kUsWidthClass); +} + +int32_t OS2Table::FsType() { + return data_->ReadUShort(Offset::kFsType); +} + +int32_t OS2Table::YSubscriptXSize() { + return data_->ReadShort(Offset::kYSubscriptXSize); +} + +int32_t OS2Table::YSubscriptYSize() { + return data_->ReadShort(Offset::kYSubscriptYSize); +} + +int32_t OS2Table::YSubscriptXOffset() { + return data_->ReadShort(Offset::kYSubscriptXOffset); +} + +int32_t OS2Table::YSubscriptYOffset() { + return data_->ReadShort(Offset::kYSubscriptYOffset); +} + +int32_t OS2Table::YSuperscriptXSize() { + return data_->ReadShort(Offset::kYSuperscriptXSize); +} + +int32_t OS2Table::YSuperscriptYSize() { + return data_->ReadShort(Offset::kYSuperscriptYSize); +} + +int32_t OS2Table::YSuperscriptXOffset() { + return data_->ReadShort(Offset::kYSuperscriptXOffset); +} + +int32_t OS2Table::YSuperscriptYOffset() { + return data_->ReadShort(Offset::kYSuperscriptYOffset); +} + +int32_t OS2Table::YStrikeoutSize() { + return data_->ReadShort(Offset::kYStrikeoutSize); +} + +int32_t OS2Table::YStrikeoutPosition() { + return data_->ReadShort(Offset::kYStrikeoutPosition); +} + +int32_t OS2Table::SFamilyClass() { + return data_->ReadShort(Offset::kSFamilyClass); +} + +void OS2Table::Panose(std::vector<uint8_t>* value) { + assert(value); + value->clear(); + value->resize(10); + data_->ReadBytes(Offset::kPanose, &((*value)[0]), 0, 10); +} + +int64_t OS2Table::UlUnicodeRange1() { + return data_->ReadULong(Offset::kUlUnicodeRange1); +} + +int64_t OS2Table::UlUnicodeRange2() { + return data_->ReadULong(Offset::kUlUnicodeRange2); +} + +int64_t OS2Table::UlUnicodeRange3() { + return data_->ReadULong(Offset::kUlUnicodeRange3); +} + +int64_t OS2Table::UlUnicodeRange4() { + return data_->ReadULong(Offset::kUlUnicodeRange4); +} + +void OS2Table::AchVendId(std::vector<uint8_t>* b) { + assert(b); + b->clear(); + b->resize(4); + data_->ReadBytes(Offset::kAchVendId, &((*b)[0]), 0, 4); +} + +int32_t OS2Table::FsSelection() { + return data_->ReadUShort(Offset::kFsSelection); +} + +int32_t OS2Table::UsFirstCharIndex() { + return data_->ReadUShort(Offset::kUsFirstCharIndex); +} + +int32_t OS2Table::UsLastCharIndex() { + return data_->ReadUShort(Offset::kUsLastCharIndex); +} + +int32_t OS2Table::STypoAscender() { + return data_->ReadShort(Offset::kSTypoAscender); +} + +int32_t OS2Table::STypoDescender() { + return data_->ReadShort(Offset::kSTypoDescender); +} + +int32_t OS2Table::STypoLineGap() { + return data_->ReadShort(Offset::kSTypoLineGap); +} + +int32_t OS2Table::UsWinAscent() { + return data_->ReadUShort(Offset::kUsWinAscent); +} + +int32_t OS2Table::UsWinDescent() { + return data_->ReadUShort(Offset::kUsWinDescent); +} + +int64_t OS2Table::UlCodePageRange1() { + return data_->ReadULong(Offset::kUlCodePageRange1); +} + +int64_t OS2Table::UlCodePageRange2() { + return data_->ReadULong(Offset::kUlCodePageRange2); +} + +int32_t OS2Table::SxHeight() { + return data_->ReadShort(Offset::kSxHeight); +} + +int32_t OS2Table::SCapHeight() { + return data_->ReadShort(Offset::kSCapHeight); +} + +int32_t OS2Table::UsDefaultChar() { + return data_->ReadUShort(Offset::kUsDefaultChar); +} + +int32_t OS2Table::UsBreakChar() { + return data_->ReadUShort(Offset::kUsBreakChar); +} + +int32_t OS2Table::UsMaxContext() { + return data_->ReadUShort(Offset::kUsMaxContext); +} + +OS2Table::OS2Table(Header* header, ReadableFontData* data) + : Table(header, data) { +} + +/****************************************************************************** + * class OS2Table::Builder + ******************************************************************************/ +OS2Table::Builder::Builder(Header* header, WritableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +OS2Table::Builder::Builder(Header* header, ReadableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +OS2Table::Builder::~Builder() {} + +CALLER_ATTACH FontDataTable* OS2Table::Builder::SubBuildTable( + ReadableFontData* data) { + FontDataTablePtr table = new OS2Table(header(), data); + return table.Detach(); +} + +CALLER_ATTACH OS2Table::Builder* + OS2Table::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr<OS2Table::Builder> builder; + builder = new OS2Table::Builder(header, data); + return builder.Detach(); +} + +int32_t OS2Table::Builder::TableVersion() { + return InternalReadData()->ReadUShort(Offset::kVersion); +} + +void OS2Table::Builder::SetTableVersion(int32_t version) { + InternalWriteData()->WriteUShort(Offset::kVersion, version); +} + +int32_t OS2Table::Builder::XAvgCharWidth() { + return InternalReadData()->ReadShort(Offset::kXAvgCharWidth); +} + +void OS2Table::Builder::SetXAvgCharWidth(int32_t width) { + InternalWriteData()->WriteShort(Offset::kXAvgCharWidth, width); +} + +int32_t OS2Table::Builder::UsWeightClass() { + return InternalReadData()->ReadUShort(Offset::kUsWeightClass); +} + +void OS2Table::Builder::SetUsWeightClass(int32_t weight) { + InternalWriteData()->WriteUShort(Offset::kUsWeightClass, weight); +} + +int32_t OS2Table::Builder::UsWidthClass() { + return InternalReadData()->ReadUShort(Offset::kUsWidthClass); +} + +void OS2Table::Builder::SetUsWidthClass(int32_t width) { + InternalWriteData()->WriteUShort(Offset::kUsWidthClass, width); +} + +int32_t OS2Table::Builder::FsType() { + return InternalReadData()->ReadUShort(Offset::kFsType); +} + +void OS2Table::Builder::SetFsType(int32_t fs_type) { + InternalWriteData()->WriteUShort(Offset::kFsType, fs_type); +} + +int32_t OS2Table::Builder::YSubscriptXSize() { + return InternalReadData()->ReadShort(Offset::kYSubscriptXSize); +} + +void OS2Table::Builder::SetYSubscriptXSize(int32_t size) { + InternalWriteData()->WriteShort(Offset::kYSubscriptXSize, size); +} + +int32_t OS2Table::Builder::YSubscriptYSize() { + return InternalReadData()->ReadShort(Offset::kYSubscriptYSize); +} + +void OS2Table::Builder::SetYSubscriptYSize(int32_t size) { + InternalWriteData()->WriteShort(Offset::kYSubscriptYSize, size); +} + +int32_t OS2Table::Builder::YSubscriptXOffset() { + return InternalReadData()->ReadShort(Offset::kYSubscriptXOffset); +} + +void OS2Table::Builder::SetYSubscriptXOffset(int32_t offset) { + InternalWriteData()->WriteShort(Offset::kYSubscriptXOffset, offset); +} + +int32_t OS2Table::Builder::YSubscriptYOffset() { + return InternalReadData()->ReadShort(Offset::kYSubscriptYOffset); +} + +void OS2Table::Builder::SetYSubscriptYOffset(int32_t offset) { + InternalWriteData()->WriteShort(Offset::kYSubscriptYOffset, offset); +} + +int32_t OS2Table::Builder::YSuperscriptXSize() { + return InternalReadData()->ReadShort(Offset::kYSuperscriptXSize); +} + +void OS2Table::Builder::SetYSuperscriptXSize(int32_t size) { + InternalWriteData()->WriteShort(Offset::kYSuperscriptXSize, size); +} + +int32_t OS2Table::Builder::YSuperscriptYSize() { + return InternalReadData()->ReadShort(Offset::kYSuperscriptYSize); +} + +void OS2Table::Builder::SetYSuperscriptYSize(int32_t size) { + InternalWriteData()->WriteShort(Offset::kYSuperscriptYSize, size); +} + +int32_t OS2Table::Builder::YSuperscriptXOffset() { + return InternalReadData()->ReadShort(Offset::kYSuperscriptXOffset); +} + +void OS2Table::Builder::SetYSuperscriptXOffset(int32_t offset) { + InternalWriteData()->WriteShort(Offset::kYSuperscriptXOffset, offset); +} + +int32_t OS2Table::Builder::YSuperscriptYOffset() { + return InternalReadData()->ReadShort(Offset::kYSuperscriptYOffset); +} + +void OS2Table::Builder::SetYSuperscriptYOffset(int32_t offset) { + InternalWriteData()->WriteShort(Offset::kYSuperscriptYOffset, offset); +} + +int32_t OS2Table::Builder::YStrikeoutSize() { + return InternalReadData()->ReadShort(Offset::kYStrikeoutSize); +} + +void OS2Table::Builder::SetYStrikeoutSize(int32_t size) { + InternalWriteData()->WriteShort(Offset::kYStrikeoutSize, size); +} + +int32_t OS2Table::Builder::YStrikeoutPosition() { + return InternalReadData()->ReadShort(Offset::kYStrikeoutPosition); +} + +void OS2Table::Builder::SetYStrikeoutPosition(int32_t position) { + InternalWriteData()->WriteShort(Offset::kYStrikeoutPosition, position); +} + +int32_t OS2Table::Builder::SFamilyClass() { + return InternalReadData()->ReadShort(Offset::kSFamilyClass); +} + +void OS2Table::Builder::SetSFamilyClass(int32_t family) { + InternalWriteData()->WriteShort(Offset::kSFamilyClass, family); +} + +void OS2Table::Builder::Panose(std::vector<uint8_t>* value) { + assert(value); + value->clear(); + value->resize(Offset::kPanoseLength); + InternalReadData()->ReadBytes(Offset::kPanose, + &((*value)[0]), + 0, + Offset::kPanoseLength); +} + +void OS2Table::Builder::SetPanose(std::vector<uint8_t>* panose) { + assert(panose); + if (panose->size() != Offset::kPanoseLength) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalArgumentException("Panose bytes must be exactly 10 in length"); +#endif + return; + } + InternalWriteData()->WriteBytes(Offset::kPanose, panose); +} + +int64_t OS2Table::Builder::UlUnicodeRange1() { + return InternalReadData()->ReadULong(Offset::kUlUnicodeRange1); +} + +void OS2Table::Builder::SetUlUnicodeRange1(int64_t range) { + InternalWriteData()->WriteULong(Offset::kUlUnicodeRange1, range); +} + +int64_t OS2Table::Builder::UlUnicodeRange2() { + return InternalReadData()->ReadULong(Offset::kUlUnicodeRange2); +} + +void OS2Table::Builder::SetUlUnicodeRange2(int64_t range) { + InternalWriteData()->WriteULong(Offset::kUlUnicodeRange2, range); +} + +int64_t OS2Table::Builder::UlUnicodeRange3() { + return InternalReadData()->ReadULong(Offset::kUlUnicodeRange3); +} + +void OS2Table::Builder::SetUlUnicodeRange3(int64_t range) { + InternalWriteData()->WriteULong(Offset::kUlUnicodeRange3, range); +} + +int64_t OS2Table::Builder::UlUnicodeRange4() { + return InternalReadData()->ReadULong(Offset::kUlUnicodeRange4); +} + +void OS2Table::Builder::SetUlUnicodeRange4(int64_t range) { + InternalWriteData()->WriteULong(Offset::kUlUnicodeRange4, range); +} + +void OS2Table::Builder::AchVendId(std::vector<uint8_t>* b) { + assert(b); + b->clear(); + b->resize(4); + InternalReadData()->ReadBytes(Offset::kAchVendId, &((*b)[0]), 0, 4); +} + +void OS2Table::Builder::SetAchVendId(std::vector<uint8_t>* b) { + assert(b); + assert(b->size()); + InternalWriteData()->WriteBytesPad(Offset::kAchVendId, + b, + 0, + std::min<size_t>( + (size_t)Offset::kAchVendIdLength, + b->size()), + static_cast<uint8_t>(' ')); +} + +int32_t OS2Table::Builder::FsSelection() { + return InternalReadData()->ReadUShort(Offset::kFsSelection); +} + +void OS2Table::Builder::SetFsSelection(int32_t fs_selection) { + InternalWriteData()->WriteUShort(Offset::kFsSelection, fs_selection); +} + +int32_t OS2Table::Builder::UsFirstCharIndex() { + return InternalReadData()->ReadUShort(Offset::kUsFirstCharIndex); +} + +void OS2Table::Builder::SetUsFirstCharIndex(int32_t first_index) { + InternalWriteData()->WriteUShort(Offset::kUsFirstCharIndex, first_index); +} + +int32_t OS2Table::Builder::UsLastCharIndex() { + return InternalReadData()->ReadUShort(Offset::kUsLastCharIndex); +} + +void OS2Table::Builder::SetUsLastCharIndex(int32_t last_index) { + InternalWriteData()->WriteUShort(Offset::kUsLastCharIndex, last_index); +} + +int32_t OS2Table::Builder::STypoAscender() { + return InternalReadData()->ReadShort(Offset::kSTypoAscender); +} + +void OS2Table::Builder::SetSTypoAscender(int32_t ascender) { + InternalWriteData()->WriteShort(Offset::kSTypoAscender, ascender); +} + +int32_t OS2Table::Builder::STypoDescender() { + return InternalReadData()->ReadShort(Offset::kSTypoDescender); +} + +void OS2Table::Builder::SetSTypoDescender(int32_t descender) { + InternalWriteData()->WriteShort(Offset::kSTypoDescender, descender); +} + +int32_t OS2Table::Builder::STypoLineGap() { + return InternalReadData()->ReadShort(Offset::kSTypoLineGap); +} + +void OS2Table::Builder::SetSTypoLineGap(int32_t line_gap) { + InternalWriteData()->WriteShort(Offset::kSTypoLineGap, line_gap); +} + +int32_t OS2Table::Builder::UsWinAscent() { + return InternalReadData()->ReadUShort(Offset::kUsWinAscent); +} + +void OS2Table::Builder::SetUsWinAscent(int32_t ascent) { + InternalWriteData()->WriteUShort(Offset::kUsWinAscent, ascent); +} + +int32_t OS2Table::Builder::UsWinDescent() { + return InternalReadData()->ReadUShort(Offset::kUsWinDescent); +} + +void OS2Table::Builder::SetUsWinDescent(int32_t descent) { + InternalWriteData()->WriteUShort(Offset::kUsWinDescent, descent); +} + +int64_t OS2Table::Builder::UlCodePageRange1() { + return InternalReadData()->ReadULong(Offset::kUlCodePageRange1); +} + +void OS2Table::Builder::SetUlCodePageRange1(int64_t range) { + InternalWriteData()->WriteULong(Offset::kUlCodePageRange1, range); +} + +int64_t OS2Table::Builder::UlCodePageRange2() { + return InternalReadData()->ReadULong(Offset::kUlCodePageRange2); +} + +void OS2Table::Builder::SetUlCodePageRange2(int64_t range) { + InternalWriteData()->WriteULong(Offset::kUlCodePageRange2, range); +} + +int32_t OS2Table::Builder::SxHeight() { + return InternalReadData()->ReadShort(Offset::kSxHeight); +} + +void OS2Table::Builder::SetSxHeight(int32_t height) { + InternalWriteData()->WriteShort(Offset::kSxHeight, height); +} + +int32_t OS2Table::Builder::SCapHeight() { + return InternalReadData()->ReadShort(Offset::kSCapHeight); +} + +void OS2Table::Builder::SetSCapHeight(int32_t height) { + InternalWriteData()->WriteShort(Offset::kSCapHeight, height); +} + +int32_t OS2Table::Builder::UsDefaultChar() { + return InternalReadData()->ReadUShort(Offset::kUsDefaultChar); +} + +void OS2Table::Builder::SetUsDefaultChar(int32_t default_char) { + InternalWriteData()->WriteUShort(Offset::kUsDefaultChar, default_char); +} + +int32_t OS2Table::Builder::UsBreakChar() { + return InternalReadData()->ReadUShort(Offset::kUsBreakChar); +} + +void OS2Table::Builder::SetUsBreakChar(int32_t break_char) { + InternalWriteData()->WriteUShort(Offset::kUsBreakChar, break_char); +} + +int32_t OS2Table::Builder::UsMaxContext() { + return InternalReadData()->ReadUShort(Offset::kUsMaxContext); +} + +void OS2Table::Builder::SetUsMaxContext(int32_t max_context) { + InternalWriteData()->WriteUShort(Offset::kUsMaxContext, max_context); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/core/os2_table.h b/gfx/sfntly/cpp/src/sfntly/table/core/os2_table.h new file mode 100644 index 0000000000..6057412bcf --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/core/os2_table.h @@ -0,0 +1,508 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_OS2_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_OS2_TABLE_H_ + +#include "sfntly/port/refcount.h" +#include "sfntly/table/table.h" +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +struct WeightClass { + enum { + kThin = 100, + kExtraLight = 200, + kUltraLight = 200, + kLight = 300, + kNormal = 400, + kRegular = 400, + kMedium = 500, + kSemiBold = 600, + kDemiBold = 600, + kBold = 700, + kExtraBold = 800, + kUltraBold = 800, + kBlack = 900, + kHeavy = 900 + }; +}; + +struct WidthClass { + enum { + kUltraCondensed = 1, + kExtraCondensed = 2, + kCondensed = 3, + kSemiCondensed = 4, + kMedium = 5, + kNormal = 5, + kSemiExpanded = 6, + kExpanded = 7, + kExtraExpanded = 8, + kUltraExpanded = 9 + }; +}; + +// Flags to indicate the embedding licensing rights for a font. +struct EmbeddingFlags { + enum { + kReserved0 = 1 << 0, + kRestrictedLicenseEmbedding = 1 << 1, + kPreviewAndPrintEmbedding = 1 << 2, + kEditableEmbedding = 1 << 3, + kReserved4 = 1 << 4, + kReserved5 = 1 << 5, + kReserved6 = 1 << 6, + kReserved7 = 1 << 7, + kNoSubsetting = 1 << 8, + kBitmapEmbeddingOnly = 1 << 9, + kReserved10 = 1 << 10, + kReserved11 = 1 << 11, + kReserved12 = 1 << 12, + kReserved13 = 1 << 13, + kReserved14 = 1 << 14, + kReserved15 = 1 << 15 + }; +}; + +struct UnicodeRange { + enum { + // Do NOT reorder. This enum relies on the ordering of the data matching the + // ordinal numbers of the properties. + kBasicLatin, + kLatin1Supplement, + kLatinExtendedA, + kLatinExtendedB, + kIPAExtensions, + kSpacingModifierLetters, + kCombiningDiacriticalMarks, + kGreekAndCoptic, + kCoptic, + kCyrillic, + kArmenian, + kHebrew, + kVai, + kArabic, + kNKo, + kDevanagari, + kBengali, + kGurmukhi, + kGujarati, + kOriya, + kTamil, + kTelugu, + kKannada, + kMalayalam, + kThai, + kLao, + kGeorgian, + kBalinese, + kHangulJamo, + kLatinExtendedAdditional, + kGreekExtended, + kGeneralPunctuation, + kSuperscriptsAndSubscripts, + kCurrencySymbols, + kNumberForms, + kArrows, + kMathematicalOperators, + kMiscTechnical, + kControlPictures, + kOCR, + kEnclosedAlphanumerics, + kBoxDrawing, + kBlockElements, + kGeometricShapes, + kMiscSymbols, + kDingbats, + kCJKSymbolsAndPunctuation, + kHiragana, + kKatakana, + kBopomofo, + kHangulCompatibilityJamo, + kPhagspa, + kEnclosedCJKLettersAndMonths, + kCJKCompatibility, + kHangulSyllables, + kNonPlane0, + kPhoenician, + kCJKUnifiedIdeographs, + kPrivateUseAreaPlane0, + kCJKStrokes, + kAlphabeticPresentationForms, + kArabicPresentationFormsA, + kCombiningHalfMarks, + kVerticalForms, + kSmallFormVariants, + kArabicPresentationFormsB, + kHalfwidthAndFullwidthForms, + kSpecials, + kTibetan, + kSyriac, + kThaana, + kSinhala, + kMyanmar, + kEthiopic, + kCherokee, + kUnifiedCanadianAboriginalSyllabics, + kOgham, + kRunic, + kKhmer, + kMongolian, + kBraillePatterns, + kYiSyllables, + kTagalog, + kOldItalic, + kGothic, + kDeseret, + kMusicalSymbols, + kMathematicalAlphanumericSymbols, + kPrivateUsePlane15And16, + kVariationSelectors, + kTags, + kLimbu, + kTaiLe, + kNewTaiLue, + kBuginese, + kGlagolitic, + kTifnagh, + kYijingHexagramSymbols, + kSylotiNagari, + kLinearB, + kAncientGreekNumbers, + kUgaritic, + kOldPersian, + kShavian, + kOsmanya, + kCypriotSyllabary, + kKharoshthi, + kTaiXuanJingSymbols, + kCuneiform, + kCountingRodNumerals, + kSudanese, + kLepcha, + kOlChiki, + kSaurashtra, + kKayahLi, + kRejang, + kCharm, + kAncientSymbols, + kPhaistosDisc, + kCarian, + kDominoTiles, + kReserved123, + kReserved124, + kReserved125, + kReserved126, + kReserved127, + kLast = kReserved127 + }; + + int32_t range(int32_t bit); + // UNIMPLEMENTED: EnumSet<UnicodeRange> asSet(long range1, long range2, + // long range3, long range4) + // long[] asArray(EnumSet<UnicodeRange> rangeSet) +}; + +struct FsSelection { + enum { + kITALIC = 1 << 0, + kUNDERSCORE = 1 << 1, + kNEGATIVE = 1 << 2, + kOUTLINED = 1 << 3, + kSTRIKEOUT = 1 << 4, + kBOLD = 1 << 5, + kREGULAR = 1 << 6, + kUSE_TYPO_METRICS = 1 << 7, + kWWS = 1 << 8, + kOBLIQUE = 1 << 9 + }; + // UNIMPLEMENTED: EnumSet<FsSelection> asSet(long range1, long range2, + // long range3, long range4) + // long[] asArray(EnumSet<FsSelection> rangeSet) +}; + +// C++ port only: C++ does not support 64-bit enums until C++0x. For better +// portability, we need to use static const int64_t instead. +struct CodePageRange { + static const int64_t kLatin1_1252; + static const int64_t kLatin2_1250; + static const int64_t kCyrillic_1251; + static const int64_t kGreek_1253; + static const int64_t kTurkish_1254; + static const int64_t kHebrew_1255; + static const int64_t kArabic_1256; + static const int64_t kWindowsBaltic_1257; + static const int64_t kVietnamese_1258; + static const int64_t kAlternateANSI9; + static const int64_t kAlternateANSI10; + static const int64_t kAlternateANSI11; + static const int64_t kAlternateANSI12; + static const int64_t kAlternateANSI13; + static const int64_t kAlternateANSI14; + static const int64_t kAlternateANSI15; + static const int64_t kThai_874; + static const int64_t kJapanJIS_932; + static const int64_t kChineseSimplified_936; + static const int64_t kKoreanWansung_949; + static const int64_t kChineseTraditional_950; + static const int64_t kKoreanJohab_1361; + static const int64_t kAlternateANSI22; + static const int64_t kAlternateANSI23; + static const int64_t kAlternateANSI24; + static const int64_t kAlternateANSI25; + static const int64_t kAlternateANSI26; + static const int64_t kAlternateANSI27; + static const int64_t kAlternateANSI28; + static const int64_t kMacintoshCharacterSet; + static const int64_t kOEMCharacterSet; + static const int64_t kSymbolCharacterSet; + static const int64_t kReservedForOEM32; + static const int64_t kReservedForOEM33; + static const int64_t kReservedForOEM34; + static const int64_t kReservedForOEM35; + static const int64_t kReservedForOEM36; + static const int64_t kReservedForOEM37; + static const int64_t kReservedForOEM38; + static const int64_t kReservedForOEM39; + static const int64_t kReservedForOEM40; + static const int64_t kReservedForOEM41; + static const int64_t kReservedForOEM42; + static const int64_t kReservedForOEM43; + static const int64_t kReservedForOEM44; + static const int64_t kReservedForOEM45; + static const int64_t kReservedForOEM46; + static const int64_t kReservedForOEM47; + static const int64_t kIBMGreek_869; + static const int64_t kMSDOSRussion_866; + static const int64_t kMSDOSNordic_865; + static const int64_t kArabic_864; + static const int64_t kMSDOSCanadianFrench_863; + static const int64_t kHebrew_862; + static const int64_t kMSDOSIcelandic_861; + static const int64_t kMSDOSPortugese_860; + static const int64_t kIBMTurkish_857; + static const int64_t kIBMCyrillic_855; + static const int64_t kLatin2_852; + static const int64_t kMSDOSBaltic_775; + static const int64_t kGreek_737; + static const int64_t kArabic_708; + static const int64_t kLatin1_850; + static const int64_t kUS_437; + + // UNIMPLEMENTED: EnumSet<CodePageRange> asSet(long range1, long range2, + // long range3, long range4) + // long[] asArray(EnumSet<CodePageRange> rangeSet) +}; + +// An OS/2 table - 'OS/2'. +class OS2Table : public Table, public RefCounted<OS2Table> { + public: + // A builder for the OS/2 table = 'OS/2'. + class Builder : public TableBasedTableBuilder, public RefCounted<Builder> { + public: + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + int32_t TableVersion(); + void SetTableVersion(int32_t version); + int32_t XAvgCharWidth(); + void SetXAvgCharWidth(int32_t width); + int32_t UsWeightClass(); + void SetUsWeightClass(int32_t weight); + int32_t UsWidthClass(); + void SetUsWidthClass(int32_t width); + // UNIMPLEMENTED: EnumSet<EmbeddingFlags> fsType() + // void setFsType(EnumSeT<EmbeddingFlags> flagSet) + int32_t FsType(); + void SetFsType(int32_t fs_type); + int32_t YSubscriptXSize(); + void SetYSubscriptXSize(int32_t size); + int32_t YSubscriptYSize(); + void SetYSubscriptYSize(int32_t size); + int32_t YSubscriptXOffset(); + void SetYSubscriptXOffset(int32_t offset); + int32_t YSubscriptYOffset(); + void SetYSubscriptYOffset(int32_t offset); + int32_t YSuperscriptXSize(); + void SetYSuperscriptXSize(int32_t size); + int32_t YSuperscriptYSize(); + void SetYSuperscriptYSize(int32_t size); + int32_t YSuperscriptXOffset(); + void SetYSuperscriptXOffset(int32_t offset); + int32_t YSuperscriptYOffset(); + void SetYSuperscriptYOffset(int32_t offset); + int32_t YStrikeoutSize(); + void SetYStrikeoutSize(int32_t size); + int32_t YStrikeoutPosition(); + void SetYStrikeoutPosition(int32_t position); + int32_t SFamilyClass(); + void SetSFamilyClass(int32_t family); + void Panose(std::vector<uint8_t>* value); + void SetPanose(std::vector<uint8_t>* panose); + int64_t UlUnicodeRange1(); + void SetUlUnicodeRange1(int64_t range); + int64_t UlUnicodeRange2(); + void SetUlUnicodeRange2(int64_t range); + int64_t UlUnicodeRange3(); + void SetUlUnicodeRange3(int64_t range); + int64_t UlUnicodeRange4(); + void SetUlUnicodeRange4(int64_t range); + // UNIMPLEMENTED: EnumSet<UnicodeRange> UlUnicodeRange() + // setUlUnicodeRange(EnumSet<UnicodeRange> rangeSet) + void AchVendId(std::vector<uint8_t>* b); + // This field is 4 bytes in length and only the first 4 bytes of the byte + // array will be written. If the byte array is less than 4 bytes it will be + // padded out with space characters (0x20). + // @param b ach Vendor Id + void SetAchVendId(std::vector<uint8_t>* b); + // UNIMPLEMENTED: public EnumSet<FsSelection> fsSelection() + int32_t FsSelection(); + void SetFsSelection(int32_t fs_selection); + int32_t UsFirstCharIndex(); + void SetUsFirstCharIndex(int32_t first_index); + int32_t UsLastCharIndex(); + void SetUsLastCharIndex(int32_t last_index); + int32_t STypoAscender(); + void SetSTypoAscender(int32_t ascender); + int32_t STypoDescender(); + void SetSTypoDescender(int32_t descender); + int32_t STypoLineGap(); + void SetSTypoLineGap(int32_t line_gap); + int32_t UsWinAscent(); + void SetUsWinAscent(int32_t ascent); + int32_t UsWinDescent(); + void SetUsWinDescent(int32_t descent); + int64_t UlCodePageRange1(); + void SetUlCodePageRange1(int64_t range); + int64_t UlCodePageRange2(); + void SetUlCodePageRange2(int64_t range); + // UNIMPLEMENTED: EnumSet<CodePageRange> ulCodePageRange() + // void setUlCodePageRange(EnumSet<CodePageRange> rangeSet) + int32_t SxHeight(); + void SetSxHeight(int32_t height); + int32_t SCapHeight(); + void SetSCapHeight(int32_t height); + int32_t UsDefaultChar(); + void SetUsDefaultChar(int32_t default_char); + int32_t UsBreakChar(); + void SetUsBreakChar(int32_t break_char); + int32_t UsMaxContext(); + void SetUsMaxContext(int32_t max_context); + }; + + ~OS2Table(); + + int32_t TableVersion(); + int32_t XAvgCharWidth(); + int32_t UsWeightClass(); + int32_t UsWidthClass(); + // UNIMPLEMENTED: public EnumSet<EmbeddingFlags> fsType() + int32_t FsType(); + int32_t YSubscriptXSize(); + int32_t YSubscriptYSize(); + int32_t YSubscriptXOffset(); + int32_t YSubscriptYOffset(); + int32_t YSuperscriptXSize(); + int32_t YSuperscriptYSize(); + int32_t YSuperscriptXOffset(); + int32_t YSuperscriptYOffset(); + int32_t YStrikeoutSize(); + int32_t YStrikeoutPosition(); + int32_t SFamilyClass(); + void Panose(std::vector<uint8_t>* value); + int64_t UlUnicodeRange1(); + int64_t UlUnicodeRange2(); + int64_t UlUnicodeRange3(); + int64_t UlUnicodeRange4(); + // UNIMPLEMENTED: public EnumSet<UnicodeRange> UlUnicodeRange() + void AchVendId(std::vector<uint8_t>* b); + // UNIMPLEMENTED: public EnumSet<FsSelection> fsSelection() + int32_t FsSelection(); + int32_t UsFirstCharIndex(); + int32_t UsLastCharIndex(); + int32_t STypoAscender(); + int32_t STypoDescender(); + int32_t STypoLineGap(); + int32_t UsWinAscent(); + int32_t UsWinDescent(); + int64_t UlCodePageRange1(); + int64_t UlCodePageRange2(); + // UNIMPLEMENTED: public EnumSet<CodePageRange> ulCodePageRange() + int32_t SxHeight(); + int32_t SCapHeight(); + int32_t UsDefaultChar(); + int32_t UsBreakChar(); + int32_t UsMaxContext(); + + private: + struct Offset { + enum { + kVersion = 0, + kXAvgCharWidth = 2, + kUsWeightClass = 4, + kUsWidthClass = 6, + kFsType = 8, + kYSubscriptXSize = 10, + kYSubscriptYSize = 12, + kYSubscriptXOffset = 14, + kYSubscriptYOffset = 16, + kYSuperscriptXSize = 18, + kYSuperscriptYSize = 20, + kYSuperscriptXOffset = 22, + kYSuperscriptYOffset = 24, + kYStrikeoutSize = 26, + kYStrikeoutPosition = 28, + kSFamilyClass = 30, + kPanose = 32, + kPanoseLength = 10, // Length of panose bytes. + kUlUnicodeRange1 = 42, + kUlUnicodeRange2 = 46, + kUlUnicodeRange3 = 50, + kUlUnicodeRange4 = 54, + kAchVendId = 58, + kAchVendIdLength = 4, // Length of ach vend id bytes. + kFsSelection = 62, + kUsFirstCharIndex = 64, + kUsLastCharIndex = 66, + kSTypoAscender = 68, + kSTypoDescender = 70, + kSTypoLineGap = 72, + kUsWinAscent = 74, + kUsWinDescent = 76, + kUlCodePageRange1 = 78, + kUlCodePageRange2 = 82, + kSxHeight = 86, + kSCapHeight = 88, + kUsDefaultChar = 90, + kUsBreakChar = 92, + kUsMaxContext = 94 + }; + }; + + OS2Table(Header* header, ReadableFontData* data); +}; +typedef Ptr<OS2Table> OS2TablePtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_OS2_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/font_data_table.cc b/gfx/sfntly/cpp/src/sfntly/table/font_data_table.cc new file mode 100644 index 0000000000..0e27f7a771 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/font_data_table.cc @@ -0,0 +1,193 @@ +/* + * 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 "sfntly/table/font_data_table.h" + +#include "sfntly/data/font_output_stream.h" + +namespace sfntly { + +/****************************************************************************** + * FontDataTable class + ******************************************************************************/ + +FontDataTable::FontDataTable(ReadableFontData* data) { + data_ = data; +} + +FontDataTable::~FontDataTable() {} + +ReadableFontData* FontDataTable::ReadFontData() { + return data_; +} + +int32_t FontDataTable::DataLength() { + return data_->Length(); +} + +int32_t FontDataTable::Serialize(OutputStream* os) { + return data_->CopyTo(os); +} + +int32_t FontDataTable::Serialize(WritableFontData* data) { + return data_->CopyTo(data); +} + +/****************************************************************************** + * FontDataTable::Builder class + ******************************************************************************/ +CALLER_ATTACH WritableFontData* FontDataTable::Builder::Data() { + WritableFontDataPtr new_data; + if (model_changed_) { + if (!SubReadyToSerialize()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("Table not ready to build."); +#endif + return NULL; + } + int32_t size = SubDataSizeToSerialize(); + new_data.Attach(WritableFontData::CreateWritableFontData(size)); + SubSerialize(new_data); + } else { + ReadableFontDataPtr data = InternalReadData(); + new_data.Attach(WritableFontData::CreateWritableFontData( + data != NULL ? data->Length() : 0)); + if (data != NULL) { + data->CopyTo(new_data); + } + } + return new_data.Detach(); +} + +void FontDataTable::Builder::SetData(ReadableFontData* data) { + InternalSetData(data, true); +} + + +CALLER_ATTACH FontDataTable* FontDataTable::Builder::Build() { + FontDataTablePtr table; // NULL default table + ReadableFontDataPtr data = InternalReadData(); + if (model_changed_) { + // Let subclass serialize from model. + if (!SubReadyToSerialize()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("Table not ready to build."); +#endif + return NULL; + } + int32_t size = SubDataSizeToSerialize(); + WritableFontDataPtr new_data; + new_data.Attach(WritableFontData::CreateWritableFontData(size)); + SubSerialize(new_data); + data = new_data; + } + + if (data != NULL) { + table = SubBuildTable(data); + NotifyPostTableBuild(table); + } + + r_data_.Release(); + w_data_.Release(); + return table; +} + +bool FontDataTable::Builder::ReadyToBuild() { + return true; +} + +ReadableFontData* FontDataTable::Builder::InternalReadData() { + return (r_data_ != NULL) ? r_data_.p_ : + static_cast<ReadableFontData*>(w_data_.p_); +} + +WritableFontData* FontDataTable::Builder::InternalWriteData() { + if (w_data_ == NULL) { + WritableFontDataPtr new_data; + new_data.Attach(WritableFontData::CreateWritableFontData( + r_data_ == NULL ? 0 : r_data_->Length())); +#if !defined (SFNTLY_NO_EXCEPTION) + try { +#endif + if (r_data_) { + r_data_->CopyTo(new_data); + } +#if !defined (SFNTLY_NO_EXCEPTION) + } catch (IOException& e) { + // TODO(stuartg): fix when IOExceptions are cleaned up + } +#endif + InternalSetData(new_data, false); + } + return w_data_.p_; +} + +FontDataTable::Builder::Builder() + : model_changed_(false), + contained_model_changed_(false), + data_changed_(false) { +} + +FontDataTable::Builder::Builder(int32_t data_size) + : model_changed_(false), + contained_model_changed_(false), + data_changed_(false) { + w_data_.Attach(WritableFontData::CreateWritableFontData(data_size)); +} + +FontDataTable::Builder::Builder(WritableFontData* data) + : model_changed_(false), + contained_model_changed_(false), + data_changed_(false) { + w_data_ = data; +} + +FontDataTable::Builder::Builder(ReadableFontData* data) + : model_changed_(false), + contained_model_changed_(false), + data_changed_(false) { + r_data_ = data; +} + +FontDataTable::Builder::~Builder() { +} + +void FontDataTable::Builder::NotifyPostTableBuild(FontDataTable* table) { + // Default: NOP. + UNREFERENCED_PARAMETER(table); +} + +void FontDataTable::Builder::InternalSetData(WritableFontData* data, + bool data_changed) { + w_data_ = data; + r_data_ = NULL; + if (data_changed) { + data_changed_ = true; + SubDataSet(); + } +} + +void FontDataTable::Builder::InternalSetData(ReadableFontData* data, + bool data_changed) { + w_data_ = NULL; + r_data_ = data; + if (data_changed) { + data_changed_ = true; + SubDataSet(); + } +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/font_data_table.h b/gfx/sfntly/cpp/src/sfntly/table/font_data_table.h new file mode 100644 index 0000000000..5e437e2f34 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/font_data_table.h @@ -0,0 +1,123 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_FONT_DATA_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_FONT_DATA_TABLE_H_ + +#include "sfntly/data/readable_font_data.h" +#include "sfntly/data/writable_font_data.h" +#include "sfntly/port/refcount.h" + +namespace sfntly { + +// An abstract base for any table that contains a FontData. This is the root of +// the table class hierarchy. +class FontDataTable : virtual public RefCount { + public: + // Note: original version is abstract Builder<T extends FontDataTable> + // C++ template is not designed that way so plain class is chosen. + class Builder : virtual public RefCount { + public: + // Get a snapshot copy of the internal data of the builder. + // This causes any internal data structures to be serialized to a new data + // object. This data object belongs to the caller and must be properly + // disposed of. No changes are made to the builder and any changes to the + // data directly do not affect the internal state. To do that a subsequent + // call must be made to {@link #SetData(WritableFontData)}. + // @return a copy of the internal data of the builder + CALLER_ATTACH WritableFontData* Data(); + virtual void SetData(ReadableFontData* data); + + // Note: changed from protected to avoid accessibility error in C++ + virtual CALLER_ATTACH FontDataTable* Build(); + virtual bool ReadyToBuild(); + + ReadableFontData* InternalReadData(); + WritableFontData* InternalWriteData(); + + bool data_changed() { return data_changed_; } + bool model_changed() { + return current_model_changed() || contained_model_changed(); + } + bool current_model_changed() { return model_changed_; } + bool contained_model_changed() { return contained_model_changed_; } + + bool set_model_changed() { return set_model_changed(true); } + bool set_model_changed(bool changed) { + bool old = model_changed_; + model_changed_ = changed; + return old; + } + + protected: + explicit Builder(); + + // Construct a FontDataTable.Builder with a WritableFontData backing store + // of size given. A positive size will create a fixed size backing store and + // a 0 or less size is an estimate for a growable backing store with the + // estimate being the absolute of the size. + // @param dataSize if positive then a fixed size; if 0 or less then an + // estimate for a growable size + Builder(int32_t data_size); + Builder(WritableFontData* data); + Builder(ReadableFontData* data); + virtual ~Builder(); + + // subclass API + virtual void NotifyPostTableBuild(FontDataTable* table); + virtual int32_t SubSerialize(WritableFontData* new_data) = 0; + virtual bool SubReadyToSerialize() = 0; + virtual int32_t SubDataSizeToSerialize() = 0; + virtual void SubDataSet() = 0; + virtual CALLER_ATTACH FontDataTable* + SubBuildTable(ReadableFontData* data) = 0; + + private: + void InternalSetData(WritableFontData* data, bool data_changed); + void InternalSetData(ReadableFontData* data, bool data_changed); + + WritableFontDataPtr w_data_; + ReadableFontDataPtr r_data_; + bool model_changed_; + bool contained_model_changed_; // may expand to list of submodel states + bool data_changed_; + }; + + explicit FontDataTable(ReadableFontData* data); + virtual ~FontDataTable(); + + // Get the readable font data for this table. + ReadableFontData* ReadFontData(); + + // Get the length of the data for this table in bytes. This is the full + // allocated length of the data underlying the table and may or may not + // include any padding. + virtual int32_t DataLength(); + + virtual int32_t Serialize(OutputStream* os); + + protected: + virtual int32_t Serialize(WritableFontData* data); + + // TODO(arthurhsu): style guide violation: protected member, need refactoring + ReadableFontDataPtr data_; +}; +typedef Ptr<FontDataTable> FontDataTablePtr; +typedef Ptr<FontDataTable::Builder> FontDataTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_FONT_DATA_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/generic_table_builder.cc b/gfx/sfntly/cpp/src/sfntly/table/generic_table_builder.cc new file mode 100644 index 0000000000..78e679772c --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/generic_table_builder.cc @@ -0,0 +1,49 @@ +/* + * 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 "sfntly/table/generic_table_builder.h" + +namespace sfntly { + +GenericTableBuilder::~GenericTableBuilder() {} + +CALLER_ATTACH +FontDataTable* GenericTableBuilder::SubBuildTable(ReadableFontData* data) { + // Note: In C++ port, we use GenericTable, the ref-counted version of Table + UNREFERENCED_PARAMETER(data); + Ptr<GenericTable> table = new GenericTable(header(), InternalReadData()); + return table.Detach(); +} + +// static +CALLER_ATTACH GenericTableBuilder* + GenericTableBuilder::CreateBuilder(Header* header, WritableFontData* data) { + Ptr<GenericTableBuilder> builder = + new GenericTableBuilder(header, data); + return builder.Detach(); +} + +GenericTableBuilder::GenericTableBuilder(Header* header, + WritableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +GenericTableBuilder::GenericTableBuilder(Header* header, + ReadableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/generic_table_builder.h b/gfx/sfntly/cpp/src/sfntly/table/generic_table_builder.h new file mode 100644 index 0000000000..a100ea072c --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/generic_table_builder.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_GENERIC_TABLE_BUILDER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_GENERIC_TABLE_BUILDER_H_ + +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +// A table builder to do the minimal table building for an unknown table type. +class GenericTableBuilder : public TableBasedTableBuilder, + public RefCounted<GenericTableBuilder> { + public: + virtual ~GenericTableBuilder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + static CALLER_ATTACH GenericTableBuilder* + CreateBuilder(Header* header, WritableFontData* data); + + private: + GenericTableBuilder(Header* header, WritableFontData* data); + GenericTableBuilder(Header* header, ReadableFontData* data); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/header.cc b/gfx/sfntly/cpp/src/sfntly/table/header.cc new file mode 100644 index 0000000000..eb8fd756bd --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/header.cc @@ -0,0 +1,66 @@ +/* + * 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 "sfntly/table/header.h" + +namespace sfntly { + +/****************************************************************************** + * Header class + ******************************************************************************/ +Header::Header(int32_t tag) + : tag_(tag), + offset_(0), + offset_valid_(false), + length_(0), + length_valid_(false), + checksum_(0), + checksum_valid_(false) { +} + +Header::Header(int32_t tag, int32_t length) + : tag_(tag), + offset_(0), + offset_valid_(false), + length_(length), + length_valid_(true), + checksum_(0), + checksum_valid_(false) { +} + +Header::Header(int32_t tag, int64_t checksum, int32_t offset, int32_t length) + : tag_(tag), + offset_(offset), + offset_valid_(true), + length_(length), + length_valid_(true), + checksum_(checksum), + checksum_valid_(true) { +} + +Header::~Header() {} + +bool HeaderComparatorByOffset::operator() (const HeaderPtr lhs, + const HeaderPtr rhs) const { + return lhs->offset_ > rhs->offset_; +} + +bool HeaderComparatorByTag::operator() (const HeaderPtr lhs, + const HeaderPtr rhs) const { + return lhs->tag_ > rhs->tag_; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/header.h b/gfx/sfntly/cpp/src/sfntly/table/header.h new file mode 100644 index 0000000000..1a4cba1f9d --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/header.h @@ -0,0 +1,114 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_HEADER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_HEADER_H_ + +#include "sfntly/port/refcount.h" + +namespace sfntly { + +class Header : public RefCounted<Header> { + public: + // Make a partial header with only the basic info for an empty new table. + explicit Header(int32_t tag); + + // Make a partial header with only the basic info for a new table. + Header(int32_t tag, int32_t length); + + // Make a full header as read from an existing font. + Header(int32_t tag, int64_t checksum, int32_t offset, int32_t length); + virtual ~Header(); + + // Get the table tag. + int32_t tag() const { return tag_; } + + // Get the table offset. The offset is from the start of the font file. This + // offset value is what was read from the font file during construction of the + // font. It may not be meaningful if the font was maninpulated through the + // builders. + int32_t offset() const { return offset_; } + + // Is the offset in the header valid. The offset will not be valid if the + // table was constructed during building and has no physical location in a + // font file. + bool offset_valid() const { return offset_valid_; } + + // Get the length of the table as recorded in the table record header. During + // building the header length will reflect the length that was initially read + // from the font file. This may not be consistent with the current state of + // the data. + int32_t length() const { return length_; } + + // Is the length in the header valid. The length will not be valid if the + // table was constructed during building and has no physical location in a + // font file until the table is built from the builder. + bool length_valid() const { return length_valid_; } + + // Get the checksum for the table as recorded in the table record header. + int64_t checksum() const { return checksum_; } + + // Is the checksum valid. The checksum will not be valid if the table was + // constructed during building and has no physical location in a font file. + // Note that this does *NOT* check the validity of the checksum against + // the calculated checksum for the table data. + bool checksum_valid() const { return checksum_valid_; } + + // UNIMPLEMENTED: boolean equals(Object obj) + // int hashCode() + // string toString() + + private: + const int32_t tag_; + const int32_t offset_; + const bool offset_valid_; + const int32_t length_; + const bool length_valid_; + const int64_t checksum_; + const bool checksum_valid_; + + friend class HeaderComparatorByOffset; + friend class HeaderComparatorByTag; +}; +typedef Ptr<Header> HeaderPtr; + +class HeaderComparator { + public: + virtual ~HeaderComparator() {} + virtual bool operator()(const HeaderPtr h1, + const HeaderPtr h2) const = 0; +}; + +class HeaderComparatorByOffset : public HeaderComparator { + public: + virtual ~HeaderComparatorByOffset() {} + virtual bool operator()(const HeaderPtr h1, + const HeaderPtr h2) const; +}; + +class HeaderComparatorByTag : public HeaderComparator { + public: + virtual ~HeaderComparatorByTag() {} + virtual bool operator()(const HeaderPtr h1, + const HeaderPtr h2) const; +}; + +typedef std::set<HeaderPtr, HeaderComparatorByOffset> HeaderOffsetSortedSet; +typedef std::set<HeaderPtr, HeaderComparatorByTag> HeaderTagSortedSet; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_HEADER_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/subtable.cc b/gfx/sfntly/cpp/src/sfntly/table/subtable.cc new file mode 100644 index 0000000000..e5b906fd37 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/subtable.cc @@ -0,0 +1,64 @@ +/* + * 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 "sfntly/table/subtable.h" + +namespace sfntly { +/****************************************************************************** + * SubTable class + ******************************************************************************/ +SubTable::~SubTable() {} + +SubTable::SubTable(ReadableFontData* data, ReadableFontData* master_data) + : FontDataTable(data), padding_(0) { + master_data_ = master_data; +} + +SubTable::SubTable(ReadableFontData* data) + : FontDataTable(data), padding_(0) { +} + +/****************************************************************************** + * SubTable::Builder class + ******************************************************************************/ +SubTable::Builder::~Builder() { +} + +SubTable::Builder::Builder(int32_t data_size) + : FontDataTable::Builder(data_size) { +} + +SubTable::Builder::Builder(WritableFontData* data, + ReadableFontData* master_data) + : FontDataTable::Builder(data) { + master_data_ = master_data; +} + +SubTable::Builder::Builder(ReadableFontData* data, + ReadableFontData* master_data) + : FontDataTable::Builder(data) { + master_data_ = master_data; +} + +SubTable::Builder::Builder(WritableFontData* data) + : FontDataTable::Builder(data) { +} + +SubTable::Builder::Builder(ReadableFontData* data) + : FontDataTable::Builder(data) { +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/subtable.h b/gfx/sfntly/cpp/src/sfntly/table/subtable.h new file mode 100644 index 0000000000..fa6f4c6bcd --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/subtable.h @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_SUBTABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_SUBTABLE_H_ + +#include "sfntly/table/font_data_table.h" + +namespace sfntly { + +// An abstract base class for subtables. Subtables are smaller tables nested +// within other tables and don't have an entry in the main font index. Examples +// of these are the CMap subtables within CMap table (cmap) or a glyph within +// the glyph table (glyf). +class SubTable : public FontDataTable { + public: + class Builder : public FontDataTable::Builder { + public: + virtual ~Builder(); + + protected: + // @param data the data for the subtable being built + // @param master_data the data for the full table + Builder(int32_t data_size); + Builder(WritableFontData* data, ReadableFontData* master_data); + Builder(ReadableFontData* data, ReadableFontData* master_data); + explicit Builder(WritableFontData* data); + explicit Builder(ReadableFontData* data); + + ReadableFontData* master_read_data() { return master_data_; } + + private: + ReadableFontDataPtr master_data_; + }; + + virtual ~SubTable(); + virtual int32_t Padding() { return padding_; } + + // Sets the amount of padding that is part of the data being used by this + // subtable. + void set_padding(int32_t padding) { padding_ = padding; } + + protected: + SubTable(ReadableFontData* data, ReadableFontData* master_data); + + // Note: constructor refactored in C++ to avoid heavy lifting. + // caller need to do data->Slice(offset, length) beforehand. + explicit SubTable(ReadableFontData* data); + + ReadableFontData* master_read_data() { return master_data_; } + + private: + // The data for the whole table in which this subtable is contained. + ReadableFontDataPtr master_data_; + int32_t padding_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_SUBTABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/subtable_container_table.h b/gfx/sfntly/cpp/src/sfntly/table/subtable_container_table.h new file mode 100644 index 0000000000..0f099debb4 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/subtable_container_table.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SFNTLY_TABLE_SUBTABLE_CONTAINER_TABLE_H_ +#define TYPOGRAPHY_FONT_SFNTLY_SRC_SFNTLY_TABLE_SUBTABLE_CONTAINER_TABLE_H_ + +#include "sfntly/table/table.h" + +namespace sfntly { + +class SubTableContainerTable : public Table { + public: + class Builder : public Table::Builder { + public: + Builder(Header* header, WritableFontData* data) + : Table::Builder(header, data) { + } + + Builder(Header* header, ReadableFontData* data) + : Table::Builder(header, data) { + } + + virtual ~Builder() {} + }; + + SubTableContainerTable(Header* header, ReadableFontData* data) + : Table(header, data) { + } + + virtual ~SubTableContainerTable() {} +}; + +} // namespace sfntly + +#endif // TYPOGRAPHY_FONT_SFNTLY_SRC_SFNTLY_TABLE_SUBTABLE_CONTAINER_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/table.cc b/gfx/sfntly/cpp/src/sfntly/table/table.cc new file mode 100644 index 0000000000..cf574b838b --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/table.cc @@ -0,0 +1,162 @@ +/* + * 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. + */ + +// type.h needs to be included first because of building issues on Windows +// Type aliases we delcare are defined in other headers and make the build +// fail otherwise. +#include "sfntly/port/type.h" +#include "sfntly/table/table.h" + +#include "sfntly/font.h" +#include "sfntly/tag.h" +#include "sfntly/table/bitmap/ebdt_table.h" +#include "sfntly/table/bitmap/eblc_table.h" +#include "sfntly/table/bitmap/ebsc_table.h" +#include "sfntly/table/core/cmap_table.h" +#include "sfntly/table/core/font_header_table.h" +#include "sfntly/table/core/horizontal_device_metrics_table.h" +#include "sfntly/table/core/horizontal_header_table.h" +#include "sfntly/table/core/horizontal_metrics_table.h" +#include "sfntly/table/core/maximum_profile_table.h" +#include "sfntly/table/core/name_table.h" +#include "sfntly/table/core/os2_table.h" +#include "sfntly/table/generic_table_builder.h" +#include "sfntly/table/table_based_table_builder.h" +#include "sfntly/table/truetype/glyph_table.h" +#include "sfntly/table/truetype/loca_table.h" + +namespace sfntly { + +/****************************************************************************** + * Table class + ******************************************************************************/ +Table::~Table() {} + +int64_t Table::CalculatedChecksum() { + return data_->Checksum(); +} + +void Table::SetFont(Font* font) { + font_ = font; +} + +Table::Table(Header* header, ReadableFontData* data) + : FontDataTable(data) { + header_ = header; +} + +/****************************************************************************** + * Table::Builder class + ******************************************************************************/ +Table::Builder::~Builder() { + header_.Release(); +} + +void Table::Builder::NotifyPostTableBuild(FontDataTable* table) { + if (model_changed() || data_changed()) { + Table* derived_table = down_cast<Table*>(table); + derived_table->header_ = new Header(header()->tag(), + derived_table->DataLength()); + } +} + +CALLER_ATTACH +Table::Builder* Table::Builder::GetBuilder(Header* header, + WritableFontData* table_data) { + int32_t tag = header->tag(); + Table::Builder* builder_raw = NULL; + + // Note: Tables are commented out when they are not used/ported. + // TODO(arthurhsu): IMPLEMENT: finish tables that are not ported. + if (tag == Tag::head) { + builder_raw = static_cast<Table::Builder*>( + FontHeaderTable::Builder::CreateBuilder(header, table_data)); +#if defined (SFNTLY_EXPERIMENTAL) + } else if (tag == Tag::cmap) { + builder_raw = static_cast<Table::Builder*>( + CMapTable::Builder::CreateBuilder(header, table_data)); +#endif // SFNTLY_EXPERIMENTAL + } else if (tag == Tag::hhea) { + builder_raw = static_cast<Table::Builder*>( + HorizontalHeaderTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::hmtx) { + builder_raw = static_cast<Table::Builder*>( + HorizontalMetricsTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::maxp) { + builder_raw = static_cast<Table::Builder*>( + MaximumProfileTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::name) { + builder_raw = static_cast<Table::Builder*>( + NameTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::OS_2) { + builder_raw = static_cast<Table::Builder*>( + OS2Table::Builder::CreateBuilder(header, table_data)); + }/* else if (tag == Tag::PostScript) { + builder_raw = static_cast<Table::Builder*>( + PostScriptTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::cvt) { + builder_raw = static_cast<Table::Builder*>( + ControlValueTable::Builder::CreateBuilder(header, table_data)); + }*/ else if (tag == Tag::glyf) { + builder_raw = static_cast<Table::Builder*>( + GlyphTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::loca) { + builder_raw = static_cast<Table::Builder*>( + LocaTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::EBDT || tag == Tag::bdat) { + builder_raw = static_cast<Table::Builder*>( + EbdtTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::EBLC || tag == Tag::bloc) { + builder_raw = static_cast<Table::Builder*>( + EblcTable::Builder::CreateBuilder(header, table_data)); + } else if (tag == Tag::EBSC) { + builder_raw = static_cast<Table::Builder*>( + EbscTable::Builder::CreateBuilder(header, table_data)); + } /* else if (tag == Tag::prep) { + builder_raw = static_cast<Table::Builder*>( + ControlProgramTable::Builder::CreateBuilder(header, table_data)); + }*/ else if (tag == Tag::bhed) { + builder_raw = static_cast<Table::Builder*>( + FontHeaderTable::Builder::CreateBuilder(header, table_data)); +#if defined (SFNTLY_EXPERIMENTAL) + } else if (tag == Tag::hdmx) { + builder_raw = static_cast<Table::Builder*>( + HorizontalDeviceMetricsTable::Builder::CreateBuilder(header, + table_data)); +#endif // SFNTLY_EXPERIMENTAL + } else { + builder_raw = static_cast<Table::Builder*>( + GenericTableBuilder::CreateBuilder(header, table_data)); + } + + return builder_raw; +} + +Table::Builder::Builder(Header* header, WritableFontData* data) + : FontDataTable::Builder(data) { + header_ = header; +} + +Table::Builder::Builder(Header* header, ReadableFontData* data) + : FontDataTable::Builder(data) { + header_ = header; +} + +Table::Builder::Builder(Header* header) { + header_ = header; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/table.h b/gfx/sfntly/cpp/src/sfntly/table/table.h new file mode 100644 index 0000000000..6ebc22df8a --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/table.h @@ -0,0 +1,119 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_H_ + +#include <set> +#include <map> +#include <vector> +#include <utility> + +#include "sfntly/port/type.h" +#include "sfntly/table/font_data_table.h" +#include "sfntly/table/header.h" + +namespace sfntly { +class Font; + +// A concrete implementation of a root level table in the font. This is the base +// class used for all specific table implementations and is used as the generic +// table for all tables which have no specific implementations. +class Table : public FontDataTable { + public: + // Note: original version is Builder<T extends Table> + // C++ template is not designed that way so plain old inheritance is + // chosen. + class Builder : public FontDataTable::Builder { + public: + virtual ~Builder(); + virtual Header* header() { return header_; } + virtual void NotifyPostTableBuild(FontDataTable* table); + + // Get a builder for the table type specified by the data in the header. + // @param header the header for the table + // @param tableData the data to be used to build the table from + // @return builder for the table specified + static CALLER_ATTACH Builder* GetBuilder(Header* header, + WritableFontData* table_data); + + // UNIMPLEMENTED: toString() + + protected: + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + Builder(Header* header); + + private: + Ptr<Header> header_; + }; + + // Note: GenericTableBuilder moved to table_based_table_builder.h to avoid + // circular inclusion. + + virtual ~Table(); + + // Get the calculated checksum for the data in the table. + virtual int64_t CalculatedChecksum(); + + // Get the header for the table. + virtual Header* header() { return header_; } + + // Get the tag for the table from the record header. + virtual int32_t header_tag() { return header_->tag(); } + + // Get the offset for the table from the record header. + virtual int32_t header_offset() { return header_->offset(); } + + // Get the length of the table from the record header. + virtual int32_t header_length() { return header_->length(); } + + // Get the checksum for the table from the record header. + virtual int64_t header_checksum() { return header_->checksum(); } + + // UNIMPLEMENTED: toString() + + virtual void SetFont(Font* font); + + protected: + Table(Header* header, ReadableFontData* data); + + private: + Ptr<Header> header_; + Ptr<Font> font_; +}; + +// C++ port only +class GenericTable : public Table, public RefCounted<GenericTable> { + public: + GenericTable(Header* header, ReadableFontData* data) : Table(header, data) {} + virtual ~GenericTable() {} +}; + +typedef Ptr<Table> TablePtr; +typedef std::vector<HeaderPtr> TableHeaderList; +typedef Ptr<Table::Builder> TableBuilderPtr; +typedef std::map<int32_t, TablePtr> TableMap; +typedef std::pair<int32_t, TablePtr> TableMapEntry; + +typedef std::map<HeaderPtr, WritableFontDataPtr> DataBlockMap; +typedef std::pair<HeaderPtr, WritableFontDataPtr> DataBlockEntry; +typedef std::map<int32_t, TableBuilderPtr> TableBuilderMap; +typedef std::pair<int32_t, TableBuilderPtr> TableBuilderEntry; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/table_based_table_builder.cc b/gfx/sfntly/cpp/src/sfntly/table/table_based_table_builder.cc new file mode 100644 index 0000000000..51a5a3baa0 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/table_based_table_builder.cc @@ -0,0 +1,71 @@ +/* + * 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 "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +/****************************************************************************** + * TableBasedTableBuilder class + ******************************************************************************/ +TableBasedTableBuilder::~TableBasedTableBuilder() {} + +int32_t TableBasedTableBuilder::SubSerialize(WritableFontData* data) { + UNREFERENCED_PARAMETER(data); + return 0; +} + +bool TableBasedTableBuilder::SubReadyToSerialize() { + return false; +} + +int32_t TableBasedTableBuilder::SubDataSizeToSerialize() { + return 0; +} + +void TableBasedTableBuilder::SubDataSet() { + table_ = NULL; +} + +CALLER_ATTACH FontDataTable* TableBasedTableBuilder::Build() { + FontDataTablePtr table = static_cast<FontDataTable*>(GetTable()); + return table.Detach(); +} + +TableBasedTableBuilder::TableBasedTableBuilder(Header* header, + WritableFontData* data) + : Table::Builder(header, data) { +} + +TableBasedTableBuilder::TableBasedTableBuilder(Header* header, + ReadableFontData* data) + : Table::Builder(header, data) { +} + +TableBasedTableBuilder::TableBasedTableBuilder(Header* header) + : Table::Builder(header) { +} + +Table* TableBasedTableBuilder::GetTable() { + if (!table_) { + ReadableFontData* data = InternalReadData(); + if (data) + table_.Attach(down_cast<Table*>(SubBuildTable(data))); + } + return table_; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/table_based_table_builder.h b/gfx/sfntly/cpp/src/sfntly/table/table_based_table_builder.h new file mode 100644 index 0000000000..d88eefd11e --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/table_based_table_builder.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_BASED_TABLE_BUILDER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_BASED_TABLE_BUILDER_H_ + +#include "sfntly/table/table.h" + +namespace sfntly { + +class TableBasedTableBuilder : public Table::Builder { + public: + virtual ~TableBasedTableBuilder(); + + virtual int32_t SubSerialize(WritableFontData* new_data); + virtual bool SubReadyToSerialize(); + virtual int32_t SubDataSizeToSerialize(); + virtual void SubDataSet(); + virtual CALLER_ATTACH FontDataTable* Build(); + + protected: + TableBasedTableBuilder(Header* header, WritableFontData* data); + TableBasedTableBuilder(Header* header, ReadableFontData* data); + explicit TableBasedTableBuilder(Header* header); + + // C++ port: renamed table() to GetTable() + virtual Table* GetTable(); + + // TODO(arthurhsu): style guide violation: protected member, need refactor + TablePtr table_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_BASED_TABLE_BUILDER_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/truetype/glyph_table.cc b/gfx/sfntly/cpp/src/sfntly/table/truetype/glyph_table.cc new file mode 100644 index 0000000000..32b76b6fd7 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/truetype/glyph_table.cc @@ -0,0 +1,615 @@ +/* + * 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 "sfntly/table/truetype/glyph_table.h" + +#include <stdlib.h> + +#include "sfntly/port/exception_type.h" + +namespace sfntly { +/****************************************************************************** + * Constants + ******************************************************************************/ +const int32_t GlyphTable::SimpleGlyph::kFLAG_ONCURVE = 1; +const int32_t GlyphTable::SimpleGlyph::kFLAG_XSHORT = 1 << 1; +const int32_t GlyphTable::SimpleGlyph::kFLAG_YSHORT = 1 << 2; +const int32_t GlyphTable::SimpleGlyph::kFLAG_REPEAT = 1 << 3; +const int32_t GlyphTable::SimpleGlyph::kFLAG_XREPEATSIGN = 1 << 4; +const int32_t GlyphTable::SimpleGlyph::kFLAG_YREPEATSIGN = 1 << 5; + +const int32_t GlyphTable::CompositeGlyph::kFLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0; +const int32_t GlyphTable::CompositeGlyph::kFLAG_ARGS_ARE_XY_VALUES = 1 << 1; +const int32_t GlyphTable::CompositeGlyph::kFLAG_ROUND_XY_TO_GRID = 1 << 2; +const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_A_SCALE = 1 << 3; +const int32_t GlyphTable::CompositeGlyph::kFLAG_RESERVED = 1 << 4; +const int32_t GlyphTable::CompositeGlyph::kFLAG_MORE_COMPONENTS = 1 << 5; +const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6; +const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7; +const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_INSTRUCTIONS = 1 << 8; +const int32_t GlyphTable::CompositeGlyph::kFLAG_USE_MY_METRICS = 1 << 9; +const int32_t GlyphTable::CompositeGlyph::kFLAG_OVERLAP_COMPOUND = 1 << 10; +const int32_t GlyphTable::CompositeGlyph::kFLAG_SCALED_COMPONENT_OFFSET = 1 << 11; +const int32_t GlyphTable::CompositeGlyph::kFLAG_UNSCALED_COMPONENT_OFFSET = 1 << 12; + +/****************************************************************************** + * GlyphTable class + ******************************************************************************/ +GlyphTable::~GlyphTable() { +} + +GlyphTable::Glyph* GlyphTable::GetGlyph(int32_t offset, int32_t length) { + return GlyphTable::Glyph::GetGlyph(this, this->data_, offset, length); +} + +GlyphTable::GlyphTable(Header* header, ReadableFontData* data) + : SubTableContainerTable(header, data) { +} + +/****************************************************************************** + * GlyphTable::Builder class + ******************************************************************************/ +GlyphTable::Builder::Builder(Header* header, ReadableFontData* data) + : SubTableContainerTable::Builder(header, data) { +} + +GlyphTable::Builder::~Builder() { +} + +void GlyphTable::Builder::SetLoca(const std::vector<int32_t>& loca) { + loca_ = loca; + set_model_changed(false); + glyph_builders_.clear(); +} + +void GlyphTable::Builder::GenerateLocaList(std::vector<int32_t>* locas) { + assert(locas); + GlyphBuilderList* glyph_builders = GetGlyphBuilders(); + locas->push_back(0); + if (glyph_builders->size() == 0) { + locas->push_back(0); + } else { + int32_t total = 0; + for (GlyphBuilderList::iterator b = glyph_builders->begin(), + b_end = glyph_builders->end(); + b != b_end; ++b) { + int32_t size = (*b)->SubDataSizeToSerialize(); + locas->push_back(total + size); + total += size; + } + } +} + +CALLER_ATTACH GlyphTable::Builder* + GlyphTable::Builder::CreateBuilder(Header* header, WritableFontData* data) { + Ptr<GlyphTable::Builder> builder; + builder = new GlyphTable::Builder(header, data); + return builder.Detach(); +} + +GlyphTable::GlyphBuilderList* GlyphTable::Builder::GlyphBuilders() { + return GetGlyphBuilders(); +} + +void GlyphTable::Builder::SetGlyphBuilders(GlyphBuilderList* glyph_builders) { + glyph_builders_ = *glyph_builders; + set_model_changed(); +} + +CALLER_ATTACH GlyphTable::Glyph::Builder* + GlyphTable::Builder::GlyphBuilder(ReadableFontData* data) { + return Glyph::Builder::GetBuilder(this, data); +} + +CALLER_ATTACH FontDataTable* + GlyphTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = new GlyphTable(header(), data); + return table.Detach(); +} + +void GlyphTable::Builder::SubDataSet() { + glyph_builders_.clear(); + set_model_changed(false); +} + +int32_t GlyphTable::Builder::SubDataSizeToSerialize() { + if (glyph_builders_.empty()) + return 0; + + bool variable = false; + int32_t size = 0; + + // Calculate size of each table. + for (GlyphBuilderList::iterator b = glyph_builders_.begin(), + end = glyph_builders_.end(); b != end; ++b) { + int32_t glyph_size = (*b)->SubDataSizeToSerialize(); + size += abs(glyph_size); + variable |= glyph_size <= 0; + } + return variable ? -size : size; +} + +bool GlyphTable::Builder::SubReadyToSerialize() { + return !glyph_builders_.empty(); +} + +int32_t GlyphTable::Builder::SubSerialize(WritableFontData* new_data) { + int32_t size = 0; + for (GlyphBuilderList::iterator b = glyph_builders_.begin(), + end = glyph_builders_.end(); b != end; ++b) { + FontDataPtr data; + data.Attach(new_data->Slice(size)); + size += (*b)->SubSerialize(down_cast<WritableFontData*>(data.p_)); + } + return size; +} + +void GlyphTable::Builder::Initialize(ReadableFontData* data, + const std::vector<int32_t>& loca) { + if (data != NULL) { + if (loca_.empty()) { + return; + } + int32_t loca_value; + int32_t last_loca_value = loca[0]; + for (size_t i = 1; i < loca.size(); ++i) { + loca_value = loca[i]; + GlyphBuilderPtr builder; + builder.Attach( + Glyph::Builder::GetBuilder(this, + data, + last_loca_value /*offset*/, + loca_value - last_loca_value /*length*/)); + glyph_builders_.push_back(builder); + last_loca_value = loca_value; + } + } +} + +GlyphTable::GlyphBuilderList* GlyphTable::Builder::GetGlyphBuilders() { + if (glyph_builders_.empty()) { + if (InternalReadData() && loca_.empty()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalStateException( + "Loca values not set - unable to parse glyph data."); +#endif + return NULL; + } + Initialize(InternalReadData(), loca_); + set_model_changed(); + } + return &glyph_builders_; +} + +void GlyphTable::Builder::Revert() { + glyph_builders_.clear(); + set_model_changed(false); +} + +/****************************************************************************** + * GlyphTable::Glyph class + ******************************************************************************/ +GlyphTable::Glyph::~Glyph() {} + +CALLER_ATTACH GlyphTable::Glyph* + GlyphTable::Glyph::GetGlyph(GlyphTable* table, + ReadableFontData* data, + int32_t offset, + int32_t length) { + UNREFERENCED_PARAMETER(table); + int32_t type = GlyphType(data, offset, length); + GlyphPtr glyph; + + ReadableFontDataPtr sliced_data; + sliced_data.Attach(down_cast<ReadableFontData*>(data->Slice(offset, length))); + if (sliced_data) { + if (type == GlyphType::kSimple) + glyph = new SimpleGlyph(sliced_data); + else + glyph = new CompositeGlyph(sliced_data); + } + return glyph.Detach(); +} + +int32_t GlyphTable::Glyph::Padding() { + Initialize(); + return SubTable::Padding(); +} + +int32_t GlyphTable::Glyph::GlyphType() { + return glyph_type_; +} + +int32_t GlyphTable::Glyph::NumberOfContours() { + return number_of_contours_; +} + +int32_t GlyphTable::Glyph::XMin() { + return data_->ReadShort(Offset::kXMin); +} + +int32_t GlyphTable::Glyph::XMax() { + return data_->ReadShort(Offset::kXMax); +} + +int32_t GlyphTable::Glyph::YMin() { + return data_->ReadShort(Offset::kYMin); +} + +int32_t GlyphTable::Glyph::YMax() { + return data_->ReadShort(Offset::kYMax); +} + +GlyphTable::Glyph::Glyph(ReadableFontData* data, int32_t glyph_type) + : SubTable(data), + glyph_type_(glyph_type) { + if (data_->Length() == 0) { + number_of_contours_ = 0; + } else { + // -1 if composite + number_of_contours_ = data_->ReadShort(Offset::kNumberOfContours); + } +} + +int32_t GlyphTable::Glyph::GlyphType(ReadableFontData* data, + int32_t offset, + int32_t length) { + if (length == 0) { + return GlyphType::kSimple; + } + int32_t number_of_contours = data->ReadShort(offset); + if (number_of_contours >= 0) { + return GlyphType::kSimple; + } + return GlyphType::kComposite; +} + +/****************************************************************************** + * GlyphTable::Glyph::Builder class + ******************************************************************************/ +GlyphTable::Glyph::Builder::~Builder() { +} + +GlyphTable::Glyph::Builder::Builder(WritableFontData* data) + : SubTable::Builder(data) { +} + +GlyphTable::Glyph::Builder::Builder(ReadableFontData* data) + : SubTable::Builder(data) { +} + +CALLER_ATTACH GlyphTable::Glyph::Builder* + GlyphTable::Glyph::Builder::GetBuilder( + GlyphTable::Builder* table_builder, + ReadableFontData* data) { + return GetBuilder(table_builder, data, 0, data->Length()); +} + +CALLER_ATTACH GlyphTable::Glyph::Builder* + GlyphTable::Glyph::Builder::GetBuilder( + GlyphTable::Builder* table_builder, + ReadableFontData* data, + int32_t offset, + int32_t length) { + UNREFERENCED_PARAMETER(table_builder); + int32_t type = Glyph::GlyphType(data, offset, length); + GlyphBuilderPtr builder; + ReadableFontDataPtr sliced_data; + sliced_data.Attach(down_cast<ReadableFontData*>(data->Slice(offset, length))); + if (type == GlyphType::kSimple) { + builder = new SimpleGlyph::SimpleGlyphBuilder(sliced_data); + } else { + builder = new CompositeGlyph::CompositeGlyphBuilder(sliced_data); + } + return builder.Detach(); +} + +void GlyphTable::Glyph::Builder::SubDataSet() { + // NOP +} + +int32_t GlyphTable::Glyph::Builder::SubDataSizeToSerialize() { + return InternalReadData()->Length(); +} + +bool GlyphTable::Glyph::Builder::SubReadyToSerialize() { + return true; +} + +int32_t GlyphTable::Glyph::Builder::SubSerialize(WritableFontData* new_data) { + return InternalReadData()->CopyTo(new_data); +} + +/****************************************************************************** + * GlyphTable::SimpleGlyph + ******************************************************************************/ +GlyphTable::SimpleGlyph::SimpleGlyph(ReadableFontData* data) + : GlyphTable::Glyph(data, GlyphType::kSimple), initialized_(false) { +} + +GlyphTable::SimpleGlyph::~SimpleGlyph() { +} + +int32_t GlyphTable::SimpleGlyph::InstructionSize() { + Initialize(); + return instruction_size_; +} + +CALLER_ATTACH ReadableFontData* GlyphTable::SimpleGlyph::Instructions() { + Initialize(); + return down_cast<ReadableFontData*>( + data_->Slice(instructions_offset_, InstructionSize())); +} + +void GlyphTable::SimpleGlyph::Initialize() { + AutoLock lock(initialization_lock_); + if (initialized_) { + return; + } + + if (ReadFontData()->Length() == 0) { + instruction_size_ = 0; + number_of_points_ = 0; + instructions_offset_ = 0; + flags_offset_ = 0; + x_coordinates_offset_ = 0; + y_coordinates_offset_ = 0; + return; + } + + instruction_size_ = data_->ReadUShort(Offset::kSimpleEndPtsOfCountours + + NumberOfContours() * DataSize::kUSHORT); + instructions_offset_ = Offset::kSimpleEndPtsOfCountours + + (NumberOfContours() + 1) * DataSize::kUSHORT; + flags_offset_ = instructions_offset_ + instruction_size_ * DataSize::kBYTE; + number_of_points_ = ContourEndPoint(NumberOfContours() - 1) + 1; + x_coordinates_.resize(number_of_points_); + y_coordinates_.resize(number_of_points_); + on_curve_.resize(number_of_points_); + ParseData(false); + x_coordinates_offset_ = flags_offset_ + flag_byte_count_ * DataSize::kBYTE; + y_coordinates_offset_ = x_coordinates_offset_ + x_byte_count_ * + DataSize::kBYTE; + contour_index_.resize(NumberOfContours() + 1); + contour_index_[0] = 0; + for (uint32_t contour = 0; contour < contour_index_.size() - 1; ++contour) { + contour_index_[contour + 1] = ContourEndPoint(contour) + 1; + } + ParseData(true); + int32_t non_padded_data_length = + 5 * DataSize::kSHORT + + (NumberOfContours() * DataSize::kUSHORT) + + DataSize::kUSHORT + + (instruction_size_ * DataSize::kBYTE) + + (flag_byte_count_ * DataSize::kBYTE) + + (x_byte_count_ * DataSize::kBYTE) + + (y_byte_count_ * DataSize::kBYTE); + set_padding(DataLength() - non_padded_data_length); + initialized_ = true; +} + +void GlyphTable::SimpleGlyph::ParseData(bool fill_arrays) { + int32_t flag = 0; + int32_t flag_repeat = 0; + int32_t flag_index = 0; + int32_t x_byte_index = 0; + int32_t y_byte_index = 0; + + for (int32_t point_index = 0; point_index < number_of_points_; + ++point_index) { + // get the flag for the current point + if (flag_repeat == 0) { + flag = FlagAsInt(flag_index++); + if ((flag & kFLAG_REPEAT) == kFLAG_REPEAT) { + flag_repeat = FlagAsInt(flag_index++); + } + } else { + flag_repeat--; + } + + // on the curve? + if (fill_arrays) { + on_curve_[point_index] = ((flag & kFLAG_ONCURVE) == kFLAG_ONCURVE); + } + // get the x coordinate + if ((flag & kFLAG_XSHORT) == kFLAG_XSHORT) { + // single byte x coord value + if (fill_arrays) { + x_coordinates_[point_index] = + data_->ReadUByte(x_coordinates_offset_ + x_byte_index); + x_coordinates_[point_index] *= + ((flag & kFLAG_XREPEATSIGN) == kFLAG_XREPEATSIGN) ? 1 : -1; + } + x_byte_index++; + } else { + // double byte coord value + if (!((flag & kFLAG_XREPEATSIGN) == kFLAG_XREPEATSIGN)) { + if (fill_arrays) { + x_coordinates_[point_index] = + data_->ReadShort(x_coordinates_offset_ + x_byte_index); + } + x_byte_index += 2; + } + } + if (fill_arrays && point_index > 0) { + x_coordinates_[point_index] += x_coordinates_[point_index - 1]; + } + + // get the y coordinate + if ((flag & kFLAG_YSHORT) == kFLAG_YSHORT) { + if (fill_arrays) { + y_coordinates_[point_index] = + data_->ReadUByte(y_coordinates_offset_ + y_byte_index); + y_coordinates_[point_index] *= + ((flag & kFLAG_YREPEATSIGN) == kFLAG_YREPEATSIGN) ? 1 : -1; + } + y_byte_index++; + } else { + if (!((flag & kFLAG_YREPEATSIGN) == kFLAG_YREPEATSIGN)) { + if (fill_arrays) { + y_coordinates_[point_index] = + data_->ReadShort(y_coordinates_offset_ + y_byte_index); + } + y_byte_index += 2; + } + } + if (fill_arrays && point_index > 0) { + y_coordinates_[point_index] += y_coordinates_[point_index - 1]; + } + } + flag_byte_count_ = flag_index; + x_byte_count_ = x_byte_index; + y_byte_count_ = y_byte_index; +} + +int32_t GlyphTable::SimpleGlyph::FlagAsInt(int32_t index) { + return data_->ReadUByte(flags_offset_ + index * DataSize::kBYTE); +} + +int32_t GlyphTable::SimpleGlyph::ContourEndPoint(int32_t contour) { + return data_->ReadUShort(contour * DataSize::kUSHORT + + Offset::kSimpleEndPtsOfCountours); +} + +/****************************************************************************** + * GlyphTable::SimpleGlyph::Builder + ******************************************************************************/ +GlyphTable::SimpleGlyph::SimpleGlyphBuilder::~SimpleGlyphBuilder() { +} + +GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SimpleGlyphBuilder( + WritableFontData* data) + : Glyph::Builder(data) { +} + +GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SimpleGlyphBuilder( + ReadableFontData* data) + : Glyph::Builder(data) { +} + +CALLER_ATTACH FontDataTable* + GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SubBuildTable( + ReadableFontData* data) { + FontDataTablePtr table = new SimpleGlyph(data); + return table.Detach(); +} + +/****************************************************************************** + * GlyphTable::CompositeGlyph + ******************************************************************************/ +GlyphTable::CompositeGlyph::CompositeGlyph(ReadableFontData* data) + : GlyphTable::Glyph(data, GlyphType::kComposite), + instruction_size_(0), + instructions_offset_(0), + initialized_(false) { + Initialize(); +} + +GlyphTable::CompositeGlyph::~CompositeGlyph() { +} + +int32_t GlyphTable::CompositeGlyph::Flags(int32_t contour) { + if (contour < 0 || static_cast<size_t>(contour) >= contour_index_.size()) + return ReadableFontData::kInvalidUnsigned; + return data_->ReadUShort(contour_index_[contour]); +} + +int32_t GlyphTable::CompositeGlyph::NumGlyphs() { + return contour_index_.size(); +} + +int32_t GlyphTable::CompositeGlyph::GlyphIndex(int32_t contour) { + if (contour < 0 || static_cast<size_t>(contour) >= contour_index_.size()) + return ReadableFontData::kInvalidUnsigned; + return data_->ReadUShort(DataSize::kUSHORT + contour_index_[contour]); +} + +int32_t GlyphTable::CompositeGlyph::InstructionSize() { + return instruction_size_; +} + +CALLER_ATTACH ReadableFontData* GlyphTable::CompositeGlyph::Instructions() { + return down_cast<ReadableFontData*>( + data_->Slice(instructions_offset_, InstructionSize())); +} + +void GlyphTable::CompositeGlyph::Initialize() { + AutoLock lock(initialization_lock_); + if (initialized_) { + return; + } + + int32_t index = 5 * DataSize::kUSHORT; + int32_t flags = kFLAG_MORE_COMPONENTS; + + while ((flags & kFLAG_MORE_COMPONENTS) == kFLAG_MORE_COMPONENTS) { + contour_index_.push_back(index); + flags = data_->ReadUShort(index); + if (flags == ReadableFontData::kInvalidUnsigned) + break; + + index += 2 * DataSize::kUSHORT; // flags and glyphIndex + if ((flags & kFLAG_ARG_1_AND_2_ARE_WORDS) == kFLAG_ARG_1_AND_2_ARE_WORDS) { + index += 2 * DataSize::kSHORT; + } else { + index += 2 * DataSize::kBYTE; + } + if ((flags & kFLAG_WE_HAVE_A_SCALE) == kFLAG_WE_HAVE_A_SCALE) { + index += DataSize::kF2DOT14; + } else if ((flags & kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) == + kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) { + index += 2 * DataSize::kF2DOT14; + } else if ((flags & kFLAG_WE_HAVE_A_TWO_BY_TWO) == + kFLAG_WE_HAVE_A_TWO_BY_TWO) { + index += 4 * DataSize::kF2DOT14; + } + int32_t non_padded_data_length = index; + if ((flags & kFLAG_WE_HAVE_INSTRUCTIONS) == kFLAG_WE_HAVE_INSTRUCTIONS) { + instruction_size_ = data_->ReadUShort(index); + index += DataSize::kUSHORT; + instructions_offset_ = index; + non_padded_data_length = index + (instruction_size_ * DataSize::kBYTE); + } + set_padding(DataLength() - non_padded_data_length); + } + + initialized_ = true; +} + +/****************************************************************************** + * GlyphTable::CompositeGlyph::Builder + ******************************************************************************/ +GlyphTable::CompositeGlyph::CompositeGlyphBuilder::~CompositeGlyphBuilder() { +} + +GlyphTable::CompositeGlyph::CompositeGlyphBuilder::CompositeGlyphBuilder( + WritableFontData* data) + : Glyph::Builder(data) { +} + +GlyphTable::CompositeGlyph::CompositeGlyphBuilder::CompositeGlyphBuilder( + ReadableFontData* data) + : Glyph::Builder(data) { +} + +CALLER_ATTACH FontDataTable* + GlyphTable::CompositeGlyph::CompositeGlyphBuilder::SubBuildTable( + ReadableFontData* data) { + FontDataTablePtr table = new CompositeGlyph(data); + return table.Detach(); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/truetype/glyph_table.h b/gfx/sfntly/cpp/src/sfntly/table/truetype/glyph_table.h new file mode 100644 index 0000000000..e16c8c8843 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/truetype/glyph_table.h @@ -0,0 +1,325 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_GLYPH_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_GLYPH_TABLE_H_ + +#include <vector> + +#include "sfntly/table/table.h" +#include "sfntly/table/subtable.h" +#include "sfntly/table/subtable_container_table.h" + +namespace sfntly { + +struct GlyphType { + enum { + kSimple = 0, + kComposite = 1 + }; +}; + +class GlyphTable : public SubTableContainerTable, + public RefCounted<GlyphTable> { + public: + class Builder; + class Glyph : public SubTable { + public: + // Note: Contour is an empty class for the version ported + class Contour { + protected: + Contour() {} + virtual ~Contour() {} + }; + + class Builder : public SubTable::Builder { + public: + virtual ~Builder(); + + protected: + // Incoming table_builder is GlyphTable::Builder*. + // Note: constructor refactored in C++ to avoid heavy lifting. + // caller need to do data->Slice(offset, length) beforehand. + explicit Builder(WritableFontData* data); + explicit Builder(ReadableFontData* data); + + static CALLER_ATTACH Builder* + GetBuilder(GlyphTable::Builder* table_builder, + ReadableFontData* data); + static CALLER_ATTACH Builder* + GetBuilder(GlyphTable::Builder* table_builder, + ReadableFontData* data, + int32_t offset, + int32_t length); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + private: + friend class GlyphTable::Builder; + }; + + virtual ~Glyph(); + static CALLER_ATTACH Glyph* GetGlyph(GlyphTable* table, + ReadableFontData* data, + int32_t offset, + int32_t length); + + virtual int32_t Padding(); + virtual int32_t GlyphType(); + virtual int32_t NumberOfContours(); + virtual int32_t XMin(); + virtual int32_t XMax(); + virtual int32_t YMin(); + virtual int32_t YMax(); + + virtual int32_t InstructionSize() = 0; + virtual ReadableFontData* Instructions() = 0; + + protected: + // Note: constructor refactored in C++ to avoid heavy lifting. + // caller need to do data->Slice(offset, length) beforehand. + Glyph(ReadableFontData* data, int32_t glyph_type); + virtual void Initialize() = 0; + // Note: Derived class to define initialization_lock_. + + private: + static int32_t GlyphType(ReadableFontData* data, + int32_t offset, + int32_t length); + + int32_t glyph_type_; + int32_t number_of_contours_; + }; // class GlyphTable::Glyph + typedef Ptr<GlyphTable::Glyph::Builder> GlyphBuilderPtr; + typedef std::vector<GlyphBuilderPtr> GlyphBuilderList; + + class Builder : public SubTableContainerTable::Builder, + public RefCounted<GlyphTable::Builder> { + public: + // Note: Constructor scope altered to public for base class to instantiate. + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + + virtual void SetLoca(const std::vector<int32_t>& loca); + virtual void GenerateLocaList(std::vector<int32_t>* locas); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + // Gets the List of glyph builders for the glyph table builder. These may be + // manipulated in any way by the caller and the changes will be reflected in + // the final glyph table produced. + // If there is no current data for the glyph builder or the glyph builders + // have not been previously set then this will return an empty glyph builder + // List. If there is current data (i.e. data read from an existing font) and + // the <code>loca</code> list has not been set or is null, empty, or + // invalid, then an empty glyph builder List will be returned. + GlyphBuilderList* GlyphBuilders(); + + // Replace the internal glyph builders with the one provided. The provided + // list and all contained objects belong to this builder. + // This call is only required if the entire set of glyphs in the glyph + // table builder are being replaced. If the glyph builder list provided from + // the GlyphTable.Builder::GlyphBuilders() is being used and modified + // then those changes will already be reflected in the glyph table builder. + void SetGlyphBuilders(GlyphBuilderList* glyph_builders); + + // Glyph builder factories + CALLER_ATTACH Glyph::Builder* GlyphBuilder(ReadableFontData* data); + + protected: // internal API for building + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + private: + void Initialize(ReadableFontData* data, const std::vector<int32_t>& loca); + GlyphBuilderList* GetGlyphBuilders(); + void Revert(); + + GlyphBuilderList glyph_builders_; + std::vector<int32_t> loca_; + }; + + class SimpleGlyph : public Glyph, public RefCounted<SimpleGlyph> { + public: + static const int32_t kFLAG_ONCURVE; + static const int32_t kFLAG_XSHORT; + static const int32_t kFLAG_YSHORT; + static const int32_t kFLAG_REPEAT; + static const int32_t kFLAG_XREPEATSIGN; + static const int32_t kFLAG_YREPEATSIGN; + + class SimpleContour : public Glyph::Contour { + protected: + SimpleContour() {} + virtual ~SimpleContour() {} + }; + + class SimpleGlyphBuilder : public Glyph::Builder, + public RefCounted<SimpleGlyphBuilder> { + public: + virtual ~SimpleGlyphBuilder(); + + protected: + // Note: constructor refactored in C++ to avoid heavy lifting. + // caller need to do data->Slice(offset, length) beforehand. + explicit SimpleGlyphBuilder(WritableFontData* data); + explicit SimpleGlyphBuilder(ReadableFontData* data); + virtual CALLER_ATTACH FontDataTable* + SubBuildTable(ReadableFontData* data); + + private: + friend class Glyph::Builder; + }; + + // Note: constructor refactored in C++ to avoid heavy lifting. + // caller need to do data->Slice(offset, length) beforehand. + explicit SimpleGlyph(ReadableFontData* data); + virtual ~SimpleGlyph(); + + virtual int32_t InstructionSize(); + virtual CALLER_ATTACH ReadableFontData* Instructions(); + virtual void Initialize(); + + private: + void ParseData(bool fill_arrays); + int32_t FlagAsInt(int32_t index); + int32_t ContourEndPoint(int32_t contour); + + bool initialized_; + Lock initialization_lock_; + int32_t instruction_size_; + int32_t number_of_points_; + + // start offsets of the arrays + int32_t instructions_offset_; + int32_t flags_offset_; + int32_t x_coordinates_offset_; + int32_t y_coordinates_offset_; + + int32_t flag_byte_count_; + int32_t x_byte_count_; + int32_t y_byte_count_; + + std::vector<int32_t> x_coordinates_; + std::vector<int32_t> y_coordinates_; + std::vector<bool> on_curve_; + std::vector<int32_t> contour_index_; + }; + + class CompositeGlyph : public Glyph, public RefCounted<CompositeGlyph> { + public: + static const int32_t kFLAG_ARG_1_AND_2_ARE_WORDS; + static const int32_t kFLAG_ARGS_ARE_XY_VALUES; + static const int32_t kFLAG_ROUND_XY_TO_GRID; + static const int32_t kFLAG_WE_HAVE_A_SCALE; + static const int32_t kFLAG_RESERVED; + static const int32_t kFLAG_MORE_COMPONENTS; + static const int32_t kFLAG_WE_HAVE_AN_X_AND_Y_SCALE; + static const int32_t kFLAG_WE_HAVE_A_TWO_BY_TWO; + static const int32_t kFLAG_WE_HAVE_INSTRUCTIONS; + static const int32_t kFLAG_USE_MY_METRICS; + static const int32_t kFLAG_OVERLAP_COMPOUND; + static const int32_t kFLAG_SCALED_COMPONENT_OFFSET; + static const int32_t kFLAG_UNSCALED_COMPONENT_OFFSET; + + class CompositeGlyphBuilder : public Glyph::Builder, + public RefCounted<CompositeGlyphBuilder> { + public: + virtual ~CompositeGlyphBuilder(); + + protected: + // Note: constructor refactored in C++ to avoid heavy lifting. + // caller need to do data->Slice(offset, length) beforehand. + explicit CompositeGlyphBuilder(WritableFontData* data); + explicit CompositeGlyphBuilder(ReadableFontData* data); + + virtual CALLER_ATTACH FontDataTable* + SubBuildTable(ReadableFontData* data); + + private: + friend class Glyph::Builder; + }; + + // Note: constructor refactored in C++ to avoid heavy lifting. + // caller need to do data->Slice(offset, length) beforehand. + explicit CompositeGlyph(ReadableFontData* data); + virtual ~CompositeGlyph(); + + int32_t Flags(int32_t contour); + int32_t NumGlyphs(); + int32_t GlyphIndex(int32_t contour); + virtual int32_t InstructionSize(); + virtual CALLER_ATTACH ReadableFontData* Instructions(); + + protected: + virtual void Initialize(); + + private: + std::vector<int32_t> contour_index_; + int32_t instruction_size_; + int32_t instructions_offset_; + bool initialized_; + Lock initialization_lock_; + }; + + virtual ~GlyphTable(); + + // C++ port: rename glyph() to GetGlyph(). + Glyph* GetGlyph(int32_t offset, int32_t length); + + private: + struct Offset { + enum { + // header + kNumberOfContours = 0, + kXMin = 2, + kYMin = 4, + kXMax = 6, + kYMax = 8, + + // Simple Glyph Description + kSimpleEndPtsOfCountours = 10, + // offset from the end of the contours array + kSimpleInstructionLength = 0, + kSimpleInstructions = 2, + // flags + // xCoordinates + // yCoordinates + + // Composite Glyph Description + kCompositeFlags = 0, + kCompositeGyphIndexWithoutFlag = 0, + kCompositeGlyphIndexWithFlag = 2, + }; + }; + + GlyphTable(Header* header, ReadableFontData* data); +}; +typedef Ptr<GlyphTable> GlyphTablePtr; +typedef Ptr<GlyphTable::Builder> GlyphTableBuilderPtr; +typedef std::vector<GlyphTableBuilderPtr> GlyphTableBuilderList; +typedef Ptr<GlyphTable::Glyph> GlyphPtr; +typedef Ptr<GlyphTable::Glyph::Builder> GlyphBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_GLYPH_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/table/truetype/loca_table.cc b/gfx/sfntly/cpp/src/sfntly/table/truetype/loca_table.cc new file mode 100644 index 0000000000..a1e82a42b7 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/truetype/loca_table.cc @@ -0,0 +1,251 @@ +/* + * 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 "sfntly/table/truetype/loca_table.h" +#include "sfntly/port/exception_type.h" + +namespace sfntly { +/****************************************************************************** + * LocaTable class + ******************************************************************************/ +LocaTable::~LocaTable() {} + +int32_t LocaTable::GlyphOffset(int32_t glyph_id) { + if (glyph_id < 0 || glyph_id >= num_glyphs_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException("Glyph ID is out of bounds."); +#endif + return 0; + } + return Loca(glyph_id); +} + +int32_t LocaTable::GlyphLength(int32_t glyph_id) { + if (glyph_id < 0 || glyph_id >= num_glyphs_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException("Glyph ID is out of bounds."); +#endif + return 0; + } + int32_t glyph_val = Loca(glyph_id); + int32_t glyph_next_val = Loca(glyph_id + 1); + if (glyph_val < 0 || glyph_next_val < 0 || glyph_next_val <= glyph_val) + return 0; + return glyph_next_val - glyph_val; +} + +int32_t LocaTable::NumLocas() { + return num_glyphs_ + 1; +} + +int32_t LocaTable::Loca(int32_t index) { + if (index > num_glyphs_) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException(); +#endif + return 0; + } + if (format_version_ == IndexToLocFormat::kShortOffset) { + return 2 * data_->ReadUShort(index * DataSize::kUSHORT); + } + return data_->ReadULongAsInt(index * DataSize::kULONG); +} + +LocaTable::LocaTable(Header* header, + ReadableFontData* data, + int32_t format_version, + int32_t num_glyphs) + : Table(header, data), + format_version_(format_version), + num_glyphs_(num_glyphs) { +} + +/****************************************************************************** + * LocaTable::Iterator class + ******************************************************************************/ +LocaTable::LocaIterator::LocaIterator(LocaTable* table) + : PODIterator<int32_t, LocaTable>(table), index_(-1) { +} + +bool LocaTable::LocaIterator::HasNext() { + return index_ <= container()->num_glyphs_; +} + +int32_t LocaTable::LocaIterator::Next() { + return container()->Loca(index_++); +} + +/****************************************************************************** + * LocaTable::Builder class + ******************************************************************************/ +LocaTable::Builder::Builder(Header* header, WritableFontData* data) + : Table::Builder(header, data), + format_version_(IndexToLocFormat::kLongOffset), + num_glyphs_(-1) { +} + +LocaTable::Builder::Builder(Header* header, ReadableFontData* data) + : Table::Builder(header, data), + format_version_(IndexToLocFormat::kLongOffset), + num_glyphs_(-1) { +} + +LocaTable::Builder::~Builder() {} + +CALLER_ATTACH +LocaTable::Builder* LocaTable::Builder::CreateBuilder(Header* header, + WritableFontData* data) { + Ptr<LocaTable::Builder> builder; + builder = new LocaTable::Builder(header, data); + return builder.Detach(); +} + +std::vector<int32_t>* LocaTable::Builder::LocaList() { + return GetLocaList(); +} + +void LocaTable::Builder::SetLocaList(std::vector<int32_t>* list) { + loca_.clear(); + if (list) { + loca_ = *list; + set_model_changed(); + } +} + +int32_t LocaTable::Builder::GlyphOffset(int32_t glyph_id) { + if (CheckGlyphRange(glyph_id) == -1) { + return 0; + } + return GetLocaList()->at(glyph_id); +} + +int32_t LocaTable::Builder::GlyphLength(int32_t glyph_id) { + if (CheckGlyphRange(glyph_id) == -1) { + return 0; + } + return GetLocaList()->at(glyph_id + 1) - GetLocaList()->at(glyph_id); +} + +void LocaTable::Builder::SetNumGlyphs(int32_t num_glyphs) { + assert(num_glyphs >= 0); + num_glyphs_ = num_glyphs; +} + +int32_t LocaTable::Builder::NumGlyphs() { + return LastGlyphIndex() - 1; +} + +void LocaTable::Builder::Revert() { + loca_.clear(); + set_model_changed(false); +} + +int32_t LocaTable::Builder::NumLocas() { + return GetLocaList()->size(); +} + +int32_t LocaTable::Builder::Loca(int32_t index) { + return GetLocaList()->at(index); +} + +CALLER_ATTACH +FontDataTable* LocaTable::Builder::SubBuildTable(ReadableFontData* data) { + FontDataTablePtr table = + new LocaTable(header(), data, format_version_, num_glyphs_); + return table.Detach(); +} + +void LocaTable::Builder::SubDataSet() { + Initialize(InternalReadData()); +} + +int32_t LocaTable::Builder::SubDataSizeToSerialize() { + if (loca_.empty()) { + return 0; + } + if (format_version_ == IndexToLocFormat::kLongOffset) { + return loca_.size() * DataSize::kULONG; + } + return loca_.size() * DataSize::kUSHORT; +} + +bool LocaTable::Builder::SubReadyToSerialize() { + return !loca_.empty(); +} + +int32_t LocaTable::Builder::SubSerialize(WritableFontData* new_data) { + int32_t size = 0; + for (std::vector<int32_t>::iterator l = loca_.begin(), end = loca_.end(); + l != end; ++l) { + if (format_version_ == IndexToLocFormat::kLongOffset) { + size += new_data->WriteULong(size, *l); + } else { + size += new_data->WriteUShort(size, *l / 2); + } + } + num_glyphs_ = loca_.size() - 1; + return size; +} + +void LocaTable::Builder::Initialize(ReadableFontData* data) { + ClearLoca(false); + if (data) { + if (NumGlyphs() < 0) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalStateException("numglyphs not set on LocaTable Builder."); +#endif + return; + } + LocaTablePtr table = + new LocaTable(header(), data, format_version_, num_glyphs_); + Ptr<LocaTable::LocaIterator> loca_iter = + new LocaTable::LocaIterator(table); + while (loca_iter->HasNext()) { + loca_.push_back(loca_iter->Next()); + } + } +} + +int32_t LocaTable::Builder::CheckGlyphRange(int32_t glyph_id) { + if (glyph_id < 0 || glyph_id > LastGlyphIndex()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException("Glyph ID is outside of the allowed range"); +#endif + return -1; + } + return glyph_id; +} + +int32_t LocaTable::Builder::LastGlyphIndex() { + return !loca_.empty() ? loca_.size() - 2 : num_glyphs_ - 1; +} + +std::vector<int32_t>* LocaTable::Builder::GetLocaList() { + if (loca_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &loca_; +} + +void LocaTable::Builder::ClearLoca(bool nullify) { + // Note: in C++ port, nullify is not used at all. + UNREFERENCED_PARAMETER(nullify); + loca_.clear(); + set_model_changed(false); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/table/truetype/loca_table.h b/gfx/sfntly/cpp/src/sfntly/table/truetype/loca_table.h new file mode 100644 index 0000000000..fe1dd4a5e4 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/table/truetype/loca_table.h @@ -0,0 +1,183 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_LOCA_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_LOCA_TABLE_H_ + +#include "sfntly/port/java_iterator.h" +#include "sfntly/table/table.h" +#include "sfntly/table/core/font_header_table.h" + +namespace sfntly { + +// A Loca table - 'loca'. +class LocaTable : public Table, public RefCounted<LocaTable> { + public: + class LocaIterator : public PODIterator<int32_t, LocaTable> { + public: + explicit LocaIterator(LocaTable* table); + virtual ~LocaIterator() {} + + virtual bool HasNext(); + virtual int32_t Next(); + + private: + int32_t index_; + }; + + class Builder : public Table::Builder, public RefCounted<Builder> { + public: + // Constructor scope altered to public for base class to instantiate. + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + virtual ~Builder(); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + // Get the format version that will be used when the loca table is + // generated. + // @return the loca table format version + int32_t format_version() { return format_version_; } + void set_format_version(int32_t value) { format_version_ = value; } + + // Gets the List of locas for loca table builder. These may be manipulated + // in any way by the caller and the changes will be reflected in the final + // loca table produced as long as no subsequent call is made to the + // SetLocaList(List) method. + // If there is no current data for the loca table builder or the loca list + // have not been previously set then this will return an empty List. + std::vector<int32_t>* LocaList(); + + // Set the list of locas to be used for building this table. If any existing + // list was already retrieved with the LocaList() method then the + // connection of that previous list to this builder will be broken. + void SetLocaList(std::vector<int32_t>* list); + + // Return the offset for the given glyph id. Valid glyph ids are from 0 to + // one less than the number of glyphs. The zero entry is the special entry + // for the notdef glyph. The final entry beyond the last glyph id is used to + // calculate the size of the last glyph. + // @param glyphId the glyph id to get the offset for; must be less than or + // equal to one more than the number of glyph ids + // @return the offset in the glyph table to the specified glyph id + int32_t GlyphOffset(int32_t glyph_id); + + // Get the length of the data in the glyph table for the specified glyph id. + int32_t GlyphLength(int32_t glyph_id); + + // Set the number of glyphs. + // This method sets the number of glyphs that the builder will attempt to + // parse location data for from the raw binary data. This method only needs + // to be called (and <b>must</b> be) when the raw data for this builder has + // been changed. It does not by itself reset the data or clear any set loca + // list. + void SetNumGlyphs(int32_t num_glyphs); + + // Get the number of glyphs that this builder has support for. + int NumGlyphs(); + + // Revert the loca table builder to the state contained in the last raw data + // set on the builder. That raw data may be that read from a font file when + // the font builder was created, that set by a user of the loca table + // builder, or null data if this builder was created as a new empty builder. + void Revert(); + + // Get the number of locations or locas. This will be one more than the + // number of glyphs for this table since the last loca position is used to + // indicate the size of the final glyph. + int32_t NumLocas(); + + // Get the value from the loca table for the index specified. These are the + // raw values from the table that are used to compute the offset and size of + // a glyph in the glyph table. Valid index values run from 0 to the number + // of glyphs in the font. + int32_t Loca(int32_t index); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + private: + // Initialize the internal state from the data. Done lazily since in many + // cases the builder will be just creating a table object with no parsing + // required. + // @param data the data to initialize from + void Initialize(ReadableFontData* data); + + // Checks that the glyph id is within the correct range. + // @return glyph_id if correct, -1 otherwise. + int32_t CheckGlyphRange(int32_t glyph_id); + + int32_t LastGlyphIndex(); + + // Internal method to get the loca list if already generated and if not to + // initialize the state of the builder. + // @return the loca list + std::vector<int32_t>* GetLocaList(); + + void ClearLoca(bool nullify); + + int32_t format_version_; // Note: IndexToLocFormat + int32_t num_glyphs_; + std::vector<int32_t> loca_; + }; + + virtual ~LocaTable(); + + int32_t format_version() { return format_version_; } + int32_t num_glyphs() { return num_glyphs_; } + + // Return the offset for the given glyph id. Valid glyph ids are from 0 to the + // one less than the number of glyphs. The zero entry is the special entry for + // the notdef glyph. The final entry beyond the last glyph id is used to + // calculate the size of the last glyph. + // @param glyphId the glyph id to get the offset for; must be less than or + // equal to one more than the number of glyph ids + // @return the offset in the glyph table to the specified glyph id + int32_t GlyphOffset(int32_t glyph_id); + + // Get the length of the data in the glyph table for the specified glyph id. + int32_t GlyphLength(int32_t glyph_id); + + // Get the number of locations or locas. This will be one more than the number + // of glyphs for this table since the last loca position is used to indicate + // the size of the final glyph. + int32_t NumLocas(); + + // Get the value from the loca table for the index specified. Valid index + // values run from 0 to the number of glyphs in the font. + int32_t Loca(int32_t index); + + private: + LocaTable(Header* header, + ReadableFontData* data, + int32_t format_version, + int32_t num_glyphs); + + int32_t format_version_; // Note: Java's version, renamed to format_version_ + int32_t num_glyphs_; + + friend class LocaIterator; +}; +typedef Ptr<LocaTable> LocaTablePtr; +typedef Ptr<LocaTable::Builder> LocaTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_LOCA_TABLE_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/tag.cc b/gfx/sfntly/cpp/src/sfntly/tag.cc new file mode 100644 index 0000000000..c9d8c29878 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/tag.cc @@ -0,0 +1,110 @@ +/* + * 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 "sfntly/tag.h" +#include "sfntly/port/endian.h" + +// Use a macro instead of GenerateTag() because gcc 4.4.3 creates static +// initializers in that case. +#define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d); + +namespace sfntly { + +const int32_t Tag::ttcf = TAG('t', 't', 'c', 'f'); +const int32_t Tag::cmap = TAG('c', 'm', 'a', 'p'); +const int32_t Tag::head = TAG('h', 'e', 'a', 'd'); +const int32_t Tag::hhea = TAG('h', 'h', 'e', 'a'); +const int32_t Tag::hmtx = TAG('h', 'm', 't', 'x'); +const int32_t Tag::maxp = TAG('m', 'a', 'x', 'p'); +const int32_t Tag::name = TAG('n', 'a', 'm', 'e'); +const int32_t Tag::OS_2 = TAG('O', 'S', '/', '2'); +const int32_t Tag::post = TAG('p', 'o', 's', 't'); +const int32_t Tag::cvt = TAG('c', 'v', 't', ' '); +const int32_t Tag::fpgm = TAG('f', 'p', 'g', 'm'); +const int32_t Tag::glyf = TAG('g', 'l', 'y', 'f'); +const int32_t Tag::loca = TAG('l', 'o', 'c', 'a'); +const int32_t Tag::prep = TAG('p', 'r', 'e', 'p'); +const int32_t Tag::CFF = TAG('C', 'F', 'F', ' '); +const int32_t Tag::VORG = TAG('V', 'O', 'R', 'G'); +const int32_t Tag::EBDT = TAG('E', 'B', 'D', 'T'); +const int32_t Tag::EBLC = TAG('E', 'B', 'L', 'C'); +const int32_t Tag::EBSC = TAG('E', 'B', 'S', 'C'); +const int32_t Tag::BASE = TAG('B', 'A', 'S', 'E'); +const int32_t Tag::GDEF = TAG('G', 'D', 'E', 'F'); +const int32_t Tag::GPOS = TAG('G', 'P', 'O', 'S'); +const int32_t Tag::GSUB = TAG('G', 'S', 'U', 'B'); +const int32_t Tag::JSTF = TAG('J', 'S', 'T', 'F'); +const int32_t Tag::DSIG = TAG('D', 'S', 'I', 'G'); +const int32_t Tag::gasp = TAG('g', 'a', 's', 'p'); +const int32_t Tag::hdmx = TAG('h', 'd', 'm', 'x'); +const int32_t Tag::kern = TAG('k', 'e', 'r', 'n'); +const int32_t Tag::LTSH = TAG('L', 'T', 'S', 'H'); +const int32_t Tag::PCLT = TAG('P', 'C', 'L', 'T'); +const int32_t Tag::VDMX = TAG('V', 'D', 'M', 'X'); +const int32_t Tag::vhea = TAG('v', 'h', 'e', 'a'); +const int32_t Tag::vmtx = TAG('v', 'm', 't', 'x'); +const int32_t Tag::bsln = TAG('b', 's', 'l', 'n'); +const int32_t Tag::feat = TAG('f', 'e', 'a', 't'); +const int32_t Tag::lcar = TAG('l', 'c', 'a', 'r'); +const int32_t Tag::morx = TAG('m', 'o', 'r', 'x'); +const int32_t Tag::opbd = TAG('o', 'p', 'b', 'd'); +const int32_t Tag::prop = TAG('p', 'r', 'o', 'p'); +const int32_t Tag::Feat = TAG('F', 'e', 'a', 't'); +const int32_t Tag::Glat = TAG('G', 'l', 'a', 't'); +const int32_t Tag::Gloc = TAG('G', 'l', 'o', 'c'); +const int32_t Tag::Sile = TAG('S', 'i', 'l', 'e'); +const int32_t Tag::Silf = TAG('S', 'i', 'l', 'f'); +const int32_t Tag::bhed = TAG('b', 'h', 'e', 'd'); +const int32_t Tag::bdat = TAG('b', 'd', 'a', 't'); +const int32_t Tag::bloc = TAG('b', 'l', 'o', 'c'); + +const int32_t CFF_TABLE_ORDERING[] = { + Tag::head, + Tag::hhea, + Tag::maxp, + Tag::OS_2, + Tag::name, + Tag::cmap, + Tag::post, + Tag::CFF }; +const size_t CFF_TABLE_ORDERING_SIZE = + sizeof(CFF_TABLE_ORDERING) / sizeof(int32_t); + +const int32_t TRUE_TYPE_TABLE_ORDERING[] = { + Tag::head, + Tag::hhea, + Tag::maxp, + Tag::OS_2, + Tag::hmtx, + Tag::LTSH, + Tag::VDMX, + Tag::hdmx, + Tag::cmap, + Tag::fpgm, + Tag::prep, + Tag::cvt, + Tag::loca, + Tag::glyf, + Tag::kern, + Tag::name, + Tag::post, + Tag::gasp, + Tag::PCLT, + Tag::DSIG }; +const size_t TRUE_TYPE_TABLE_ORDERING_SIZE = + sizeof(TRUE_TYPE_TABLE_ORDERING) / sizeof(int32_t); + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/tag.h b/gfx/sfntly/cpp/src/sfntly/tag.h new file mode 100644 index 0000000000..0ecbab85b4 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/tag.h @@ -0,0 +1,123 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TAG_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TAG_H_ + +#include <cstddef> + +#include "sfntly/port/type.h" + +namespace sfntly { + +// Font identification tags used for tables, features, etc. +// Tag names are consistent with the OpenType and sfnt specs. +struct Tag { + static const int32_t ttcf; + + // Table Type Tags + // required tables + static const int32_t cmap; + static const int32_t head; + static const int32_t hhea; + static const int32_t hmtx; + static const int32_t maxp; + static const int32_t name; + static const int32_t OS_2; + static const int32_t post; + + // TrueType outline tables + static const int32_t cvt; + static const int32_t fpgm; + static const int32_t glyf; + static const int32_t loca; + static const int32_t prep; + + // PostScript outline tables + static const int32_t CFF; + static const int32_t VORG; + + // opentype bitmap glyph outlines + static const int32_t EBDT; + static const int32_t EBLC; + static const int32_t EBSC; + + // advanced typographic features + static const int32_t BASE; + static const int32_t GDEF; + static const int32_t GPOS; + static const int32_t GSUB; + static const int32_t JSTF; + + // other + static const int32_t DSIG; + static const int32_t gasp; + static const int32_t hdmx; + static const int32_t kern; + static const int32_t LTSH; + static const int32_t PCLT; + static const int32_t VDMX; + static const int32_t vhea; + static const int32_t vmtx; + + // AAT tables + static const int32_t bsln; + static const int32_t feat; + static const int32_t lcar; + static const int32_t morx; + static const int32_t opbd; + static const int32_t prop; + + // Graphite tables + static const int32_t Feat; + static const int32_t Glat; + static const int32_t Gloc; + static const int32_t Sile; + static const int32_t Silf; + + // truetype bitmap font tables + static const int32_t bhed; + static const int32_t bdat; + static const int32_t bloc; +}; + +// Create integer tag value for human readable tag name. +inline int32_t GenerateTag(int32_t a, int32_t b, int32_t c, int32_t d) { + return (a << 24) | (b << 16) | (c << 8) | d; +} + +// Translate tag to human readable string. +// The Caller must delete[] the returned value. +inline char* TagToString(int32_t tag) { + char *name = new char[5]; + name[0] = static_cast<char>((tag & 0xff000000) >> 24); + name[1] = static_cast<char>((tag & 0x00ff0000) >> 16); + name[2] = static_cast<char>((tag & 0x0000ff00) >> 8); + name[3] = static_cast<char>(tag & 0x000000ff); + name[4] = 0; + return name; +} + +// Note: For Java, these two orderings are in Font class. Moved here to avoid +// VC++ bug of not populating correct values. +extern const int32_t CFF_TABLE_ORDERING[]; +extern const size_t CFF_TABLE_ORDERING_SIZE; +extern const int32_t TRUE_TYPE_TABLE_ORDERING[]; +extern const size_t TRUE_TYPE_TABLE_ORDERING_SIZE; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TAG_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/tools/subsetter/glyph_table_subsetter.cc b/gfx/sfntly/cpp/src/sfntly/tools/subsetter/glyph_table_subsetter.cc new file mode 100644 index 0000000000..02cc149e29 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/tools/subsetter/glyph_table_subsetter.cc @@ -0,0 +1,90 @@ +/* + * 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 "sfntly/tools/subsetter/glyph_table_subsetter.h" + +#include "sfntly/table/truetype/glyph_table.h" +#include "sfntly/table/truetype/loca_table.h" +#include "sfntly/tag.h" +#include "sfntly/tools/subsetter/subsetter.h" +#include "sfntly/port/exception_type.h" + +namespace sfntly { + +const int32_t kGlyphTableSubsetterTags[2] = {Tag::glyf, Tag::loca}; + +GlyphTableSubsetter::GlyphTableSubsetter() + : TableSubsetterImpl(kGlyphTableSubsetterTags, 2) { +} + +GlyphTableSubsetter::~GlyphTableSubsetter() {} + +bool GlyphTableSubsetter::Subset(Subsetter* subsetter, + Font* font, + Font::Builder* font_builder) { + assert(font); + assert(subsetter); + assert(font_builder); + + std::vector<int32_t>* permutation_table = subsetter->GlyphPermutationTable(); + if (!permutation_table || permutation_table->empty()) + return false; + + GlyphTablePtr glyph_table = down_cast<GlyphTable*>(font->GetTable(Tag::glyf)); + LocaTablePtr loca_table = down_cast<LocaTable*>(font->GetTable(Tag::loca)); + if (glyph_table == NULL || loca_table == NULL) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw RuntimeException("Font to subset is not valid."); +#endif + return false; + } + + GlyphTableBuilderPtr glyph_table_builder = + down_cast<GlyphTable::Builder*> + (font_builder->NewTableBuilder(Tag::glyf)); + LocaTableBuilderPtr loca_table_builder = + down_cast<LocaTable::Builder*> + (font_builder->NewTableBuilder(Tag::loca)); + if (glyph_table_builder == NULL || loca_table_builder == NULL) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw RuntimeException("Builder for subset is not valid."); +#endif + return false; + } + GlyphTable::GlyphBuilderList* glyph_builders = + glyph_table_builder->GlyphBuilders(); + for (std::vector<int32_t>::iterator old_glyph_id = permutation_table->begin(), + old_glyph_id_end = permutation_table->end(); + old_glyph_id != old_glyph_id_end; ++old_glyph_id) { + int old_offset = loca_table->GlyphOffset(*old_glyph_id); + int old_length = loca_table->GlyphLength(*old_glyph_id); + GlyphPtr glyph; + glyph.Attach(glyph_table->GetGlyph(old_offset, old_length)); + ReadableFontDataPtr data = glyph->ReadFontData(); + WritableFontDataPtr copy_data; + copy_data.Attach(WritableFontData::CreateWritableFontData(data->Length())); + data->CopyTo(copy_data); + GlyphBuilderPtr glyph_builder; + glyph_builder.Attach(glyph_table_builder->GlyphBuilder(copy_data)); + glyph_builders->push_back(glyph_builder); + } + std::vector<int32_t> loca_list; + glyph_table_builder->GenerateLocaList(&loca_list); + loca_table_builder->SetLocaList(&loca_list); + return true; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/tools/subsetter/glyph_table_subsetter.h b/gfx/sfntly/cpp/src/sfntly/tools/subsetter/glyph_table_subsetter.h new file mode 100644 index 0000000000..88c704443f --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/tools/subsetter/glyph_table_subsetter.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_GLYPH_TABLE_SUBSETTER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_GLYPH_TABLE_SUBSETTER_H_ + +#include "sfntly/tools/subsetter/table_subsetter_impl.h" + +namespace sfntly { + +class GlyphTableSubsetter : public TableSubsetterImpl, + public RefCounted<GlyphTableSubsetter> { + public: + GlyphTableSubsetter(); + virtual ~GlyphTableSubsetter(); + + virtual bool Subset(Subsetter* subsetter, + Font* font, + Font::Builder* font_builder); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_GLYPH_TABLE_SUBSETTER_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/tools/subsetter/subsetter.cc b/gfx/sfntly/cpp/src/sfntly/tools/subsetter/subsetter.cc new file mode 100644 index 0000000000..3019cad5f4 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/tools/subsetter/subsetter.cc @@ -0,0 +1,102 @@ +/* + * 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 "sfntly/tools/subsetter/subsetter.h" + +#include <algorithm> +#include <iterator> + +#include "sfntly/tools/subsetter/glyph_table_subsetter.h" + +namespace sfntly { + +Subsetter::Subsetter(Font* font, FontFactory* font_factory) { + font_ = font; + font_factory_ = font_factory; + TableSubsetterPtr subsetter = new GlyphTableSubsetter(); + // TODO(arthurhsu): IMPLEMENT: CMap table subsetter + table_subsetters_.push_back(subsetter); +} + +Subsetter::~Subsetter() { + font_factory_.Release(); + font_.Release(); + table_subsetters_.clear(); +} + +void Subsetter::SetGlyphs(std::vector<int32_t>* glyphs) { + new_to_old_glyphs_ = *glyphs; +} + +void Subsetter::SetCMaps(CMapIdList* cmap_ids, int32_t number) { + UNREFERENCED_PARAMETER(cmap_ids); + UNREFERENCED_PARAMETER(number); + // TODO(arthurhsu): IMPLEMENT +} + +void Subsetter::SetRemoveTables(std::set<int32_t>* remove_tables) { + remove_tables_ = *remove_tables; +} + +CALLER_ATTACH Font::Builder* Subsetter::Subset() { + FontBuilderPtr font_builder; + font_builder.Attach(font_factory_->NewFontBuilder()); + + std::set<int32_t> table_tags; + for (TableMap::const_iterator i = font_->GetTableMap()->begin(), + e = font_->GetTableMap()->end(); i != e; ++i) { + table_tags.insert(i->first); + } + if (!remove_tables_.empty()) { + std::set<int32_t> result; + std::set_difference(table_tags.begin(), table_tags.end(), + remove_tables_.begin(), remove_tables_.end(), + std::inserter(result, result.end())); + table_tags = result; + } + for (TableSubsetterList::iterator + table_subsetter = table_subsetters_.begin(), + table_subsetter_end = table_subsetters_.end(); + table_subsetter != table_subsetter_end; ++table_subsetter) { + bool handled = (*table_subsetter)->Subset(this, font_, font_builder); + if (handled) { + std::set<int32_t>* handled_tags = (*table_subsetter)->TagsHandled(); + std::set<int32_t> result; + std::set_difference(table_tags.begin(), table_tags.end(), + handled_tags->begin(), handled_tags->end(), + std::inserter(result, result.end())); + table_tags = result; + } + } + for (std::set<int32_t>::iterator tag = table_tags.begin(), + tag_end = table_tags.end(); tag != tag_end; ++tag) { + Table* table = font_->GetTable(*tag); + if (table) { + font_builder->NewTableBuilder(*tag, table->ReadFontData()); + } + } + return font_builder.Detach(); +} + +std::vector<int32_t>* Subsetter::GlyphPermutationTable() { + return &new_to_old_glyphs_; +} + +CMapIdList* Subsetter::CMapId() { + return &cmap_ids_; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/tools/subsetter/subsetter.h b/gfx/sfntly/cpp/src/sfntly/tools/subsetter/subsetter.h new file mode 100644 index 0000000000..d0a2607b3a --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/tools/subsetter/subsetter.h @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_SUBSETTER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_SUBSETTER_H_ + +#include <vector> + +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/table/core/cmap_table.h" +#include "sfntly/tools/subsetter/table_subsetter.h" + +namespace sfntly { + +class Subsetter : public RefCounted<Subsetter> { + public: + Subsetter(Font* font, FontFactory* font_factory); + virtual ~Subsetter(); + + virtual void SetGlyphs(std::vector<int32_t>* glyphs); + + // Set the cmaps to be used in the subsetted font. The cmaps are listed in + // order of priority and the number parameter gives a count of how many of the + // list should be put into the subsetted font. If there are no matches in the + // font for any of the provided cmap ids which would lead to a font with no + // cmap then an error will be thrown during subsetting. + // The two most common cases would be: <list> + // * a list of one or more cmap ids with a count setting of 1 + // This will use the list of cmap ids as an ordered priority and look for + // an available cmap in the font that matches the requests. Only the first + // such match will be placed in the subsetted font. + // * a list of one or more cmap ids with a count setting equal to the list + // length + // This will use the list of cmap ids and try to place each one specified + // into the subsetted font. + // @param cmapIds the cmap ids to use for the subsetted font + // @param number the maximum number of cmaps to place in the subsetted font + virtual void SetCMaps(CMapIdList* cmap_ids, int32_t number); + + virtual void SetRemoveTables(std::set<int32_t>* remove_tables); + virtual CALLER_ATTACH Font::Builder* Subset(); + virtual std::vector<int32_t>* GlyphPermutationTable(); + virtual CMapIdList* CMapId(); + + private: + FontPtr font_; + FontFactoryPtr font_factory_; + TableSubsetterList table_subsetters_; + + // Settings from user + std::set<int32_t> remove_tables_; + std::vector<int32_t> new_to_old_glyphs_; + CMapIdList cmap_ids_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_SUBSETTER_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/tools/subsetter/table_subsetter.h b/gfx/sfntly/cpp/src/sfntly/tools/subsetter/table_subsetter.h new file mode 100644 index 0000000000..6a39f73fbc --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/tools/subsetter/table_subsetter.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_H_ + +#include <vector> + +#include "sfntly/font.h" + +namespace sfntly { + +class Subsetter; +class TableSubsetter : virtual public RefCount { + public: + virtual std::set<int32_t>* TagsHandled() = 0; + virtual bool TagHandled(int32_t tag) = 0; + virtual bool Subset(Subsetter* subsetter, Font* font, + Font::Builder* font_builder) = 0; +}; +typedef Ptr<TableSubsetter> TableSubsetterPtr; +typedef std::vector<TableSubsetterPtr> TableSubsetterList; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_H_ diff --git a/gfx/sfntly/cpp/src/sfntly/tools/subsetter/table_subsetter_impl.cc b/gfx/sfntly/cpp/src/sfntly/tools/subsetter/table_subsetter_impl.cc new file mode 100644 index 0000000000..d2085a148c --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/tools/subsetter/table_subsetter_impl.cc @@ -0,0 +1,38 @@ +/* + * 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 "sfntly/tools/subsetter/table_subsetter_impl.h" + +namespace sfntly { + +TableSubsetterImpl::TableSubsetterImpl(const int32_t* tags, + size_t tags_length) { + for (size_t i = 0; i < tags_length; ++i) { + tags_.insert(tags[i]); + } +} + +TableSubsetterImpl::~TableSubsetterImpl() {} + +bool TableSubsetterImpl::TagHandled(int32_t tag) { + return tags_.find(tag) != tags_.end(); +} + +std::set<int32_t>* TableSubsetterImpl::TagsHandled() { + return &tags_; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/sfntly/tools/subsetter/table_subsetter_impl.h b/gfx/sfntly/cpp/src/sfntly/tools/subsetter/table_subsetter_impl.h new file mode 100644 index 0000000000..14c770af46 --- /dev/null +++ b/gfx/sfntly/cpp/src/sfntly/tools/subsetter/table_subsetter_impl.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_IMPL_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_IMPL_H_ + +#include "sfntly/tools/subsetter/table_subsetter.h" + +namespace sfntly { + +class TableSubsetterImpl : public TableSubsetter { + public: + TableSubsetterImpl(const int32_t* tags, size_t tags_length); + virtual ~TableSubsetterImpl(); + virtual bool TagHandled(int32_t tag); + virtual std::set<int32_t>* TagsHandled(); + + protected: + std::set<int32_t> tags_; +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_IMPL_H_ diff --git a/gfx/sfntly/cpp/src/test/autogenerated/cmap_basic_test.cc b/gfx/sfntly/cpp/src/test/autogenerated/cmap_basic_test.cc new file mode 100644 index 0000000000..083b27fa9d --- /dev/null +++ b/gfx/sfntly/cpp/src/test/autogenerated/cmap_basic_test.cc @@ -0,0 +1,131 @@ +/* + * 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. + */ + +// type.h needs to be included first because of building issues on Windows +// Type aliases we delcare are defined in other headers and make the build +// fail otherwise. +#include "sfntly/port/type.h" +#include <assert.h> +#include <stdio.h> +#include <unicode/ucnv.h> + +#include <iostream> +#include <string> + +#include "gtest/gtest.h" +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/table/core/cmap_table.h" +#include "sfntly/table/core/font_header_table.h" +#include "sfntly/tag.h" +#include "test/autogenerated/cmap_test_data.h" +#include "test/test_font_utils.h" +#include "test/test_utils.h" +#include "test/test_xml_utils.h" + +namespace sfntly { + +#if GTEST_HAS_PARAM_TEST + +using ::testing::TestWithParam; +using ::testing::Values; + +class CMapBasicTests : public :: testing::TestWithParam<const char*> { + public: + CMapBasicTests() {} + virtual void SetUp(); + virtual void TearDown() {} + + Ptr<CMapTable> cmap_table_; + TiXmlDocument document_; +}; + +void CMapBasicTests::SetUp() { + // Loading the font + Ptr<FontFactory> font_factory; + font_factory.Attach(FontFactory::GetInstance()); + FontArray font_array; + std::string font_name = "../../"; +#if defined (WIN32) + font_name += "../"; +#endif + font_name += std::string(GetParam()); + LoadFont(font_name.c_str(), font_factory, &font_array); + ASSERT_FALSE(font_array.empty()); + Ptr<Font> font = font_array.at(0); + ASSERT_NE(font, static_cast<Font*>(NULL)); + cmap_table_ = down_cast<CMapTable*>(font->GetTable(Tag::cmap)); + if (!cmap_table_) + fprintf(stderr, "No CMap: %s\n", font_name.c_str()); + ASSERT_NE(cmap_table_, static_cast<CMapTable*>(NULL)); + + // Loading the XML file + document_ = TiXmlDocument((font_name + ".xml").c_str()); + ASSERT_TRUE(document_.LoadFile()); +} + +TEST_P(CMapBasicTests, BasicTest) { + TiXmlNodeVector* cmap_table = GetNodesWithName(&document_, "cmap_table"); + // A font can only have one CMap table + ASSERT_EQ(cmap_table->size(), (size_t)1); + TiXmlNodeVector* cmaps = GetNodesWithName(cmap_table->at(0), "cmap"); + const TiXmlAttribute* num_cmaps_attr = GetAttribute(cmap_table->at(0), + "num_cmaps"); + ASSERT_NE(num_cmaps_attr, static_cast<TiXmlAttribute*>(NULL)); + // But there may be more than one CMap in this table + ASSERT_LE(cmaps->size(), (size_t)num_cmaps_attr->IntValue()); + for (TiXmlNodeVector::iterator it = cmaps->begin(); + it != cmaps->end(); ++it) { + int32_t platform_id = GetAttribute(*it, "platform_id")->IntValue(); + int32_t encoding_id = GetAttribute(*it, "encoding_id")->IntValue(); + Ptr<CMapTable::CMap> cmap; + cmap.Attach(cmap_table_->GetCMap(platform_id, encoding_id)); + if (!cmap) { + fprintf(stderr, "Cannot test unsupported CMapFormat%d\n", + GetAttribute(*it, "format")->IntValue()); + continue; + } + ASSERT_EQ(cmap->platform_id(), platform_id); + ASSERT_EQ(cmap->encoding_id(), encoding_id); + TiXmlNodeVector* maps = GetNodesWithName(*it, "map"); + for (TiXmlNodeVector::iterator jt = maps->begin(); + jt != maps->end(); ++jt) { + int32_t character; +#if defined (WIN32) + sscanf_s(GetAttribute(*jt, "char")->Value(), "%x", &character); +#else + sscanf(GetAttribute(*jt, "char")->Value(), "%x", &character); +#endif + int32_t glyph_id = GetAttribute(*jt, "gid")->IntValue(); + ASSERT_EQ(cmap->GlyphId(character), glyph_id); + } + delete maps; + } + delete cmaps; + delete cmap_table; +} + +INSTANTIATE_TEST_CASE_P(CMapBasicTests, + CMapBasicTests, + ::testing::ValuesIn(cmap_test_data::kAllTests)); + +#else + +TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {} + +#endif // GTEST_HAS_PARAM +} diff --git a/gfx/sfntly/cpp/src/test/autogenerated/cmap_test_data.h b/gfx/sfntly/cpp/src/test/autogenerated/cmap_test_data.h new file mode 100644 index 0000000000..4a9f267d1c --- /dev/null +++ b/gfx/sfntly/cpp/src/test/autogenerated/cmap_test_data.h @@ -0,0 +1,185 @@ +/* + * !!! DO NOT EDIT !!! + * THIS FILE IS GENERATED BY A SCRIPT. + * FOR MORE DETAILS SEE 'README-test_data.txt'. + */ + +/* + * 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. + */ + +#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_TEST_AUTOGENERATED_CMAP_TEST_DATA_H_ +#define TYPOGRAPHY_FONT_SFNTLY_SRC_TEST_AUTOGENERATED_CMAP_TEST_DATA_H_ + +#include "sfntly/port/type.h" + +namespace sfntly { +namespace cmap_test_data { +const char* kAllTests[] = { + "data/fonts/cousine/Cousine-BoldItalic.ttf", + "data/fonts/cousine/Cousine-Bold.ttf", + "data/fonts/cousine/Cousine-Regular.ttf", + "data/fonts/cousine/Cousine-Italic.ttf", + "data/fonts/cedarvillecursive/Cedarville-Cursive.ttf", + "data/fonts/dancingscript/DancingScript-Bold.ttf", + "data/fonts/dancingscript/DancingScript-Regular.ttf", + "data/fonts/damion/Damion-Regular.ttf", + "data/fonts/annieuseyourtelescope/AnnieUseYourTelescope.ttf", + "data/fonts/deliusswashcaps/DeliusSwashCaps-Regular.ttf", + "data/fonts/delius/Delius-Regular.ttf", + "data/fonts/coveredbyyourgrace/CoveredByYourGrace.ttf", + "data/fonts/ebgaramond/EBGaramond-Regular.ttf", + "data/fonts/cabinsketch/CabinSketch-Bold.ttf", + "data/fonts/allan/Allan-Bold.ttf", + "data/fonts/coda/Coda-Caption-Heavy.ttf", + "data/fonts/coda/Coda-Heavy.ttf", + "data/fonts/forum/Forum-Regular.ttf", + "data/fonts/alike/Alike-Regular.ttf", + "data/fonts/corben/Corben-Bold.ttf", + "data/fonts/caudex/Caudex-Regular.ttf", + "data/fonts/caudex/Caudex-BoldItalic.ttf", + "data/fonts/caudex/Caudex-Italic.ttf", + "data/fonts/caudex/Caudex-Bold.ttf", + "data/fonts/cabin/Cabin-MediumItalic.ttf", + "data/fonts/cabin/Cabin-SemiBold.ttf", + "data/fonts/cabin/Cabin-SemiBoldItalic.ttf", + "data/fonts/cabin/Cabin-BoldItalic.ttf", + "data/fonts/cabin/Cabin-Medium.ttf", + "data/fonts/cabin/Cabin-Italic.ttf", + "data/fonts/cabin/Cabin-Bold.ttf", + "data/fonts/cabin/Cabin-Regular.ttf", + "data/fonts/dawningofanewday/DawningofaNewDay.ttf", + "data/fonts/dangrek/Dangrek.ttf", + "data/fonts/blackopsone/BlackOpsOne.ttf", + "data/fonts/francoisone/FrancoisOne.ttf", + "data/fonts/bowlbyone/BowlbyOne.ttf", + "data/fonts/bowlbyone/BowlbyOneSC.ttf", + "data/fonts/calligraffiti/Calligraffiti.ttf", + "data/fonts/bangers/Bangers.ttf", + "data/fonts/astloch/Astloch-Regular.ttf", + "data/fonts/astloch/Astloch-Bold.ttf", + "data/fonts/angkor/Angkor.ttf", + "data/fonts/abrilfatface/AbrilFatface-Regular.ttf", + "data/fonts/cantarell/Cantarell-BoldOblique.ttf", + "data/fonts/cantarell/Cantarell-Oblique.ttf", + "data/fonts/cantarell/Cantarell-Bold.ttf", + "data/fonts/cantarell/Cantarell-Regular.ttf", + "data/fonts/arvo/Arvo-Bold.ttf", + "data/fonts/arvo/Arvo-Italic.ttf", + "data/fonts/arvo/Arvo-BoldItalic.ttf", + "data/fonts/arvo/Arvo-Regular.ttf", + "data/fonts/chewy/Chewy.ttf", + "data/fonts/bigshotone/BigshotOne.ttf", + "data/fonts/chenla/Chenla.ttf", + "data/fonts/bayon/Bayon.ttf", + "data/fonts/coustard/Coustard-Black.ttf", + "data/fonts/coustard/Coustard-Regular.ttf", + "data/fonts/amaticsc/AmaticSC-Bold.ttf", + "data/fonts/amaticsc/AmaticSC-Regular.ttf", + "data/fonts/comfortaa/Comfortaa-Light.ttf", + "data/fonts/comfortaa/Comfortaa-Bold.ttf", + "data/fonts/comfortaa/Comfortaa-Regular.ttf", + "data/fonts/expletussans/ExpletusSans-Bold.ttf", + "data/fonts/expletussans/ExpletusSans-MediumItalic.ttf", + "data/fonts/expletussans/ExpletusSans-Medium.ttf", + "data/fonts/expletussans/ExpletusSans-SemiBold.ttf", + "data/fonts/expletussans/ExpletusSans-Regular.ttf", + "data/fonts/expletussans/ExpletusSans-Italic.ttf", + "data/fonts/expletussans/ExpletusSans-SemiBoldItalic.ttf", + "data/fonts/expletussans/ExpletusSans-BoldItalic.ttf", + "data/fonts/aubrey/Aubrey-Regular.ttf", + "data/fonts/antic/Antic-Regular.ttf", + "data/fonts/copse/Copse-Regular.ttf", + "data/fonts/daysone/DaysOne-Regular.ttf", + "data/fonts/actor/Actor-Regular.ttf", + "data/fonts/bentham/Bentham-Regular.ttf", + "data/fonts/federo/Federo-Regular.ttf", + "data/fonts/arimo/Arimo-Italic.ttf", + "data/fonts/arimo/Arimo-BoldItalic.ttf", + "data/fonts/arimo/Arimo-Bold.ttf", + "data/fonts/arimo/Arimo-Regular.ttf", + "data/fonts/felltypes/IMFeDPsc28P.ttf", + "data/fonts/felltypes/IMFeGPrm28P.ttf", + "data/fonts/felltypes/IMFeENsc28P.ttf", + "data/fonts/felltypes/IMFePIit28P.ttf", + "data/fonts/felltypes/IMFeDPrm28P.ttf", + "data/fonts/felltypes/IMFePIrm28P.ttf", + "data/fonts/felltypes/IMFeFCrm28P.ttf", + "data/fonts/felltypes/IMFeGPit28P.ttf", + "data/fonts/felltypes/IMFeENit28P.ttf", + "data/fonts/felltypes/IMFeDPit28P.ttf", + "data/fonts/felltypes/IMFeENrm28P.ttf", + "data/fonts/felltypes/IMFeGPsc28P.ttf", + "data/fonts/felltypes/IMFePIsc28P.ttf", + "data/fonts/felltypes/IMFeFCsc28P.ttf", + "data/fonts/felltypes/IMFeFCit28P.ttf", + "data/fonts/bokor/Bokor.ttf", + "data/fonts/didactgothic/DidactGothic.ttf", + "data/fonts/allerta/Allerta-Medium.ttf", + "data/fonts/allerta/Allerta-Stencil.ttf", + "data/fonts/buda/Buda-Light.ttf", + "data/fonts/brawler/Brawler-Regular.ttf", + "data/fonts/carterone/CarterOne.ttf", + "data/fonts/candal/Candal.ttf", + "data/fonts/dorsa/Dorsa-Regular.ttf", + "data/fonts/crimson/CrimsonText-BoldItalic.ttf", + "data/fonts/crimson/CrimsonText-Bold.ttf", + "data/fonts/crimson/CrimsonText-Italic.ttf", + "data/fonts/crimson/CrimsonText-Roman.ttf", + "data/fonts/crimson/CrimsonText-Semibold.ttf", + "data/fonts/crimson/CrimsonText-SemiboldItalic.ttf", + "data/fonts/amaranth/Amaranth-Italic.ttf", + "data/fonts/amaranth/Amaranth-Bold.ttf", + "data/fonts/amaranth/Amaranth-Regular.ttf", + "data/fonts/amaranth/Amaranth-BoldItalic.ttf", + "data/fonts/crushed/Crushed.ttf", + "data/fonts/adamina/Adamina-Regular.ttf", + "data/fonts/aldrich/Aldrich-Regular.ttf", + "data/fonts/fanwoodtext/FanwoodText-Italic.ttf", + "data/fonts/fanwoodtext/FanwoodText-Regular.ttf", + "data/fonts/anonymouspro/AnonymousPro-Regular.ttf", + "data/fonts/anonymouspro/AnonymousPro-Bold.ttf", + "data/fonts/anonymouspro/AnonymousPro-Italic.ttf", + "data/fonts/anonymouspro/AnonymousPro-BoldItalic.ttf", + "data/fonts/bevan/Bevan.ttf", + "data/fonts/artifika/Artifika-Regular.ttf", + "data/fonts/anton/Anton.ttf", + "data/fonts/battambang/Battambang-Regular.ttf", + "data/fonts/battambang/Battambang-Bold.ttf", + "data/fonts/carme/Carme-Regular.ttf", + "data/fonts/cherrycreamsoda/CherryCreamSoda.ttf", + "data/fonts/deliusunicase/DeliusUnicase-Regular.ttf", + "data/fonts/comingsoon/ComingSoon.ttf", + "data/fonts/freehand/Freehand.ttf", + "data/fonts/alice/Alice-Regular.ttf", + "data/fonts/contrail/Contrail-Regular.ttf", + "data/fonts/cardo/Cardo-Bold.ttf", + "data/fonts/cardo/Cardo-Italic.ttf", + "data/fonts/cardo/Cardo-Regular.ttf", + "data/fonts/asset/Asset.ttf", + "data/fonts/changaone/ChangaOne-Regular.ttf", + "data/fonts/aclonica/Aclonica.ttf", + "data/fonts/craftygirls/CraftyGirls.ttf", + "data/fonts/architectsdaughter/ArchitectsDaughter.ttf", + "data/fonts/content/Content-Bold.ttf", + "data/fonts/content/Content-Regular.ttf", + "data/fonts/abel/Abel-Regular.ttf", + "data/fonts/cuprum/Cuprum.ttf", + "data/fonts/andika/Andika-R.ttf" +}; +} // namespace cmap_test_data +} // namespace sfntly + +#endif // TYPOGRAPHY_FONT_SFNTLY_SRC_TEST_AUTOGENERATED_CMAP_TEST_DATA_H_ diff --git a/gfx/sfntly/cpp/src/test/bitmap_table_test.cc b/gfx/sfntly/cpp/src/test/bitmap_table_test.cc new file mode 100644 index 0000000000..e9eacc7aac --- /dev/null +++ b/gfx/sfntly/cpp/src/test/bitmap_table_test.cc @@ -0,0 +1,216 @@ +/* + * 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 "gtest/gtest.h" +#include "sfntly/font.h" +#include "sfntly/port/file_input_stream.h" +#include "sfntly/port/memory_input_stream.h" +#include "sfntly/port/memory_output_stream.h" +#include "sfntly/table/bitmap/ebdt_table.h" +#include "sfntly/table/bitmap/eblc_table.h" +#include "sfntly/table/bitmap/index_sub_table_format3.h" +#include "sfntly/table/bitmap/index_sub_table_format4.h" +#include "test/test_data.h" +#include "test/test_font_utils.h" + +namespace sfntly { + +const int32_t NUM_STRIKES = 4; +const int32_t STRIKE1_ARRAY_OFFSET = 0xc8; +const int32_t STRIKE1_INDEX_TABLE_SIZE = 0x4f4; +const int32_t STRIKE1_NUM_INDEX_TABLES = 1; +const int32_t STRIKE1_COLOR_REF = 0; +const int32_t STRIKE1_START_GLYPH_INDEX = 0; +const int32_t STRIKE1_END_GLYPH_INDEX = 623; +const int32_t STRIKE1_PPEM_X = 10; +const int32_t STRIKE1_PPEM_Y = 10; +const int32_t STRIKE1_BIT_DEPTH = 1; +const int32_t STRIKE1_FLAGS = 0x01; + +const int32_t STRIKE4_SUB1_INDEX_FORMAT = 3; +const int32_t STRIKE4_SUB1_IMAGE_FORMAT = 1; +const int32_t STRIKE4_SUB1_IMAGE_DATA_OFFSET = 0x00005893; +const int32_t STRIKE4_SUB1_GLYPH_OFFSET[] = { + 0x00005893, 0x00005898, 0x0000589d, 0x000058a2, 0x000058a7, + 0x000058b2, 0x000058c2, 0x000058d0, 0x000058de, 0x000058e6 }; +const int32_t NUM_STRIKE4_SUB1_GLYPH_OFFSET = 10; +const int32_t STRIKE4_SUB1_GLYPH2_LENGTH = 0x58a2 - 0x589d; + +bool CommonReadingTest(Font* raw_font) { + FontPtr font = raw_font; + + EblcTablePtr bitmap_loca = down_cast<EblcTable*>(font->GetTable(Tag::EBLC)); + EbdtTablePtr bitmap_table = down_cast<EbdtTable*>(font->GetTable(Tag::EBDT)); + + EXPECT_FALSE(bitmap_loca == NULL); + EXPECT_FALSE(bitmap_table == NULL); + + if (!bitmap_loca) { + return false; + } + + EXPECT_EQ(bitmap_loca->NumSizes(), NUM_STRIKES); + + // Strike 1 + BitmapSizeTablePtr strike1 = bitmap_loca->GetBitmapSizeTable(0); + EXPECT_FALSE(strike1 == NULL); + if (!strike1) { + return false; + } + EXPECT_EQ(strike1->IndexSubTableArrayOffset(), STRIKE1_ARRAY_OFFSET); + EXPECT_EQ(strike1->NumberOfIndexSubTables(), STRIKE1_NUM_INDEX_TABLES); + EXPECT_EQ(strike1->ColorRef(), STRIKE1_COLOR_REF); + EXPECT_EQ(strike1->StartGlyphIndex(), STRIKE1_START_GLYPH_INDEX); + EXPECT_EQ(strike1->EndGlyphIndex(), STRIKE1_END_GLYPH_INDEX); + EXPECT_EQ(strike1->PpemX(), STRIKE1_PPEM_X); + EXPECT_EQ(strike1->PpemY(), STRIKE1_PPEM_Y); + EXPECT_EQ(strike1->BitDepth(), STRIKE1_BIT_DEPTH); + EXPECT_EQ(strike1->FlagsAsInt(), STRIKE1_FLAGS); + + // Strike 4 + // In this test font, all strikes and all subtables have same glyphs. + BitmapSizeTablePtr strike4 = bitmap_loca->GetBitmapSizeTable(3); + EXPECT_FALSE(strike4 == NULL); + EXPECT_EQ(strike4->StartGlyphIndex(), STRIKE1_START_GLYPH_INDEX); + EXPECT_EQ(strike4->EndGlyphIndex(), STRIKE1_END_GLYPH_INDEX); + IndexSubTablePtr sub1 = strike4->GetIndexSubTable(0); + EXPECT_FALSE(sub1 == NULL); + EXPECT_EQ(sub1->image_format(), STRIKE4_SUB1_IMAGE_FORMAT); + EXPECT_EQ(sub1->first_glyph_index(), STRIKE1_START_GLYPH_INDEX); + EXPECT_EQ(sub1->last_glyph_index(), STRIKE1_END_GLYPH_INDEX); + EXPECT_EQ(sub1->image_data_offset(), STRIKE4_SUB1_IMAGE_DATA_OFFSET); + + for (int32_t i = 0; i < NUM_STRIKE4_SUB1_GLYPH_OFFSET; ++i) { + EXPECT_EQ(sub1->GlyphOffset(i), STRIKE4_SUB1_GLYPH_OFFSET[i]); + } + return true; +} + +bool TestReadingBitmapTable() { + FontFactoryPtr factory; + factory.Attach(FontFactory::GetInstance()); + FontArray font_array; + LoadFont(SAMPLE_BITMAP_FONT, factory, &font_array); + FontPtr font = font_array[0]; + EXPECT_TRUE(CommonReadingTest(font)); + + EblcTablePtr bitmap_loca = down_cast<EblcTable*>(font->GetTable(Tag::EBLC)); + BitmapSizeTablePtr strike1 = bitmap_loca->GetBitmapSizeTable(0); + BitmapSizeTablePtr strike4 = bitmap_loca->GetBitmapSizeTable(3); + IndexSubTablePtr sub1 = strike4->GetIndexSubTable(0); + + EXPECT_EQ(strike1->IndexTableSize(), STRIKE1_INDEX_TABLE_SIZE); + EXPECT_EQ(sub1->index_format(), STRIKE4_SUB1_INDEX_FORMAT); + + // Strike 4 Index Sub Table 1 is a Format 3 + IndexSubTableFormat3Ptr sub3 = + down_cast<IndexSubTableFormat3*>(strike4->GetIndexSubTable(0)); + EXPECT_FALSE(sub3 == NULL); + BitmapGlyphInfoPtr info; + info.Attach(sub3->GlyphInfo(2)); + EXPECT_EQ(info->glyph_id(), 2); + EXPECT_EQ(info->block_offset(), STRIKE4_SUB1_IMAGE_DATA_OFFSET); + EXPECT_EQ(info->start_offset(), + STRIKE4_SUB1_GLYPH_OFFSET[2] - STRIKE4_SUB1_GLYPH_OFFSET[0]); + EXPECT_EQ(info->format(), STRIKE4_SUB1_IMAGE_FORMAT); + EXPECT_EQ(info->length(), STRIKE4_SUB1_GLYPH2_LENGTH); + + return true; +} + +// Function in subset_impl.cc +extern +void SubsetEBLC(EblcTable::Builder* eblc, const BitmapLocaList& new_loca); + +bool TestIndexFormatConversion() { + FontFactoryPtr factory; + factory.Attach(FontFactory::GetInstance()); + FontBuilderArray builder_array; + BuilderForFontFile(SAMPLE_BITMAP_FONT, factory, &builder_array); + + FontBuilderPtr font_builder; + font_builder = builder_array[0]; + EblcTableBuilderPtr eblc_builder = + down_cast<EblcTable::Builder*>(font_builder->GetTableBuilder(Tag::EBLC)); + BitmapLocaList new_loca; + eblc_builder->GenerateLocaList(&new_loca); + SubsetEBLC(eblc_builder, new_loca); // Format 3 -> 4 + + FontPtr new_font; + new_font.Attach(font_builder->Build()); + + // Serialize and reload the serialized font. + MemoryOutputStream os; + factory->SerializeFont(new_font, &os); + +#if defined (SFNTLY_DEBUG_BITMAP) + SerializeToFile(&os, "anon-mod.ttf"); +#endif + + MemoryInputStream is; + is.Attach(os.Get(), os.Size()); + FontArray font_array; + factory->LoadFonts(&is, &font_array); + new_font = font_array[0]; + + EXPECT_TRUE(CommonReadingTest(new_font)); + + // Strike 4 Index Sub Table 1 is a Format 4 + EblcTablePtr bitmap_loca = + down_cast<EblcTable*>(new_font->GetTable(Tag::EBLC)); + BitmapSizeTablePtr strike4 = bitmap_loca->GetBitmapSizeTable(3); + IndexSubTableFormat4Ptr sub4 = + down_cast<IndexSubTableFormat4*>(strike4->GetIndexSubTable(0)); + EXPECT_FALSE(sub4 == NULL); + + // And this subtable shall have exactly the same offset as original table + // since no subsetting happens. + FontArray original_font_array; + LoadFont(SAMPLE_BITMAP_FONT, factory, &original_font_array); + FontPtr font = original_font_array[0]; + EXPECT_FALSE(font == NULL); + EblcTablePtr original_loca = down_cast<EblcTable*>(font->GetTable(Tag::EBLC)); + EXPECT_FALSE(original_loca == NULL); + BitmapSizeTablePtr original_strike4 = bitmap_loca->GetBitmapSizeTable(3); + EXPECT_FALSE(original_strike4 == NULL); + IndexSubTableFormat3Ptr sub3 = + down_cast<IndexSubTableFormat3*>(strike4->GetIndexSubTable(0)); + EXPECT_FALSE(sub3 == NULL); + EXPECT_EQ(strike4->StartGlyphIndex(), original_strike4->StartGlyphIndex()); + EXPECT_EQ(strike4->EndGlyphIndex(), original_strike4->EndGlyphIndex()); + for (int32_t i = strike4->StartGlyphIndex(); + i <= strike4->EndGlyphIndex(); ++i) { + BitmapGlyphInfoPtr info, original_info; + info.Attach(sub4->GlyphInfo(i)); + original_info.Attach(sub3->GlyphInfo(i)); + EXPECT_EQ(info->format(), original_info->format()); + EXPECT_EQ(info->glyph_id(), original_info->glyph_id()); + EXPECT_EQ(info->length(), original_info->length()); + EXPECT_EQ(info->offset(), original_info->offset()); + } + + return true; +} + +} // namespace sfntly + +TEST(BitmapTable, Reading) { + ASSERT_TRUE(sfntly::TestReadingBitmapTable()); +} + +TEST(BitmapTable, IndexFormatConversion) { + ASSERT_TRUE(sfntly::TestIndexFormatConversion()); +} diff --git a/gfx/sfntly/cpp/src/test/byte_array_test.cc b/gfx/sfntly/cpp/src/test/byte_array_test.cc new file mode 100644 index 0000000000..de50089ee2 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/byte_array_test.cc @@ -0,0 +1,146 @@ +/* + * 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 <stdio.h> + +#include "gtest/gtest.h" +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/data/growable_memory_byte_array.h" + +namespace sfntly { +namespace byte_array_test { + +const int32_t BYTE_ARRAY_SIZES[] = + {1, 7, 127, 128, 129, 255, 256, 257, 666, 1023, 10000, 0xffff, 0x10000}; + +void FillTestByteArray(ByteArray* ba, int32_t size) { + for (int32_t i = 0; i < size; ++i) { + ba->Put(i, (uint8_t)(i % 256)); + } +} + +void ReadByteArrayWithBuffer(ByteArray* ba, ByteVector* buffer, ByteVector* b) { + b->resize(ba->Length()); + int32_t index = 0; + while (index < ba->Length()) { + int32_t bytes_read = ba->Get(index, buffer); + std::copy(buffer->begin(), buffer->begin() + bytes_read, + b->begin() + index); + index += bytes_read; + } +} + +void ReadByteArrayWithSlidingWindow(ByteArray* ba, int window_size, + ByteVector* b) { + b->resize(ba->Length()); + int32_t index = 0; + int32_t actual_window_size = window_size; + while (index < ba->Length()) { + actual_window_size = + std::min<int32_t>(actual_window_size, b->size() - index); + int32_t bytes_read = ba->Get(index, &((*b)[0]), index, actual_window_size); + index += bytes_read; + } +} + +bool ReadComparison(ByteArray* ba1, ByteArray* ba2) { + // single byte reads + for (int i = 0; i < ba1->Length(); ++i) { + EXPECT_EQ(ba1->Get(i), ba2->Get(i)); + } + + ByteVector b1, b2; + // buffer reads + int increments = std::max<int32_t>(ba1->Length() / 11, 1); + for (int buffer_size = 1; buffer_size < ba1->Length(); + buffer_size += increments) { + ByteVector buffer(buffer_size); + ReadByteArrayWithBuffer(ba1, &buffer, &b1); + ReadByteArrayWithBuffer(ba2, &buffer, &b2); + EXPECT_GT(b1.size(), static_cast<size_t>(0)); + EXPECT_EQ(b1.size(), b2.size()); + EXPECT_TRUE(std::equal(b1.begin(), b1.end(), b2.begin())); + } + + // sliding window reads + b1.clear(); + b2.clear(); + for (int window_size = 1; window_size < ba1->Length(); + window_size += increments) { + ReadByteArrayWithSlidingWindow(ba1, window_size, &b1); + ReadByteArrayWithSlidingWindow(ba2, window_size, &b2); + EXPECT_GT(b1.size(), static_cast<size_t>(0)); + EXPECT_EQ(b1.size(), b2.size()); + EXPECT_TRUE(std::equal(b1.begin(), b1.end(), b2.begin())); + } + + return true; +} + +bool CopyTest(ByteArray* ba) { + ByteArrayPtr fixed_copy = new MemoryByteArray(ba->Length()); + ba->CopyTo(fixed_copy); + EXPECT_EQ(ba->Length(), fixed_copy->Length()); + EXPECT_TRUE(ReadComparison(ba, fixed_copy)); + + ByteArrayPtr growable_copy = new GrowableMemoryByteArray(); + ba->CopyTo(growable_copy); + EXPECT_EQ(ba->Length(), growable_copy->Length()); + EXPECT_TRUE(ReadComparison(ba, growable_copy)); + + return true; +} + +bool ByteArrayTester(ByteArray* ba) { + return CopyTest(ba); +} + +} // namespace byte_array_test + +bool TestMemoryByteArray() { + fprintf(stderr, "fixed mem: size "); + for (size_t i = 0; + i < sizeof(byte_array_test::BYTE_ARRAY_SIZES) / sizeof(int32_t); ++i) { + int32_t size = byte_array_test::BYTE_ARRAY_SIZES[i]; + fprintf(stderr, "%d ", size); + ByteArrayPtr ba = new MemoryByteArray(size); + byte_array_test::FillTestByteArray(ba, size); + EXPECT_TRUE(byte_array_test::ByteArrayTester(ba)); + } + fprintf(stderr, "\n"); + return true; +} + +bool TestGrowableMemoryByteArray() { + fprintf(stderr, "growable mem: size "); + for (size_t i = 0; + i < sizeof(byte_array_test::BYTE_ARRAY_SIZES) / sizeof(int32_t); ++i) { + int32_t size = byte_array_test::BYTE_ARRAY_SIZES[i]; + fprintf(stderr, "%d ", size); + ByteArrayPtr ba = new GrowableMemoryByteArray(); + byte_array_test::FillTestByteArray(ba, size); + EXPECT_TRUE(byte_array_test::ByteArrayTester(ba)); + } + fprintf(stderr, "\n"); + return true; +} + +} // namespace sfntly + +TEST(ByteArray, All) { + ASSERT_TRUE(sfntly::TestMemoryByteArray()); + ASSERT_TRUE(sfntly::TestGrowableMemoryByteArray()); +} diff --git a/gfx/sfntly/cpp/src/test/chrome_subsetter.cc b/gfx/sfntly/cpp/src/test/chrome_subsetter.cc new file mode 100644 index 0000000000..9563ab1576 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/chrome_subsetter.cc @@ -0,0 +1,75 @@ +/* + * 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 "gtest/gtest.h" +#include "sample/chromium/font_subsetter.h" +#include "test/test_data.h" +#include "test/test_font_utils.h" + +namespace { + // Use an additional variable to easily change name for testing. + const char* kInputFileName = sfntly::SAMPLE_TTF_FILE; + const char* kFontName = "Tuffy"; + const char* kOutputFileName = "tuffy-s.ttf"; + // The subset we want: Hello, world! + // The array is unsorted to verify that the subsetter gets the glyph id + // correctly. + const unsigned int kGlyphIds[] = { 43, 72, 79, 82, 15, 3, 90, 85, 71, 4 }; + const unsigned int kGlyphIdsCount = sizeof(kGlyphIds) / sizeof(unsigned int); +} + +// This function is deliberately located at global namespace. +bool TestChromeSubsetter() { + sfntly::ByteVector input_buffer; + sfntly::LoadFile(kInputFileName, &input_buffer); + EXPECT_GT(input_buffer.size(), (size_t)0); + + unsigned char* output_buffer = NULL; + int output_length = + SfntlyWrapper::SubsetFont(kFontName, + &(input_buffer[0]), + input_buffer.size(), + kGlyphIds, + kGlyphIdsCount, + &output_buffer); + + EXPECT_GT(output_length, 0); + + if (output_length > 0) { + FILE* output_file = NULL; +#if defined WIN32 + fopen_s(&output_file, kOutputFileName, "wb"); +#else + output_file = fopen(kOutputFileName, "wb"); +#endif + EXPECT_TRUE((output_file != NULL)); + if (output_file) { + int byte_count = fwrite(output_buffer, 1, output_length, output_file); + EXPECT_EQ(byte_count, output_length); + fflush(output_file); + fclose(output_file); + } + + delete[] output_buffer; + return true; + } + + return false; +} + +TEST(ChromeSubsetter, All) { + EXPECT_TRUE(TestChromeSubsetter()); +} diff --git a/gfx/sfntly/cpp/src/test/cmap_editing_test.cc b/gfx/sfntly/cpp/src/test/cmap_editing_test.cc new file mode 100644 index 0000000000..299b607625 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/cmap_editing_test.cc @@ -0,0 +1,101 @@ +/* + * 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 <map> +#include <algorithm> + +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/table/core/font_header_table.h" +#include "sfntly/tag.h" +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/port/endian.h" +#include "sfntly/port/file_input_stream.h" +#include "sfntly/port/memory_output_stream.h" +#include "test/test_data.h" +#include "test/test_font_utils.h" +#include "sfntly/table/core/cmap_table.h" +#include "sfntly/port/refcount.h" +#include "gtest/gtest.h" + +namespace sfntly { +TEST(CMapEditingTest, RemoveAllButOneCMap) { + FontBuilderArray builders; + FontFactoryPtr font_factory; + font_factory.Attach(FontFactory::GetInstance()); + BuilderForFontFile(SAMPLE_TTF_FILE, font_factory, &builders); + ASSERT_FALSE(builders.empty()); + FontBuilderPtr font_builder = builders[0]; + Ptr<CMapTable::Builder> cmap_table_builder = + (CMapTable::Builder*)font_builder->GetTableBuilder(Tag::cmap); + ASSERT_NE(cmap_table_builder, static_cast<CMapTable::Builder*>(NULL)); + CMapTable::CMapBuilderMap* + cmap_builders = cmap_table_builder->GetCMapBuilders(); + ASSERT_FALSE(cmap_builders->empty()); + + for (CMapTable::CMapBuilderMap::iterator + it = cmap_builders->begin(); it != cmap_builders->end();) { + if (it->second->cmap_id() == CMapTable::WINDOWS_BMP) { + ++it; + } else { + cmap_builders->erase(it++); + } + } + ASSERT_EQ(cmap_builders->size(), (uint32_t)1); + Font* font = font_builder->Build(); + CMapTablePtr cmap_table = down_cast<CMapTable*>(font->GetTable(Tag::cmap)); + ASSERT_EQ(1, cmap_table->NumCMaps()); + CMapTable::CMapPtr cmap; + cmap.Attach(cmap_table->GetCMap(CMapTable::WINDOWS_BMP)); + ASSERT_EQ(CMapTable::WINDOWS_BMP, cmap->cmap_id()); + delete font; +} + +TEST(CMapEditingTest, CopyAllCMapsToNewFont) { + FontArray fonts; + FontFactoryPtr font_factory; + font_factory.Attach(FontFactory::GetInstance()); + LoadFont(SAMPLE_TTF_FILE, font_factory, &fonts); + + ASSERT_FALSE(fonts.empty()); + ASSERT_FALSE(fonts[0] == NULL); + FontPtr font = fonts[0]; + CMapTablePtr cmap_table = down_cast<CMapTable*>(font->GetTable(Tag::cmap)); + FontBuilderPtr font_builder; + font_builder.Attach(font_factory->NewFontBuilder()); + Ptr<CMapTable::Builder> cmap_table_builder = + (CMapTable::Builder*)font_builder->NewTableBuilder(Tag::cmap); + + CMapTable::CMapIterator cmap_iter(cmap_table, NULL); + while (cmap_iter.HasNext()) { + CMapTable::CMapPtr cmap; + cmap.Attach(cmap_iter.Next()); + if (!cmap) + continue; + cmap_table_builder->NewCMapBuilder(cmap->cmap_id(), cmap->ReadFontData()); + } + + FontPtr new_font; + new_font.Attach(font_builder->Build()); + CMapTablePtr new_cmap_table = + down_cast<CMapTable*>(font->GetTable(Tag::cmap)); + ASSERT_EQ(cmap_table->NumCMaps(), new_cmap_table->NumCMaps()); + CMapTable::CMapPtr cmap; + cmap.Attach(cmap_table->GetCMap(CMapTable::WINDOWS_BMP)); + ASSERT_NE(cmap, static_cast<CMapTable::CMap*>(NULL)); + ASSERT_EQ(CMapTable::WINDOWS_BMP, cmap->cmap_id()); +} +} diff --git a/gfx/sfntly/cpp/src/test/cmap_iterator_test.cc b/gfx/sfntly/cpp/src/test/cmap_iterator_test.cc new file mode 100644 index 0000000000..e01a301628 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/cmap_iterator_test.cc @@ -0,0 +1,156 @@ +/* + * 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> + +#include <vector> +#include <string> +#include <algorithm> + +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/table/core/cmap_table.h" +#include "sfntly/tag.h" +#include "sfntly/port/type.h" +#include "sfntly/port/refcount.h" +#include "test/test_data.h" +#include "test/test_font_utils.h" + +#include "gtest/gtest.h" + +#if GTEST_HAS_PARAM_TEST + +namespace sfntly { +using ::testing::TestWithParam; +using ::testing::Values; + +typedef std::vector<bool> BitSet; + +class CMapIteratorTestCase { + public: + CMapIteratorTestCase(int32_t platform_id, int32_t encoding_id, + const char* file_name) + : platform_id_(platform_id), + encoding_id_(encoding_id), + file_name_(file_name) { + } + ~CMapIteratorTestCase() {} + int32_t platform_id() const { return platform_id_; } + int32_t encoding_id() const { return encoding_id_; } + const char* file_name() const { return file_name_; } + + private: + int32_t platform_id_; + int32_t encoding_id_; + const char* file_name_; +}; + +class CMapIteratorTests + : public ::testing::TestWithParam<CMapIteratorTestCase> { + public: + virtual void SetUp(); + virtual void TearDown() {} + + BitSet* GenerateCMapEntries(int32_t start, int32_t count); + int32_t CompareCMapIterAndBitSet(CMapTable::CMap::CharacterIterator* + character_iterator, + BitSet* bit_set); + + Ptr<CMapTable::CMap> cmap_; +}; + +void CMapIteratorTests::SetUp() { + FontArray fonts; + Ptr<FontFactory> font_factory; + const char* file_name = GetParam().file_name(); + LoadFont(file_name, font_factory, &fonts); + Ptr<Font> font; + font.Attach(fonts[0].Detach()); + Ptr<CMapTable> cmap_table = down_cast<CMapTable*>(font->GetTable(Tag::cmap)); + ASSERT_FALSE(cmap_table == NULL); + cmap_.Attach(cmap_table->GetCMap(GetParam().platform_id(), + GetParam().encoding_id())); + ASSERT_FALSE(cmap_ == NULL); +} + +BitSet* CMapIteratorTests::GenerateCMapEntries(int32_t start, int32_t count) { + BitSet* entries = new BitSet(count); + for (int32_t c = start; c < start + count; ++c) { + int32_t g = cmap_->GlyphId(c); + if (g != CMapTable::NOTDEF) + (*entries)[c] = true; + } + return entries; +} + +int32_t +CMapIteratorTests:: +CompareCMapIterAndBitSet(CMapTable::CMap::CharacterIterator* character_iterator, + BitSet* bit_set) { + int32_t iterator_not_bitset_count = 0; + BitSet::iterator end = bit_set->end(), + beginning = bit_set->begin(), + init_beginning = beginning, + current = std::find(beginning, end, true); + for (int32_t next_bit = current - beginning; + character_iterator->HasNext() && current != end; + next_bit = current - init_beginning) { + int32_t c = character_iterator->Next(); + EXPECT_TRUE(c <= next_bit || current == end); + if (!(c <= next_bit || current == end)) + return -1; + if (c == next_bit) { + beginning = current + 1; + current = std::find(beginning, end, true); + } else { + iterator_not_bitset_count++; + } + } + EXPECT_EQ(end, current); +#if defined (SFNTLY_DEBUG_CMAP) + fprintf(stderr, "%s %d: Differences between iterator and bitset: %d\n", + cmap_->format(), GetParam().file_name(), iterator_not_bitset_count); +#endif + return iterator_not_bitset_count; +} + +TEST_P(CMapIteratorTests, IteratorTest) { + BitSet* bit_set = GenerateCMapEntries(0, 0x10ffff); + CMapTable::CMap::CharacterIterator* character_iterator = NULL; + character_iterator = cmap_->Iterator(); + EXPECT_NE(character_iterator, + static_cast<CMapTable::CMap::CharacterIterator*>(NULL)); + CompareCMapIterAndBitSet(character_iterator, bit_set); + delete character_iterator; + delete bit_set; +} + +CMapIteratorTestCase kCMapIteratorTestsTestCases[] = { + CMapIteratorTestCase(CMapTable::WINDOWS_BMP.platform_id, + CMapTable::WINDOWS_BMP.encoding_id, + SAMPLE_TTF_FILE) +}; + +INSTANTIATE_TEST_CASE_P(CMapIteratorTests, + CMapIteratorTests, + ::testing::ValuesIn(kCMapIteratorTestsTestCases)); +} + +#else + +TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {} + +#endif // GTEST_HAS_PARAM diff --git a/gfx/sfntly/cpp/src/test/cmap_test.cc b/gfx/sfntly/cpp/src/test/cmap_test.cc new file mode 100644 index 0000000000..5961f1cea3 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/cmap_test.cc @@ -0,0 +1,213 @@ +/* + * 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 "sfntly/port/type.h" +#include <assert.h> +#include <unicode/ucnv.h> + +#include <string> +#include <iostream> + +#include "gtest/gtest.h" +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/table/core/cmap_table.h" +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/table/core/font_header_table.h" +#include "sfntly/tag.h" + +#include "test/test_utils.h" +#include "test/test_font_utils.h" +#include "test/test_data.h" + +#if GTEST_HAS_PARAM_TEST + +namespace sfntly { +using ::testing::TestWithParam; +using ::testing::Values; + +class CMapTestCase { + public: + CMapTestCase(const char* font_name, + int32_t first_platform_id, + int32_t first_encoding_id, + const char* first_charset_name, + int32_t second_platform_id, + int32_t second_encoding_id, + const char* second_charset_name, + int32_t low_char, + int32_t high_char) + : font_name_(font_name), + first_platform_id_(first_platform_id), + first_encoding_id_(first_encoding_id), + first_charset_name_(first_charset_name), + second_platform_id_(second_platform_id), + second_encoding_id_(second_encoding_id), + second_charset_name_(second_charset_name), + low_char_(low_char), + high_char_(high_char) { + } + + const char* font_name() const { return font_name_; } + int32_t first_platform_id() const { return first_platform_id_; } + int32_t first_encoding_id() const { return first_encoding_id_; } + const char* first_charset_name() const { return first_charset_name_; } + int32_t second_platform_id() const { return second_platform_id_; } + int32_t second_encoding_id() const { return second_encoding_id_; } + const char* second_charset_name() const { return second_charset_name_; } + int32_t low_char() const { return low_char_; } + int32_t high_char() const { return high_char_; } + + private: + const char* font_name_; + int32_t first_platform_id_; + int32_t first_encoding_id_; + const char* first_charset_name_; + int32_t second_platform_id_; + int32_t second_encoding_id_; + const char* second_charset_name_; + int32_t low_char_; + int32_t high_char_; +}; + +class CMapTests : public :: testing::TestWithParam<CMapTestCase> { + public: + CMapTests() : encoder1_(NULL), encoder2_(NULL), successful_setup_(false) { + } + virtual void SetUp() {} + virtual void TearDown(); + + void CommonSetUp(FontArray* font_array); + + void CompareCMaps(); + + Ptr<CMapTable::CMap> cmap1_; + Ptr<CMapTable::CMap> cmap2_; + UConverter* encoder1_; + UConverter* encoder2_; + bool successful_setup_; +}; + +::std::ostream& operator<<(::std::ostream& os, const CMapTestCase *test_case) { + return os << "(" + << test_case->font_name() << ", " + << test_case->first_platform_id() << ", " + << test_case->first_encoding_id() << ", " + << test_case->first_charset_name() << ", " + << test_case->second_platform_id() << ", " + << test_case->second_encoding_id() << ", " + << test_case->second_charset_name() << ", " + << test_case->low_char() << ", " + << test_case->high_char() << ")"; +} + +void CMapTests::CommonSetUp(FontArray* font_array) { + ASSERT_NE(font_array, static_cast<FontArray*>(NULL)); + ASSERT_FALSE(font_array->empty()); + Ptr<Font> font; + font = font_array->at(0); + ASSERT_NE(font, static_cast<Font*>(NULL)); + Ptr<CMapTable> cmap_table = + down_cast<CMapTable*>(font->GetTable(Tag::cmap)); + cmap1_.Attach(cmap_table->GetCMap(GetParam().first_platform_id(), + GetParam().first_encoding_id())); + ASSERT_NE((cmap1_), static_cast<CMapTable::CMap*>(NULL)); + cmap2_.Attach(cmap_table->GetCMap(GetParam().second_platform_id(), + GetParam().second_encoding_id())); + ASSERT_NE((cmap2_), static_cast<CMapTable::CMap*>(NULL)); + encoder1_ = TestUtils::GetEncoder(GetParam().first_charset_name()); + encoder2_ = TestUtils::GetEncoder(GetParam().second_charset_name()); + successful_setup_ = true; +} + +void CMapTests::TearDown() { + if (encoder1_) + ucnv_close(encoder1_); + if (encoder2_) + ucnv_close(encoder2_); +} + +void CMapTests::CompareCMaps() { + ASSERT_TRUE(successful_setup_); + for (int32_t uchar = GetParam().low_char(); + uchar <= GetParam().high_char(); ++uchar) { + int32_t c1 = uchar; + if (encoder1_ != NULL) + c1 = TestUtils::EncodeOneChar(encoder1_, (int16_t)uchar); + int32_t c2 = uchar; + if (encoder2_ != NULL) + c2 = TestUtils::EncodeOneChar(encoder2_, (int16_t)uchar); + int32_t glyph_id1 = cmap1_->GlyphId(c1); + int32_t glyph_id2 = cmap2_->GlyphId(c2); +#ifdef SFNTLY_DEBUG_CMAP + if (glyph_id1 != glyph_id2) + fprintf(stderr, "%x: g1=%x, %x: g2=%x\n", c1, glyph_id1, c2, glyph_id2); +#endif + ASSERT_EQ(glyph_id1, glyph_id2); + } +#ifdef SFNTLY_SFNTLY_DEBUG_CMAPCMAP + fprintf(stderr, "\n"); +#endif +} + +TEST_P(CMapTests, GlyphsBetweenCMapsFingerprint) { + Ptr<FontFactory> font_factory; + font_factory.Attach(FontFactory::GetInstance()); + font_factory->FingerprintFont(true); + FontArray font_array; + LoadFont(GetParam().font_name(), font_factory, &font_array); + CommonSetUp(&font_array); + CompareCMaps(); +} + +TEST_P(CMapTests, GlyphsBetweenCMapsNoFingerprint) { + Ptr<FontFactory> font_factory; + font_factory.Attach(FontFactory::GetInstance()); + FontArray font_array; + LoadFont(GetParam().font_name(), font_factory, &font_array); + CommonSetUp(&font_array); + CompareCMaps(); +} + +TEST_P(CMapTests, GlyphsBetweenCMapsUsingByteVector) { + FontArray font_array; + LoadFontUsingByteVector(GetParam().font_name(), true, &font_array); + CommonSetUp(&font_array); + CompareCMaps(); +} + +CMapTestCase kCMapTestsTestCases[] = { + CMapTestCase(SAMPLE_TTF_FILE, + PlatformId::kWindows, + WindowsEncodingId::kUnicodeUCS2, + NULL, + PlatformId::kUnicode, + UnicodeEncodingId::kUnicode2_0_BMP, + NULL, + (int32_t)0x20, + (int32_t)0x7f), +}; + +INSTANTIATE_TEST_CASE_P(CMapTests, + CMapTests, + ::testing::ValuesIn(kCMapTestsTestCases)); +} + +#else + +TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {} + +#endif // GTEST_HAS_PARAM diff --git a/gfx/sfntly/cpp/src/test/endian_test.cc b/gfx/sfntly/cpp/src/test/endian_test.cc new file mode 100644 index 0000000000..80cce6879a --- /dev/null +++ b/gfx/sfntly/cpp/src/test/endian_test.cc @@ -0,0 +1,77 @@ +/* + * 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 "gtest/gtest.h" +#include "sfntly/tag.h" +#include "sfntly/data/growable_memory_byte_array.h" +#include "sfntly/data/writable_font_data.h" +#include "sfntly/math/fixed1616.h" +#include "sfntly/port/memory_output_stream.h" +#include "sfntly/data/font_output_stream.h" + +namespace sfntly { + +bool TestEndian() { + uint8_t test_data[] = { + 0x68, 0x65, 0x61, 0x64, // 0: head + 0xca, 0xca, 0xca, 0xca, // 4: ubyte, byte, char + 0x00, 0x18, 0x80, 0x18, // 8: ushort, short + 0x00, 0x00, 0x18, 0x00, // 12: uint24 + 0x00, 0x00, 0x00, 0x18, // 16: ulong + 0xff, 0xff, 0xff, 0x00, // 20: long + 0x00, 0x01, 0x00, 0x00 // 24: fixed + }; + + ByteArrayPtr ba1 = new GrowableMemoryByteArray(); + for (size_t i = 0; i < sizeof(test_data); ++i) { + ba1->Put(i, test_data[i]); + } + ReadableFontDataPtr rfd = new ReadableFontData(ba1); + EXPECT_EQ(rfd->ReadULongAsInt(0), Tag::head); + EXPECT_EQ(rfd->ReadUByte(4), 202); + EXPECT_EQ(rfd->ReadByte(5), -54); + EXPECT_EQ(rfd->ReadChar(6), 202); + EXPECT_EQ(rfd->ReadUShort(8), 24); + EXPECT_EQ(rfd->ReadShort(10), -32744); + EXPECT_EQ(rfd->ReadUInt24(12), 24); + EXPECT_EQ(rfd->ReadULong(16), 24); + EXPECT_EQ(rfd->ReadLong(20), -256); + EXPECT_EQ(rfd->ReadFixed(24), Fixed1616::Fixed(1, 0)); + + MemoryOutputStream os; + FontOutputStream fos(&os); + fos.WriteULong(Tag::head); + fos.Write(202); + fos.Write(202); + fos.Write(202); + fos.Write(202); + fos.WriteUShort(24); + fos.WriteShort(-32744); + fos.WriteUInt24(24); + fos.WriteChar(0); + fos.WriteULong(24); + fos.WriteLong(-256); + fos.WriteFixed(Fixed1616::Fixed(1, 0)); + EXPECT_EQ(memcmp(os.Get(), test_data, sizeof(test_data)), 0); + + return true; +} + +} // namespace sfntly + +TEST(Endian, All) { + ASSERT_TRUE(sfntly::TestEndian()); +} diff --git a/gfx/sfntly/cpp/src/test/file_io_test.cc b/gfx/sfntly/cpp/src/test/file_io_test.cc new file mode 100644 index 0000000000..3cec4d6900 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/file_io_test.cc @@ -0,0 +1,153 @@ +/* + * 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 <stdio.h> + +#include "gtest/gtest.h" +#include "sfntly/port/file_input_stream.h" +#include "sfntly/data/font_input_stream.h" +#include "test/test_data.h" + +namespace sfntly { + +bool TestFileInputStream() { + FILE* file_handle = NULL; +#if defined (WIN32) + fopen_s(&file_handle, SAMPLE_TTF_FILE, "rb"); +#else + file_handle = fopen(SAMPLE_TTF_FILE, "rb"); +#endif + if (file_handle == NULL) { + return false; + } + fseek(file_handle, 0, SEEK_END); + size_t length = ftell(file_handle); + fseek(file_handle, 0, SEEK_SET); + ByteVector b1; + b1.resize(length); + size_t bytes_read = fread(&(b1[0]), 1, length, file_handle); + EXPECT_EQ(bytes_read, length); + fclose(file_handle); + + // Full file reading test + FileInputStream is; + is.Open(SAMPLE_TTF_FILE); + EXPECT_EQ(length, (size_t)is.Available()); + ByteVector b2; + is.Read(&b2, 0, length); + is.Close(); + EXPECT_EQ(memcmp(&(b1[0]), &(b2[0]), length), 0); + b2.clear(); + + // Partial reading test + is.Open(SAMPLE_TTF_FILE); + is.Skip(89); + is.Read(&b2, 0, 100); + EXPECT_EQ(memcmp(&(b1[89]), &(b2[0]), 100), 0); + b2.clear(); + + // Skip test + is.Skip(-89); + is.Read(&b2, 0, 100); + EXPECT_EQ(memcmp(&(b1[100]), &(b2[0]), 100), 0); + b2.clear(); + is.Skip(100); + is.Read(&b2, 0, 100); + EXPECT_EQ(memcmp(&(b1[300]), &(b2[0]), 100), 0); + is.Skip(-400); + b2.clear(); + + // Offset test + is.Read(&b2, 0, 100); + is.Read(&b2, 100, 100); + EXPECT_EQ(memcmp(&(b1[0]), &(b2[0]), 200), 0); + + // Unread test + ByteVector b3; + b3.resize(200); + is.Unread(&b3); + EXPECT_EQ(memcmp(&(b3[0]), &(b2[0]), 200), 0); + + return true; +} + +bool TestFontInputStreamBasic() { + FILE* file_handle = NULL; +#if defined (WIN32) + fopen_s(&file_handle, SAMPLE_TTF_FILE, "rb"); +#else + file_handle = fopen(SAMPLE_TTF_FILE, "rb"); +#endif + if (file_handle == NULL) { + return false; + } + fseek(file_handle, 0, SEEK_END); + size_t length = ftell(file_handle); + fseek(file_handle, 0, SEEK_SET); + ByteVector b1; + b1.resize(length); + size_t bytes_read = fread(&(b1[0]), 1, length, file_handle); + EXPECT_EQ(bytes_read, length); + fclose(file_handle); + + FileInputStream is; + is.Open(SAMPLE_TTF_FILE); + FontInputStream font_is1(&is); + EXPECT_EQ((size_t)font_is1.Available(), length); + + ByteVector b2; + font_is1.Read(&b2, 0, length); + font_is1.Close(); + EXPECT_EQ(memcmp(&(b1[0]), &(b2[0]), length), 0); + b2.clear(); + + is.Open(SAMPLE_TTF_FILE); + is.Skip(89); + FontInputStream font_is2(&is, 200); + font_is2.Read(&b2, 0, 100); + EXPECT_EQ(memcmp(&(b1[89]), &(b2[0]), 100), 0); + font_is2.Read(&b2, 100, 100); + EXPECT_EQ(memcmp(&(b1[89]), &(b2[0]), 200), 0); + b2.clear(); + font_is2.Skip(-200); + font_is2.Read(&b2, 0, 100); + EXPECT_EQ(memcmp(&(b1[89]), &(b2[0]), 100), 0); + + return true; +} + +bool TestFontInputStreamTableLoading() { + FileInputStream is; + is.Open(SAMPLE_TTF_FILE); + FontInputStream font_is(&is); + + font_is.Skip(TTF_OFFSET[SAMPLE_TTF_FEAT]); + FontInputStream gdef_is(&font_is, TTF_LENGTH[SAMPLE_TTF_FEAT]); + ByteVector feat_data; + gdef_is.Read(&feat_data, 0, TTF_LENGTH[SAMPLE_TTF_FEAT]); + EXPECT_EQ(memcmp(&(feat_data[0]), TTF_FEAT_DATA, + TTF_LENGTH[SAMPLE_TTF_FEAT]), 0); + + return true; +} + +} // namespace sfntly + +TEST(FileIO, All) { + ASSERT_TRUE(sfntly::TestFileInputStream()); + ASSERT_TRUE(sfntly::TestFontInputStreamBasic()); + ASSERT_TRUE(sfntly::TestFontInputStreamTableLoading()); +} diff --git a/gfx/sfntly/cpp/src/test/font_data_test.cc b/gfx/sfntly/cpp/src/test/font_data_test.cc new file mode 100644 index 0000000000..5ed041cb69 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/font_data_test.cc @@ -0,0 +1,337 @@ +/* + * 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 <vector> +#include <algorithm> + +#include "gtest/gtest.h" +#include "sfntly/port/type.h" +#include "sfntly/data/writable_font_data.h" +#include "sfntly/data/memory_byte_array.h" + +namespace sfntly { + +const int32_t BYTE_ARRAY_SIZES[] = + {1, 7, 127, 128, 129, 255, 256, 257, 666, 1023, 0x10000}; + +// array data for searching +const int32_t LOWER_BYTE_ARRAY_FOR_SEARCHING[] = {2, 4, 7, 13, 127}; +const int32_t UPPER_BYTE_ARRAY_FOR_SEARCHING[] = {2, 5, 12, 16, 256}; +const int32_t kLowerByteArrayForSearchingLength = 5; +const int32_t kUpperByteArrayForSearchingLength = 5; + +// search test result pairs - number to search for; index found at +const int32_t SEARCH_TEST_PAIRS[][2] = { + {0, -1}, {1, -1}, {2, 0}, {3, -1}, {4, 1}, {5, 1}, {6, -1}, {12, 2}, + {13, 3}, {17, -1}, {126, -1}, {127, 4}, {256, 4}, {257, -1}, {0x1000, -1} +}; +const int32_t kSearchTestPairsLength = 15; + +// offset and start index data for searching data +// array data size, lower_start_index, lower_offset, upper_start_index, +// upper_offset +const int32_t SEARCH_TEST_OFFSETS[][5] = { + // lower[], upper[] + { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength) + * DataSize::kUSHORT, + 0, + DataSize::kUSHORT, + kLowerByteArrayForSearchingLength * DataSize::kUSHORT, + DataSize::kUSHORT }, + + // {lower, upper} [] + { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength) + * DataSize::kUSHORT, + 0, + 2 * DataSize::kUSHORT, + DataSize::kUSHORT, + 2 * DataSize::kUSHORT }, + + // upper[], lower[] + { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength) + * DataSize::kUSHORT, + kLowerByteArrayForSearchingLength * DataSize::kUSHORT, + DataSize::kUSHORT, + 0, + DataSize::kUSHORT }, + + // {upper, lower} [] + { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength) + * DataSize::kUSHORT, + DataSize::kUSHORT, + 2 * DataSize::kUSHORT, + 0, + 2 * DataSize::kUSHORT } +}; +const int32_t kSearchTestOffsetLength = 4; + +ReadableFontData* +FillTestFontDataWithShortsForSearching(WritableFontData* wfd, + const int32_t* lower_data, + int32_t lower_start_index, + int32_t lower_offset, + const int32_t* upper_data, + int32_t upper_start_index, + int32_t upper_offset) { + // lower data + int offset = lower_start_index; + for (int32_t i = 0; i < kLowerByteArrayForSearchingLength; ++i) { + wfd->WriteUShort(offset, lower_data[i]); + offset += lower_offset; + } + + // upper data + offset = upper_start_index; + for (int32_t i = 0; i < kUpperByteArrayForSearchingLength; ++i) { + wfd->WriteUShort(offset, upper_data[i]); + offset += upper_offset; + } + + return wfd; +} + +bool TestReadableFontDataSearching() { + for (int32_t i = 0; i < kSearchTestOffsetLength; ++i) { + const int32_t* array_setup_offset = SEARCH_TEST_OFFSETS[i]; + WritableFontDataPtr wfd; + wfd.Attach(WritableFontData::CreateWritableFontData(array_setup_offset[0])); + FillTestFontDataWithShortsForSearching(wfd, + LOWER_BYTE_ARRAY_FOR_SEARCHING, + array_setup_offset[1], + array_setup_offset[2], + UPPER_BYTE_ARRAY_FOR_SEARCHING, + array_setup_offset[3], + array_setup_offset[4]); + for (int32_t j = 0; j < kSearchTestPairsLength; ++j) { + const int32_t* test_case = SEARCH_TEST_PAIRS[j]; + int32_t found = wfd->SearchUShort(array_setup_offset[1], + array_setup_offset[2], + array_setup_offset[3], + array_setup_offset[4], + kLowerByteArrayForSearchingLength, + test_case[0]); +#if defined (SFNTLY_DEBUG_FONTDATA) + fprintf(stderr, "Searching for %d; Got %d; Expected %d; " + "[test %d][offset %d]\n", + test_case[0], found, test_case[1], j, i); +#endif + EXPECT_EQ(test_case[1], found); + } + } + return true; +} + +void FillTestByteArray(ByteArray* ba, int32_t size) { + for (int32_t i = 0; i < size; ++i) { + ba->Put(i, (uint8_t)(i % 256)); + } +} + +void ReadFontDataWithSingleByte(ReadableFontData* rfd, ByteVector* buffer) { + buffer->resize(rfd->Length()); + for (int32_t index = 0; index < rfd->Length(); ++index) { + (*buffer)[index] = (uint8_t)(rfd->ReadByte(index)); + } +} + +void ReadFontDataWithBuffer(ReadableFontData* rfd, + int32_t buffer_size, + ByteVector* b) { + ByteVector buffer(buffer_size); + b->resize(rfd->Length()); + + int32_t index = 0; + while (index < rfd->Length()) { + int32_t bytes_read = rfd->ReadBytes(index, &(buffer[0]), 0, buffer.size()); + EXPECT_GE(bytes_read, 0); + std::copy(buffer.begin(), buffer.begin() + bytes_read, b->begin() + index); + index += bytes_read; + } +} + +void ReadFontDataWithSlidingWindow(ReadableFontData* rfd, int32_t window_size, + ByteVector* b) { + b->resize(rfd->Length()); + int32_t index = 0; + while (index < rfd->Length()) { + int32_t actual_window_size = + std::min<int32_t>(window_size, b->size() - index); + int32_t bytes_read = + rfd->ReadBytes(index, &((*b)[0]), index, actual_window_size); + EXPECT_GE(bytes_read, 0); + index += bytes_read; + } +} + +void WriteFontDataWithSingleByte(ReadableFontData* rfd, WritableFontData* wfd) { + for (int32_t index = 0; index < rfd->Length(); ++index) { + uint8_t b = (uint8_t)(rfd->ReadByte(index)); + wfd->WriteByte(index, b); + } +} + +void WriteFontDataWithBuffer(ReadableFontData* rfd, + WritableFontData* wfd, + int32_t buffer_size) { + ByteVector buffer(buffer_size); + int32_t index = 0; + while (index < rfd->Length()) { + int32_t bytesRead = rfd->ReadBytes(index, &(buffer[0]), 0, buffer.size()); + wfd->WriteBytes(index, &(buffer[0]), 0, buffer.size()); + index += bytesRead; + } +} + +void WriteFontDataWithSlidingWindow(ReadableFontData* rfd, + WritableFontData* wfd, + int32_t window_size) { + ByteVector b(rfd->Length()); + int32_t index = 0; + while (index < rfd->Length()) { + int32_t sliding_size = std::min<int32_t>(window_size, b.size() - index); + int32_t bytes_read = rfd->ReadBytes(index, &(b[0]), index, sliding_size); + wfd->WriteBytes(index, &(b[0]), index, sliding_size); + index += bytes_read; + } +} + +bool ReadComparison(int32_t offset, + int32_t length, + ReadableFontData* rfd1, + ReadableFontData* rfd2) { + EXPECT_TRUE(length == rfd2->Length()); + ByteVector b1, b2; + b1.resize(length); + b2.resize(length); + + // single byte reads + ReadFontDataWithSingleByte(rfd1, &b1); + ReadFontDataWithSingleByte(rfd2, &b2); + EXPECT_EQ(memcmp(&(b1[offset]), &(b2[0]), length), 0); + + // buffer reads + int32_t increments = std::max<int32_t>(length / 11, 1); + for (int32_t buffer_size = 1; buffer_size <= length; + buffer_size += increments) { + b1.clear(); + b2.clear(); + b1.resize(length); + b2.resize(length); + ReadFontDataWithBuffer(rfd1, buffer_size, &b1); + ReadFontDataWithBuffer(rfd2, buffer_size, &b2); + int result = memcmp(&(b1[offset]), &(b2[0]), length); + EXPECT_EQ(result, 0); + } + + // sliding window reads + for (int32_t window_size = 1; window_size <= length; + window_size += increments) { + b1.clear(); + b2.clear(); + b1.resize(length); + b2.resize(length); + ReadFontDataWithSlidingWindow(rfd1, window_size, &b1); + ReadFontDataWithSlidingWindow(rfd2, window_size, &b2); + int result = memcmp(&(b1[offset]), &(b2[0]), length); + EXPECT_EQ(result, 0); + } + return true; +} + +void SlicingReadTest(ReadableFontData* rfd) { + fprintf(stderr, "read - trim = "); + for (int32_t trim = 0; trim < (rfd->Length() / 2) + 1; + trim += (rfd->Length() / 21) + 1) { + fprintf(stderr, "%d ", trim); + int32_t length = rfd->Length() - 2 * trim; + ReadableFontDataPtr slice; + slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length))); + EXPECT_TRUE(ReadComparison(trim, length, rfd, slice)); + } + fprintf(stderr, "\n"); +} + +void SlicingWriteTest(ReadableFontData* rfd, WritableFontData* wfd) { + fprintf(stderr, "write - trim = "); + for (int32_t trim = 0; trim < (rfd->Length() / 2) + 1; + trim += (rfd->Length() / 21) + 1) { + fprintf(stderr, "%d ", trim); + int32_t length = rfd->Length() - 2 * trim; + WritableFontDataPtr w_slice; + ReadableFontDataPtr r_slice; + + // single byte writes + w_slice.Attach(down_cast<WritableFontData*>(wfd->Slice(trim, length))); + r_slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length))); + WriteFontDataWithSingleByte(r_slice, w_slice); + EXPECT_TRUE(ReadComparison(trim, length, rfd, w_slice)); + + // buffer writes + int32_t increments = std::max<int32_t>(length / 11, 1); + for (int32_t buffer_size = 1; buffer_size < length; + buffer_size += increments) { + w_slice.Attach(down_cast<WritableFontData*>(wfd->Slice(trim, length))); + r_slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length))); + WriteFontDataWithBuffer(r_slice, w_slice, buffer_size); + EXPECT_TRUE(ReadComparison(trim, length, rfd, w_slice)); + } + + // sliding window writes + for (int window_size = 1; window_size < length; window_size += increments) { + w_slice.Attach(down_cast<WritableFontData*>(wfd->Slice(trim, length))); + r_slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length))); + WriteFontDataWithSlidingWindow(r_slice, w_slice, window_size); + EXPECT_TRUE(ReadComparison(trim, length, rfd, w_slice)); + } + } + fprintf(stderr, "\n"); +} + +bool TestReadableFontData() { + for (size_t i = 0; i < sizeof(BYTE_ARRAY_SIZES) / sizeof(int32_t); ++i) { + int32_t size = BYTE_ARRAY_SIZES[i]; + ByteArrayPtr ba = new MemoryByteArray(size); + FillTestByteArray(ba, size); + ReadableFontDataPtr rfd = new ReadableFontData(ba); + SlicingReadTest(rfd); + } + return true; +} + +bool TestWritableFontData() { + for (size_t i = 0; i < sizeof(BYTE_ARRAY_SIZES) / sizeof(int32_t); ++i) { + int32_t size = BYTE_ARRAY_SIZES[i]; + ByteArrayPtr ba = new MemoryByteArray(size); + FillTestByteArray(ba, size); + WritableFontDataPtr wfd = new WritableFontData(ba); + SlicingReadTest(wfd); + ByteArrayPtr temp = new MemoryByteArray(size); + WritableFontDataPtr wfd_copy = new WritableFontData(temp); + SlicingWriteTest(wfd, wfd_copy); + } + return true; +} + +} // namespace sfntly + +TEST(FontData, ReadableFontDataSearching) { + ASSERT_TRUE(sfntly::TestReadableFontDataSearching()); +} + +TEST(FontData, All) { + ASSERT_TRUE(sfntly::TestReadableFontData()); + ASSERT_TRUE(sfntly::TestWritableFontData()); +} diff --git a/gfx/sfntly/cpp/src/test/font_parsing_test.cc b/gfx/sfntly/cpp/src/test/font_parsing_test.cc new file mode 100644 index 0000000000..6fd5c3b29e --- /dev/null +++ b/gfx/sfntly/cpp/src/test/font_parsing_test.cc @@ -0,0 +1,140 @@ +/* + * 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 "gtest/gtest.h" + +#include "sfntly/data/font_input_stream.h" +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/table/core/font_header_table.h" +#include "sfntly/table/table.h" +#include "sfntly/table/generic_table_builder.h" +#include "sfntly/table/table_based_table_builder.h" +#include "sfntly/tag.h" +#include "sfntly/port/file_input_stream.h" +#include "test/test_data.h" +#include "test/test_font_utils.h" + +namespace sfntly { + +bool TestFontParsing() { + ByteVector input_buffer; + LoadFile(SAMPLE_TTF_FILE, &input_buffer); + + FontFactoryPtr factory; + factory.Attach(FontFactory::GetInstance()); + // File based + FontBuilderArray font_builder_array; + BuilderForFontFile(SAMPLE_TTF_FILE, factory, &font_builder_array); + FontBuilderPtr font_builder = font_builder_array[0]; + // Memory based + FontBuilderArray font_builder_array2; + factory->LoadFontsForBuilding(&input_buffer, &font_builder_array2); + FontBuilderPtr font_builder2 = font_builder_array2[0]; + + for (size_t i = 0; i < SAMPLE_TTF_KNOWN_TAGS; ++i) { + EXPECT_TRUE(font_builder->HasTableBuilder(TTF_KNOWN_TAGS[i])); + EXPECT_TRUE(font_builder2->HasTableBuilder(TTF_KNOWN_TAGS[i])); + } + + // Generic table + Ptr<GenericTableBuilder> gdef_builder = + down_cast<GenericTableBuilder*>(font_builder->GetTableBuilder(Tag::feat)); + HeaderPtr gdef_header = gdef_builder->header(); + EXPECT_EQ(gdef_header->length(), TTF_LENGTH[SAMPLE_TTF_FEAT]); + EXPECT_EQ(gdef_header->offset(), TTF_OFFSET[SAMPLE_TTF_FEAT]); + EXPECT_EQ(gdef_header->checksum(), TTF_CHECKSUM[SAMPLE_TTF_FEAT]); + EXPECT_TRUE(gdef_header->checksum_valid()); + + WritableFontDataPtr wfd; + wfd.Attach(gdef_builder->Data()); + ByteVector b; + b.resize(TTF_LENGTH[SAMPLE_TTF_FEAT]); + wfd->ReadBytes(0, &(b[0]), 0, TTF_LENGTH[SAMPLE_TTF_FEAT]); + EXPECT_EQ(memcmp(&(b[0]), TTF_FEAT_DATA, TTF_LENGTH[SAMPLE_TTF_FEAT]), 0); + + // Header table + FontHeaderTableBuilderPtr header_builder = + down_cast<FontHeaderTable::Builder*>( + font_builder->GetTableBuilder(Tag::head)); + HeaderPtr header_header = header_builder->header(); + EXPECT_EQ(header_header->length(), TTF_LENGTH[SAMPLE_TTF_HEAD]); + EXPECT_EQ(header_header->offset(), TTF_OFFSET[SAMPLE_TTF_HEAD]); + EXPECT_EQ(header_header->checksum(), TTF_CHECKSUM[SAMPLE_TTF_HEAD]); + EXPECT_TRUE(header_header->checksum_valid()); + + // Data conformance + for (size_t i = 0; i < SAMPLE_TTF_KNOWN_TAGS; ++i) { + ByteVector b1, b2; + b1.resize(TTF_LENGTH[i]); + b2.resize(TTF_LENGTH[i]); + TableBuilderPtr builder1 = + font_builder->GetTableBuilder(TTF_KNOWN_TAGS[i]); + TableBuilderPtr builder2 = + font_builder2->GetTableBuilder(TTF_KNOWN_TAGS[i]); + WritableFontDataPtr wfd1; + wfd1.Attach(builder1->Data()); + WritableFontDataPtr wfd2; + wfd2.Attach(builder2->Data()); + wfd1->ReadBytes(0, &(b1[0]), 0, TTF_LENGTH[i]); + wfd2->ReadBytes(0, &(b2[0]), 0, TTF_LENGTH[i]); + EXPECT_EQ(memcmp(&(b1[0]), &(b2[0]), TTF_LENGTH[i]), 0); + } + + return true; +} + +bool TestTTFReadWrite() { + FontFactoryPtr factory; + factory.Attach(FontFactory::GetInstance()); + FontBuilderArray font_builder_array; + BuilderForFontFile(SAMPLE_TTF_FILE, factory, &font_builder_array); + FontBuilderPtr font_builder = font_builder_array[0]; + FontPtr font; + font.Attach(font_builder->Build()); + MemoryOutputStream output_stream; + factory->SerializeFont(font, &output_stream); + EXPECT_GE(output_stream.Size(), SAMPLE_TTF_SIZE); + + return true; +} + +bool TestTTFMemoryBasedReadWrite() { + ByteVector input_buffer; + LoadFile(SAMPLE_TTF_FILE, &input_buffer); + + FontFactoryPtr factory; + factory.Attach(FontFactory::GetInstance()); + FontBuilderArray font_builder_array; + factory->LoadFontsForBuilding(&input_buffer, &font_builder_array); + FontBuilderPtr font_builder = font_builder_array[0]; + FontPtr font; + font.Attach(font_builder->Build()); + MemoryOutputStream output_stream; + factory->SerializeFont(font, &output_stream); + EXPECT_GE(output_stream.Size(), input_buffer.size()); + + return true; +} + +} // namespace sfntly + +TEST(FontParsing, All) { + ASSERT_TRUE(sfntly::TestFontParsing()); + ASSERT_TRUE(sfntly::TestTTFReadWrite()); + ASSERT_TRUE(sfntly::TestTTFMemoryBasedReadWrite()); +} diff --git a/gfx/sfntly/cpp/src/test/hdmx_test.cc b/gfx/sfntly/cpp/src/test/hdmx_test.cc new file mode 100644 index 0000000000..cdc4ed0587 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/hdmx_test.cc @@ -0,0 +1,82 @@ +/* + * 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 "gtest/gtest.h" +#include "sfntly/font.h" +#include "sfntly/table/core/horizontal_device_metrics_table.h" +#include "test/test_data.h" +#include "test/test_font_utils.h" + +namespace sfntly { + +const int32_t HDMX_VERSION = 0; +const int32_t HDMX_NUM_RECORDS = 4; +const int32_t HDMX_RECORD_SIZE = 628; +const int32_t HDMX_PIXEL_SIZE[] = {10, 11, 12, 13}; +const int32_t HDMX_MAX_WIDTH[] = {5, 6, 7, 7}; + +bool TestReadingHdmxTable() { + FontFactoryPtr factory; + factory.Attach(FontFactory::GetInstance()); + FontArray font_array; + LoadFont(SAMPLE_BITMAP_FONT, factory, &font_array); + FontPtr font = font_array[0]; + + HorizontalDeviceMetricsTablePtr hdmx_table = + down_cast<HorizontalDeviceMetricsTable*>(font->GetTable(Tag::hdmx)); + + EXPECT_FALSE(hdmx_table == NULL); + + EXPECT_EQ(hdmx_table->Version(), HDMX_VERSION); + EXPECT_EQ(hdmx_table->NumRecords(), HDMX_NUM_RECORDS); + EXPECT_EQ(hdmx_table->RecordSize(), HDMX_RECORD_SIZE); + + for (int32_t i = 0; i < HDMX_NUM_RECORDS; ++i) { + EXPECT_EQ(hdmx_table->PixelSize(i), HDMX_PIXEL_SIZE[i]); + EXPECT_EQ(hdmx_table->MaxWidth(i), HDMX_MAX_WIDTH[i]); + } + + EXPECT_EQ(hdmx_table->Width(0, 0), HDMX_MAX_WIDTH[0]); + EXPECT_EQ(hdmx_table->Width(0, 19), HDMX_MAX_WIDTH[0]); + EXPECT_EQ(hdmx_table->Width(0, 623), HDMX_MAX_WIDTH[0]); + EXPECT_EQ(hdmx_table->Width(1, 0), HDMX_MAX_WIDTH[1]); + EXPECT_EQ(hdmx_table->Width(1, 19), HDMX_MAX_WIDTH[1]); + EXPECT_EQ(hdmx_table->Width(1, 623), HDMX_MAX_WIDTH[1]); + EXPECT_EQ(hdmx_table->Width(2, 0), HDMX_MAX_WIDTH[2]); + EXPECT_EQ(hdmx_table->Width(2, 19), HDMX_MAX_WIDTH[2]); + EXPECT_EQ(hdmx_table->Width(2, 623), HDMX_MAX_WIDTH[2]); + EXPECT_EQ(hdmx_table->Width(3, 0), HDMX_MAX_WIDTH[3]); + EXPECT_EQ(hdmx_table->Width(3, 19), HDMX_MAX_WIDTH[3]); + EXPECT_EQ(hdmx_table->Width(3, 623), HDMX_MAX_WIDTH[3]); + +#if defined(SFNTLY_NO_EXCEPTION) + EXPECT_EQ(hdmx_table->PixelSize(4), -1); + EXPECT_EQ(hdmx_table->PixelSize(-1), -1); + EXPECT_EQ(hdmx_table->MaxWidth(4), -1); + EXPECT_EQ(hdmx_table->MaxWidth(-1), -1); + EXPECT_EQ(hdmx_table->Width(0, 624), -1); + EXPECT_EQ(hdmx_table->Width(1, -1), -1); + EXPECT_EQ(hdmx_table->Width(-1, 0), -1); + EXPECT_EQ(hdmx_table->Width(-1, -1), -1); +#endif + return true; +} + +} // namespace sfntly + +TEST(HdmxTable, All) { + ASSERT_TRUE(sfntly::TestReadingHdmxTable()); +} diff --git a/gfx/sfntly/cpp/src/test/lock_test.cc b/gfx/sfntly/cpp/src/test/lock_test.cc new file mode 100644 index 0000000000..b29a4bf7ab --- /dev/null +++ b/gfx/sfntly/cpp/src/test/lock_test.cc @@ -0,0 +1,244 @@ +/* + * 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 <stdlib.h> + +#include "gtest/gtest.h" +#include "sfntly/port/lock.h" +#include "test/platform_thread.h" + +namespace sfntly { + +// Basic test to make sure that Acquire()/Unlock()/Try() don't crash + +class BasicLockTestThread : public PlatformThread::Delegate { + public: + BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {} + + virtual void ThreadMain() { + for (int i = 0; i < 10; i++) { + lock_->Acquire(); + acquired_++; + lock_->Unlock(); + } + for (int i = 0; i < 10; i++) { + lock_->Acquire(); + acquired_++; + PlatformThread::Sleep(rand() % 20); + lock_->Unlock(); + } + for (int i = 0; i < 10; i++) { + if (lock_->Try()) { + acquired_++; + PlatformThread::Sleep(rand() % 20); + lock_->Unlock(); + } + } + } + + int acquired() const { return acquired_; } + + private: + Lock* lock_; + int acquired_; + + NO_COPY_AND_ASSIGN(BasicLockTestThread); +}; + +bool BasicLockTest() { + Lock lock; + BasicLockTestThread thread(&lock); + PlatformThreadHandle handle = kNullThreadHandle; + + EXPECT_TRUE(PlatformThread::Create(&thread, &handle)); + + int acquired = 0; + for (int i = 0; i < 5; i++) { + lock.Acquire(); + acquired++; + lock.Unlock(); + } + for (int i = 0; i < 10; i++) { + lock.Acquire(); + acquired++; + PlatformThread::Sleep(rand() % 20); + lock.Unlock(); + } + for (int i = 0; i < 10; i++) { + if (lock.Try()) { + acquired++; + PlatformThread::Sleep(rand() % 20); + lock.Unlock(); + } + } + for (int i = 0; i < 5; i++) { + lock.Acquire(); + acquired++; + PlatformThread::Sleep(rand() % 20); + lock.Unlock(); + } + + PlatformThread::Join(handle); + + EXPECT_GE(acquired, 20); + EXPECT_GE(thread.acquired(), 20); + + return true; +} + +// Test that Try() works as expected ------------------------------------------- + +class TryLockTestThread : public PlatformThread::Delegate { + public: + TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {} + + virtual void ThreadMain() { + got_lock_ = lock_->Try(); + if (got_lock_) + lock_->Unlock(); + } + + bool got_lock() const { return got_lock_; } + + private: + Lock* lock_; + bool got_lock_; + + NO_COPY_AND_ASSIGN(TryLockTestThread); +}; + +bool TryLockTest() { + Lock lock; + + EXPECT_TRUE(lock.Try()); + // We now have the lock.... + + // This thread will not be able to get the lock. + { + TryLockTestThread thread(&lock); + PlatformThreadHandle handle = kNullThreadHandle; + + EXPECT_TRUE(PlatformThread::Create(&thread, &handle)); + + PlatformThread::Join(handle); + + EXPECT_FALSE(thread.got_lock()); + } + + lock.Unlock(); + + // This thread will.... + { + TryLockTestThread thread(&lock); + PlatformThreadHandle handle = kNullThreadHandle; + + EXPECT_TRUE(PlatformThread::Create(&thread, &handle)); + + PlatformThread::Join(handle); + + EXPECT_TRUE(thread.got_lock()); + // But it released it.... + EXPECT_TRUE(lock.Try()); + } + + lock.Unlock(); + return true; +} + +// Tests that locks actually exclude ------------------------------------------- + +class MutexLockTestThread : public PlatformThread::Delegate { + public: + MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {} + + // Static helper which can also be called from the main thread. + static void DoStuff(Lock* lock, int* value) { + for (int i = 0; i < 40; i++) { + lock->Acquire(); + int v = *value; + PlatformThread::Sleep(rand() % 10); + *value = v + 1; + lock->Unlock(); + } + } + + virtual void ThreadMain() { + DoStuff(lock_, value_); + } + + private: + Lock* lock_; + int* value_; + + NO_COPY_AND_ASSIGN(MutexLockTestThread); +}; + +bool MutexTwoThreads() { + Lock lock; + int value = 0; + + MutexLockTestThread thread(&lock, &value); + PlatformThreadHandle handle = kNullThreadHandle; + + EXPECT_TRUE(PlatformThread::Create(&thread, &handle)); + + MutexLockTestThread::DoStuff(&lock, &value); + + PlatformThread::Join(handle); + + EXPECT_EQ(2 * 40, value); + return true; +} + +bool MutexFourThreads() { + Lock lock; + int value = 0; + + MutexLockTestThread thread1(&lock, &value); + MutexLockTestThread thread2(&lock, &value); + MutexLockTestThread thread3(&lock, &value); + PlatformThreadHandle handle1 = kNullThreadHandle; + PlatformThreadHandle handle2 = kNullThreadHandle; + PlatformThreadHandle handle3 = kNullThreadHandle; + + EXPECT_TRUE(PlatformThread::Create(&thread1, &handle1)); + EXPECT_TRUE(PlatformThread::Create(&thread2, &handle2)); + EXPECT_TRUE(PlatformThread::Create(&thread3, &handle3)); + + MutexLockTestThread::DoStuff(&lock, &value); + + PlatformThread::Join(handle1); + PlatformThread::Join(handle2); + PlatformThread::Join(handle3); + + EXPECT_EQ(4 * 40, value); + return true; +} + +} // namespace sfntly + +TEST(LockTest, Basic) { + ASSERT_TRUE(sfntly::BasicLockTest()); +} + +TEST(LockTest, TryLock) { + ASSERT_TRUE(sfntly::TryLockTest()); +} + +TEST(LockTest, Mutex) { + ASSERT_TRUE(sfntly::MutexTwoThreads()); + ASSERT_TRUE(sfntly::MutexFourThreads()); +} diff --git a/gfx/sfntly/cpp/src/test/memory_io_test.cc b/gfx/sfntly/cpp/src/test/memory_io_test.cc new file mode 100755 index 0000000000..b34e1e74f9 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/memory_io_test.cc @@ -0,0 +1,102 @@ +/* + * 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 <stdio.h> + +#include <algorithm> + +#include "gtest/gtest.h" +#include "sfntly/port/memory_input_stream.h" +#include "sfntly/port/memory_output_stream.h" +#include "sfntly/port/type.h" + +namespace { + const char* kTestData = +"01234567890123456789012345678901234567890123456789" // 50 +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx" // 100 +"yz"; // 102 + const size_t kTestBufferLen = 102; +} + +namespace sfntly { + +bool TestMemoryInputStream() { + ByteVector test_buffer; + test_buffer.resize(kTestBufferLen); + std::copy(kTestData, kTestData + kTestBufferLen, test_buffer.begin()); + + MemoryInputStream is; + is.Attach(&(test_buffer[0]), kTestBufferLen); + EXPECT_EQ(is.Available(), (int32_t)kTestBufferLen); + + // Read one byte + EXPECT_EQ(is.Read(), '0'); // position 1 + EXPECT_EQ(is.Read(), '1'); // position 2 + EXPECT_EQ(is.Read(), '2'); // position 3 + + // Read byte vector + ByteVector b; + b.resize(7); + EXPECT_EQ(is.Read(&b), 7); // position 10 + EXPECT_EQ(memcmp(&(b[0]), &(test_buffer[0]) + 3, 7), 0); + + b.resize(17); + EXPECT_EQ(is.Read(&b, 7, 10), 10); // position 20 + EXPECT_EQ(memcmp(&(b[0]), &(test_buffer[0]) + 3, 17), 0); + + // Test skip + b.clear(); + b.resize(10); + EXPECT_EQ(is.Skip(30), 30); // position 50 + EXPECT_EQ(is.Read(&b), 10); // position 60 + EXPECT_EQ(memcmp(&(b[0]), &(test_buffer[0]) + 50, 10), 0); + b.clear(); + b.resize(10); + EXPECT_EQ(is.Skip(-20), -20); // position 40 + EXPECT_EQ(is.Read(&b), 10); // position 50 + EXPECT_EQ(memcmp(&(b[0]), &(test_buffer[0]) + 40, 10), 0); + + EXPECT_EQ(is.Available(), (int32_t)kTestBufferLen - 50); + EXPECT_EQ(is.Skip(-60), -50); // Out of bound, position 0 + EXPECT_EQ(is.Skip(kTestBufferLen + 10), (int32_t)kTestBufferLen); + + b.clear(); + b.resize(10); + is.Unread(&b); + EXPECT_EQ(memcmp(&(b[0]), &(test_buffer[0]) + kTestBufferLen - 10, 10), 0); + + return true; +} + +bool TestMemoryOutputStream() { + ByteVector test_buffer; + test_buffer.resize(kTestBufferLen); + std::copy(kTestData, kTestData + kTestBufferLen, test_buffer.begin()); + + MemoryOutputStream os; + os.Write(&(test_buffer[0]), (int32_t)50, (int32_t)(kTestBufferLen - 50)); + EXPECT_EQ(os.Size(), kTestBufferLen - 50); + EXPECT_EQ(memcmp(os.Get(), &(test_buffer[0]) + 50, kTestBufferLen - 50), 0); + + return true; +} + +} // namespace sfntly + +TEST(MemoryIO, All) { + ASSERT_TRUE(sfntly::TestMemoryInputStream()); + ASSERT_TRUE(sfntly::TestMemoryOutputStream()); +} diff --git a/gfx/sfntly/cpp/src/test/name_editing_test.cc b/gfx/sfntly/cpp/src/test/name_editing_test.cc new file mode 100644 index 0000000000..260d9d4ae1 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/name_editing_test.cc @@ -0,0 +1,242 @@ +/* + * 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. + */ + +// Must include this before ICU to avoid stdint redefinition issue. +#include "sfntly/port/type.h" + +#include <unicode/ustring.h> +#include <unicode/unistr.h> + +#include "gtest/gtest.h" +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/port/memory_input_stream.h" +#include "sfntly/port/memory_output_stream.h" +#include "sfntly/table/core/name_table.h" +#include "sfntly/tag.h" +#include "test/test_data.h" +#include "test/test_font_utils.h" + +namespace sfntly { + +static ByteVector input_buffer; + +void LoadTestFile(FontFactory* factory, FontBuilderArray* font_builders) { + assert(factory); + assert(font_builders); + if (input_buffer.empty()) { + LoadFile(SAMPLE_TTF_FILE, &input_buffer); + } + factory->LoadFontsForBuilding(&input_buffer, font_builders); +} + +bool TestChangeOneName() { + FontFactoryPtr factory; + factory.Attach(FontFactory::GetInstance()); + FontBuilderArray font_builder_array; + LoadTestFile(factory, &font_builder_array); + FontBuilderPtr font_builder = font_builder_array[0]; + + NameTableBuilderPtr name_builder = down_cast<NameTable::Builder*>( + font_builder->GetTableBuilder(Tag::name)); + + // Change the font name. + NameEntryBuilderPtr neb = + name_builder->NameBuilder(PlatformId::kWindows, + WindowsEncodingId::kUnicodeUCS2, + WindowsLanguageId::kEnglish_UnitedStates, + NameId::kFontFamilyName); + U_STRING_DECL(new_name, "Timothy", 7); + neb->SetName(new_name); + + // Build the font. + FontPtr font; + font.Attach(font_builder->Build()); + + // Serialize and reload the serialized font. + MemoryOutputStream os; + factory->SerializeFont(font, &os); + MemoryInputStream is; + is.Attach(os.Get(), os.Size()); + FontArray font_array; + factory->LoadFonts(&is, &font_array); + FontPtr new_font = font_array[0]; + + // Check the font name. + NameTablePtr name_table = down_cast<NameTable*>(font->GetTable(Tag::name)); + UChar* name = name_table->Name(PlatformId::kWindows, + WindowsEncodingId::kUnicodeUCS2, + WindowsLanguageId::kEnglish_UnitedStates, + NameId::kFontFamilyName); + EXPECT_TRUE(name != NULL); + EXPECT_EQ(u_strcmp(name, new_name), 0); + delete[] name; + return true; +} + +bool TestModifyNameTableAndRevert() { + FontFactoryPtr factory; + factory.Attach(FontFactory::GetInstance()); + FontBuilderArray font_builder_array; + LoadTestFile(factory, &font_builder_array); + FontBuilderPtr font_builder = font_builder_array[0]; + + NameTableBuilderPtr name_builder = down_cast<NameTable::Builder*>( + font_builder->GetTableBuilder(Tag::name)); + + // Change the font name. + NameEntryBuilderPtr neb = + name_builder->NameBuilder(PlatformId::kWindows, + WindowsEncodingId::kUnicodeUCS2, + WindowsLanguageId::kEnglish_UnitedStates, + NameId::kFontFamilyName); + NameTable::NameEntry* neb_entry = neb->name_entry(); + UChar* original_name = neb_entry->Name(); + EXPECT_TRUE(original_name != NULL); + + U_STRING_DECL(new_name, "Timothy", 7); + neb->SetName(new_name); + name_builder->RevertNames(); + + // Build the font. + FontPtr font; + font.Attach(font_builder->Build()); + + // Serialize and reload the serialized font. + MemoryOutputStream os; + factory->SerializeFont(font, &os); + MemoryInputStream is; + is.Attach(os.Get(), os.Size()); + FontArray font_array; + factory->LoadFonts(&is, &font_array); + FontPtr new_font = font_array[0]; + + // Check the font name. + NameTablePtr name_table = down_cast<NameTable*>(font->GetTable(Tag::name)); + UChar* name = name_table->Name(PlatformId::kWindows, + WindowsEncodingId::kUnicodeUCS2, + WindowsLanguageId::kEnglish_UnitedStates, + NameId::kFontFamilyName); + + EXPECT_EQ(u_strcmp(name, original_name), 0); + delete[] name; + delete[] original_name; + + return true; +} + +bool TestRemoveOneName() { + FontFactoryPtr factory; + factory.Attach(FontFactory::GetInstance()); + FontBuilderArray font_builder_array; + LoadTestFile(factory, &font_builder_array); + FontBuilderPtr font_builder = font_builder_array[0]; + + NameTableBuilderPtr name_builder = down_cast<NameTable::Builder*>( + font_builder->GetTableBuilder(Tag::name)); + + EXPECT_TRUE(name_builder->Has(PlatformId::kWindows, + WindowsEncodingId::kUnicodeUCS2, + WindowsLanguageId::kEnglish_UnitedStates, + NameId::kFontFamilyName)); + EXPECT_TRUE(name_builder->Remove(PlatformId::kWindows, + WindowsEncodingId::kUnicodeUCS2, + WindowsLanguageId::kEnglish_UnitedStates, + NameId::kFontFamilyName)); + + // Build the font. + FontPtr font; + font.Attach(font_builder->Build()); + + // Serialize and reload the serialized font. + MemoryOutputStream os; + factory->SerializeFont(font, &os); + MemoryInputStream is; + is.Attach(os.Get(), os.Size()); + FontArray font_array; + factory->LoadFonts(&is, &font_array); + FontPtr new_font = font_array[0]; + + // Check the font name. + NameTablePtr name_table = down_cast<NameTable*>(font->GetTable(Tag::name)); + UChar* name = name_table->Name(PlatformId::kWindows, + WindowsEncodingId::kUnicodeUCS2, + WindowsLanguageId::kEnglish_UnitedStates, + NameId::kFontFamilyName); + EXPECT_TRUE(name == NULL); + + return true; +} + +// Note: Function is not implemented but the test case is built. Uncomment +// when NameTable::clear() is implemented. +/* +bool TestClearAllNamesAndSetOne() { + FontFactoryPtr factory; + factory.Attach(FontFactory::GetInstance()); + FontBuilderArray font_builder_array; + LoadTestFile(factory, &font_builder_array); + FontBuilderPtr font_builder = font_builder_array[0]; + + NameTableBuilderPtr name_builder = down_cast<NameTable::Builder*>( + font_builder->GetTableBuilder(Tag::name)); + + EXPECT_GT(name_builder->builderCount(), 0); + name_builder->clear(); + EXPECT_EQ(name_builder->builderCount(), 0); + + // Change the font name. + NameEntryBuilderPtr neb = + name_builder->NameBuilder(PlatformId::kWindows, + WindowsEncodingId::kUnicodeUCS2, + WindowsLanguageId::kEnglish_UnitedStates, + NameId::kFontFamilyName); + U_STRING_DECL(new_name, "Fred", 4); + neb->SetName(new_name); + + // Build the font. + FontPtr font = font_builder->Build(); + + // Serialize and reload the serialized font. + MemoryOutputStream os; + factory->SerializeFont(font, &os); + FontArray font_array; + ByteArrayPtr new_ba = new MemoryByteArray(os.Get(), os.Size()); + factory->LoadFonts(new_ba, &font_array); + FontPtr new_font = font_array[0]; + + // Check the font name. + NameTablePtr name_table = down_cast<NameTable*>(font->table(Tag::name)); + UChar* name = name_table->Name(PlatformId::kWindows, + WindowsEncodingId::kUnicodeUCS2, + WindowsLanguageId::kEnglish_UnitedStates, + NameId::kFontFamilyName); + EXPECT_EQ(name_table->NameCount(), 1); + EXPECT_EQ(u_strcmp(name, new_name), 0); + + delete[] name; + return true; +} +*/ + +} // namespace sfntly + +TEST(NameEditing, All) { + EXPECT_TRUE(sfntly::TestChangeOneName()); + EXPECT_TRUE(sfntly::TestModifyNameTableAndRevert()); + EXPECT_TRUE(sfntly::TestRemoveOneName()); +} diff --git a/gfx/sfntly/cpp/src/test/open_type_data_test.cc b/gfx/sfntly/cpp/src/test/open_type_data_test.cc new file mode 100644 index 0000000000..5d73e84d9a --- /dev/null +++ b/gfx/sfntly/cpp/src/test/open_type_data_test.cc @@ -0,0 +1,70 @@ +/* + * 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 "gtest/gtest.h" +#include "sfntly/data/writable_font_data.h" +#include "sfntly/data/memory_byte_array.h" + +namespace sfntly { + +const uint8_t TEST_OTF_DATA[] = + {0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + +bool TestOTFRead() { + ByteVector bytes; + for (size_t i = 0; i < sizeof(TEST_OTF_DATA) / sizeof(uint8_t); ++i) { + bytes.push_back(TEST_OTF_DATA[i]); + } + ByteArrayPtr array = new MemoryByteArray(&(bytes[0]), bytes.size()); + ReadableFontDataPtr data = new ReadableFontData(array); + + EXPECT_EQ(-1, data->ReadByte(0)); + EXPECT_EQ(0xff, data->ReadUByte(0)); + EXPECT_EQ(0x01, data->ReadByte(1)); + EXPECT_EQ(65281, data->ReadUShort(0)); + EXPECT_EQ(-255, data->ReadShort(0)); + EXPECT_EQ(16711937, data->ReadUInt24(0)); + EXPECT_EQ(4278255873LL, data->ReadULong(0)); + EXPECT_EQ(-16711423, data->ReadLong(0)); + return true; +} + +bool TestOTFCopy() { + ByteVector source_bytes(1024); + for (size_t i = 0; i < source_bytes.size(); ++i) { + source_bytes[i] = (uint8_t)(i & 0xff); + } + ByteArrayPtr source_array = new MemoryByteArray(&(source_bytes[0]), 1024); + ReadableFontDataPtr source = new ReadableFontData(source_array); + + ByteVector destination_bytes(1024); + ByteArrayPtr destination_array = + new MemoryByteArray(&(destination_bytes[0]), 1024); + WritableFontDataPtr destination = new WritableFontData(destination_array); + + int32_t length = source->CopyTo(destination); + EXPECT_EQ(1024, length); + EXPECT_TRUE(std::equal(source_bytes.begin(), source_bytes.end(), + destination_bytes.begin())); + return true; +} + +} // namespace sfntly + +TEST(OpenTypeData, All) { + ASSERT_TRUE(sfntly::TestOTFRead()); + ASSERT_TRUE(sfntly::TestOTFCopy()); +} diff --git a/gfx/sfntly/cpp/src/test/otf_basic_editing_test.cc b/gfx/sfntly/cpp/src/test/otf_basic_editing_test.cc new file mode 100644 index 0000000000..04c8778c25 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/otf_basic_editing_test.cc @@ -0,0 +1,101 @@ +/* + * 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 "gtest/gtest.h" +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/table/core/font_header_table.h" +#include "sfntly/tag.h" +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/port/endian.h" +#include "sfntly/port/file_input_stream.h" +#include "sfntly/port/memory_output_stream.h" +#include "test/test_data.h" +#include "test/test_font_utils.h" + +namespace sfntly { + +bool TestOTFBasicEditing() { + FontFactoryPtr factory; + factory.Attach(FontFactory::GetInstance()); + FontBuilderArray font_builder_array; + BuilderForFontFile(SAMPLE_TTF_FILE, factory, &font_builder_array); + if (font_builder_array.size() != 1) { + EXPECT_TRUE(false); + return false; + } + FontBuilderPtr font_builder = font_builder_array[0]; + + // ensure the builder is not bogus + if (!font_builder) { + EXPECT_TRUE(false); + return false; + } + TableBuilderMap* builder_map = font_builder->table_builders(); + if (!builder_map) { + EXPECT_TRUE(false); + return false; + } + IntegerSet builder_tags; + for (TableBuilderMap::iterator i = builder_map->begin(), + e = builder_map->end(); i != e; ++i) { + if (!i->second) { + EXPECT_TRUE(false); + char tag[5] = {0}; + int32_t value = ToBE32(i->first); + memcpy(tag, &value, 4); + fprintf(stderr, "tag %s does not have valid builder\n", tag); + continue; + } + builder_tags.insert(i->first); + } + + FontHeaderTableBuilderPtr header_builder = + down_cast<FontHeaderTable::Builder*>( + font_builder->GetTableBuilder(Tag::head)); + int64_t mod_date = header_builder->Modified(); + EXPECT_EQ(3397043097, mod_date); + header_builder->SetModified(mod_date + 1); + FontPtr font; + font.Attach(font_builder->Build()); + + // ensure every table had a builder + const TableMap* table_map = font->GetTableMap(); + for (TableMap::const_iterator i = table_map->begin(), e = table_map->end(); + i != e; ++i) { + TablePtr table = i->second; + HeaderPtr header = table->header(); + size_t erased = builder_tags.erase(header->tag()); + EXPECT_EQ(1U, erased); + } + EXPECT_TRUE(builder_tags.empty()); + + FontHeaderTablePtr header = + down_cast<FontHeaderTable*>(font->GetTable(Tag::head)); + int64_t after_mod_date = header->Modified(); + EXPECT_EQ(mod_date + 1, after_mod_date); + + // Checksum correctness of builder. + TablePtr post = font->GetTable(Tag::post); + EXPECT_EQ(TTF_CHECKSUM[SAMPLE_TTF_POST], post->CalculatedChecksum()); + return true; +} + +} // namespace sfntly + +TEST(OTFBasicEditing, All) { + ASSERT_TRUE(sfntly::TestOTFBasicEditing()); +} diff --git a/gfx/sfntly/cpp/src/test/platform_thread.cc b/gfx/sfntly/cpp/src/test/platform_thread.cc new file mode 100644 index 0000000000..6a0b84b4a7 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/platform_thread.cc @@ -0,0 +1,101 @@ +/* + * 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 "test/platform_thread.h" + +namespace sfntly { + +#if defined (WIN32) + +DWORD __stdcall ThreadFunc(void* params) { + PlatformThread::Delegate* delegate = + static_cast<PlatformThread::Delegate*>(params); + delegate->ThreadMain(); + return 0; +} + +// static +bool PlatformThread::Create(Delegate* delegate, + PlatformThreadHandle* thread_handle) { + assert(thread_handle); + *thread_handle = CreateThread(NULL, 0, ThreadFunc, delegate, 0, NULL); + if (!(*thread_handle)) { + return false; + } + + return true; +} + +// static +void PlatformThread::Join(PlatformThreadHandle thread_handle) { + assert(thread_handle); + DWORD result = WaitForSingleObject(thread_handle, INFINITE); + assert(result == WAIT_OBJECT_0); + CloseHandle(thread_handle); +} + +// static +void PlatformThread::Sleep(int32_t duration_ms) { + ::Sleep(duration_ms); +} + +#else + +void* ThreadFunc(void* params) { + PlatformThread::Delegate* delegate = + static_cast<PlatformThread::Delegate*>(params); + delegate->ThreadMain(); + return NULL; +} + +// static +bool PlatformThread::Create(Delegate* delegate, + PlatformThreadHandle* thread_handle) { + assert(thread_handle); + + bool success = false; + pthread_attr_t attributes; + pthread_attr_init(&attributes); + success = !pthread_create(thread_handle, &attributes, ThreadFunc, delegate); + pthread_attr_destroy(&attributes); + + return success; +} + +// static +void PlatformThread::Join(PlatformThreadHandle thread_handle) { + assert(thread_handle); + pthread_join(thread_handle, NULL); +} + +// static +void PlatformThread::Sleep(int32_t duration_ms) { + struct timespec sleep_time, remaining; + + // Contains the portion of duration_ms >= 1 sec. + sleep_time.tv_sec = duration_ms / 1000; + duration_ms -= sleep_time.tv_sec * 1000; + + // Contains the portion of duration_ms < 1 sec. + sleep_time.tv_nsec = duration_ms * 1000 * 1000; // nanoseconds. + + while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR) + sleep_time = remaining; +} + +#endif // WIN32 + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/test/platform_thread.h b/gfx/sfntly/cpp/src/test/platform_thread.h new file mode 100644 index 0000000000..f236f4cdf3 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/platform_thread.h @@ -0,0 +1,75 @@ +/* + * 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. + */ + +// Simple platform thread implementation used to test our cross-platform locks. +// This is a trimmed down version of Chromium base/threading/platform_thread.h. + +#ifndef SFNTLY_CPP_SRC_TEST_PLATFORM_THREAD_H_ +#define SFNTLY_CPP_SRC_TEST_PLATFORM_THREAD_H_ + +#if defined (WIN32) +#include <windows.h> +#else // Assume pthread +#include <errno.h> +#include <pthread.h> +#include <time.h> +#endif // if defined (WIN32) + +#include "sfntly/port/type.h" + +namespace sfntly { + +#if defined (WIN32) +typedef HANDLE PlatformThreadHandle; +const PlatformThreadHandle kNullThreadHandle = NULL; +#else // Assume pthread +typedef pthread_t PlatformThreadHandle; +const PlatformThreadHandle kNullThreadHandle = 0; +#endif + +class PlatformThread { + public: + class Delegate { + public: + virtual ~Delegate() {} + virtual void ThreadMain() = 0; + }; + + // Sleeps for the specified duration (units are milliseconds). + static void Sleep(int32_t duration_ms); + + // Creates a new thread using default stack size. Upon success, + // |*thread_handle| will be assigned a handle to the newly created thread, + // and |delegate|'s ThreadMain method will be executed on the newly created + // thread. + // NOTE: When you are done with the thread handle, you must call Join to + // release system resources associated with the thread. You must ensure that + // the Delegate object outlives the thread. + static bool Create(Delegate* delegate, PlatformThreadHandle* thread_handle); + + // Joins with a thread created via the Create function. This function blocks + // the caller until the designated thread exits. This will invalidate + // |thread_handle|. + static void Join(PlatformThreadHandle thread_handle); + +private: + PlatformThread() {} + NO_COPY_AND_ASSIGN(PlatformThread); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_TEST_PLATFORM_THREAD_H_ diff --git a/gfx/sfntly/cpp/src/test/serialization_test.cc b/gfx/sfntly/cpp/src/test/serialization_test.cc new file mode 100755 index 0000000000..0f2f489f4b --- /dev/null +++ b/gfx/sfntly/cpp/src/test/serialization_test.cc @@ -0,0 +1,151 @@ +/* + * 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 "gtest/gtest.h" +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/port/memory_input_stream.h" +#include "sfntly/port/memory_output_stream.h" +#include "test/test_data.h" +#include "test/test_font_utils.h" +#include "test/serialization_test.h" + +namespace sfntly { + +bool TestSerialization() { + FontFactoryPtr factory1, factory2, factory3; + factory1.Attach(FontFactory::GetInstance()); + FontArray font_array; + LoadFont(SAMPLE_TTF_FILE, factory1, &font_array); + FontPtr original = font_array[0]; + + factory2.Attach(FontFactory::GetInstance()); + FontBuilderArray font_builder_array; + BuilderForFontFile(SAMPLE_TTF_FILE, factory2, &font_builder_array); + FontBuilderPtr font_builder = font_builder_array[0]; + + FontPtr intermediate; + intermediate.Attach(font_builder->Build()); + MemoryOutputStream os; + factory2->SerializeFont(intermediate, &os); + + factory3.Attach(FontFactory::GetInstance()); + FontArray new_font_array; + MemoryInputStream is; + is.Attach(os.Get(), os.Size()); + factory3->LoadFonts(&is, &new_font_array); + FontPtr serialized = new_font_array[0]; + + // Check number of tables + EXPECT_EQ(original->num_tables(), serialized->num_tables()); + + // Check if same set of tables + const TableMap* original_tables = original->GetTableMap(); + const TableMap* serialized_tables = serialized->GetTableMap(); + EXPECT_EQ(original_tables->size(), serialized_tables->size()); + TableMap::const_iterator not_found = serialized_tables->end(); + for (TableMap::const_iterator b = original_tables->begin(), + e = original_tables->end(); b != e; ++b) { + EXPECT_TRUE((serialized_tables->find(b->first) != not_found)); + } + + // TODO(arthurhsu): check cmap equivalence + // Check checksum equivalence + for (size_t i = 0; i < SAMPLE_TTF_KNOWN_TAGS; ++i) { + TablePtr original_table = original->GetTable(TTF_KNOWN_TAGS[i]); + TablePtr serialized_table = serialized->GetTable(TTF_KNOWN_TAGS[i]); + EXPECT_EQ(original_table->CalculatedChecksum(), + serialized_table->CalculatedChecksum()); + EXPECT_EQ(original_table->DataLength(), serialized_table->DataLength()); + + if (TTF_KNOWN_TAGS[i] == Tag::hhea) { + EXPECT_TRUE(VerifyHHEA(original_table, serialized_table)); + } else if (TTF_KNOWN_TAGS[i] == Tag::glyf) { + EXPECT_TRUE(VerifyGLYF(original_table, serialized_table)); + } else if (TTF_KNOWN_TAGS[i] == Tag::hmtx) { + EXPECT_TRUE(VerifyHMTX(original_table, serialized_table)); + } else if (TTF_KNOWN_TAGS[i] == Tag::loca) { + EXPECT_TRUE(VerifyLOCA(original_table, serialized_table)); + } else if (TTF_KNOWN_TAGS[i] == Tag::maxp) { + EXPECT_TRUE(VerifyMAXP(original_table, serialized_table)); + } else if (TTF_KNOWN_TAGS[i] == Tag::name) { + EXPECT_TRUE(VerifyNAME(original_table, serialized_table)); + } else if (TTF_KNOWN_TAGS[i] == Tag::OS_2) { + EXPECT_TRUE(VerifyOS_2(original_table, serialized_table)); + } + } + + return true; +} + +bool TestSerializationBitmap() { + FontFactoryPtr factory1, factory2, factory3; + factory1.Attach(FontFactory::GetInstance()); + FontArray font_array; + LoadFont(SAMPLE_BITMAP_FONT, factory1, &font_array); + FontPtr original = font_array[0]; + + factory2.Attach(FontFactory::GetInstance()); + FontBuilderArray font_builder_array; + BuilderForFontFile(SAMPLE_BITMAP_FONT, factory2, &font_builder_array); + FontBuilderPtr font_builder = font_builder_array[0]; + + FontPtr intermediate; + intermediate.Attach(font_builder->Build()); + MemoryOutputStream os; + factory2->SerializeFont(intermediate, &os); + + factory3.Attach(FontFactory::GetInstance()); + FontArray new_font_array; + MemoryInputStream is; + is.Attach(os.Get(), os.Size()); + factory3->LoadFonts(&is, &new_font_array); + FontPtr serialized = new_font_array[0]; + + // Check number of tables + EXPECT_EQ(original->num_tables(), serialized->num_tables()); + + // Check if same set of tables + const TableMap* original_tables = original->GetTableMap(); + const TableMap* serialized_tables = serialized->GetTableMap(); + EXPECT_EQ(original_tables->size(), serialized_tables->size()); + TableMap::const_iterator not_found = serialized_tables->end(); + for (TableMap::const_iterator b = original_tables->begin(), + e = original_tables->end(); b != e; ++b) { + EXPECT_TRUE((serialized_tables->find(b->first) != not_found)); + } + + // Check checksum equivalence + for (size_t i = 0; i < SAMPLE_BITMAP_KNOWN_TAGS; ++i) { + TablePtr original_table = original->GetTable(BITMAP_KNOWN_TAGS[i]); + TablePtr serialized_table = serialized->GetTable(BITMAP_KNOWN_TAGS[i]); + EXPECT_EQ(original_table->CalculatedChecksum(), + serialized_table->CalculatedChecksum()); + EXPECT_EQ(original_table->DataLength(), serialized_table->DataLength()); + } + + return true; +} + +} // namespace sfntly + +TEST(Serialization, Simple) { + ASSERT_TRUE(sfntly::TestSerialization()); +} + +TEST(Serialization, Bitmap) { + ASSERT_TRUE(sfntly::TestSerializationBitmap()); +} diff --git a/gfx/sfntly/cpp/src/test/serialization_test.h b/gfx/sfntly/cpp/src/test/serialization_test.h new file mode 100644 index 0000000000..8996793585 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/serialization_test.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_TEST_SERIALIZATION_TEST_H_ +#define SFNTLY_CPP_SRC_TEST_SERIALIZATION_TEST_H_ + +#include "sfntly/table/table.h" + +namespace sfntly { + +bool VerifyHHEA(Table* original, Table* target); +bool VerifyGLYF(Table* original, Table* target); +bool VerifyHMTX(Table* original, Table* target); +bool VerifyLOCA(Table* original, Table* target); +bool VerifyMAXP(Table* original, Table* target); +bool VerifyNAME(Table* original, Table* target); +bool VerifyOS_2(Table* original, Table* target); + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_TEST_SERIALIZATION_TEST_H_ diff --git a/gfx/sfntly/cpp/src/test/smart_pointer_test.cc b/gfx/sfntly/cpp/src/test/smart_pointer_test.cc new file mode 100644 index 0000000000..9e81baaba6 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/smart_pointer_test.cc @@ -0,0 +1,79 @@ +/* + * 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 "gtest/gtest.h" +#define ENABLE_OBJECT_COUNTER +#include "sfntly/port/refcount.h" + +using sfntly::RefCounted; +using sfntly::Ptr; + +class Foo : public RefCounted<Foo> { +public: // put in something to make sure it's not empty + int foo_; + int foo() { return foo_; } +}; + +bool TestSmartPointer() { + // scope out allocation + { + Ptr<Foo> p1; + p1 = new Foo(); + EXPECT_EQ(size_t(1), p1->ref_count_); + EXPECT_EQ(size_t(1), RefCounted<Foo>::object_counter_); + + Ptr<Foo> p2; + p2 = p1; + EXPECT_EQ(size_t(2), p1->ref_count_); + EXPECT_EQ(size_t(2), p2->ref_count_); + EXPECT_EQ(size_t(1), RefCounted<Foo>::object_counter_); + + Ptr<Foo> p3; + p3 = p1; + EXPECT_EQ(size_t(3), p1->ref_count_); + EXPECT_EQ(size_t(3), p2->ref_count_); + EXPECT_EQ(size_t(3), p3->ref_count_); + EXPECT_EQ(size_t(1), RefCounted<Foo>::object_counter_); + + p2 = new Foo(); + EXPECT_EQ(size_t(2), p1->ref_count_); + EXPECT_EQ(size_t(1), p2->ref_count_); + EXPECT_EQ(size_t(2), p3->ref_count_); + EXPECT_EQ(size_t(2), RefCounted<Foo>::object_counter_); + + p3.Release(); + EXPECT_EQ(size_t(1), p1->ref_count_); + EXPECT_EQ(NULL, p3.p_); + EXPECT_EQ(size_t(2), RefCounted<Foo>::object_counter_); + + p2 = NULL; + EXPECT_EQ(size_t(1), RefCounted<Foo>::object_counter_); + + p1 = p1; + EXPECT_EQ(size_t(1), p1->ref_count_); + EXPECT_EQ(size_t(1), RefCounted<Foo>::object_counter_); + + p1 = &(*p1); + EXPECT_EQ(size_t(1), p1->ref_count_); + EXPECT_EQ(size_t(1), RefCounted<Foo>::object_counter_); + } + EXPECT_EQ(size_t(0), RefCounted<Foo>::object_counter_); + return true; +} + +TEST(SmartPointer, All) { + ASSERT_TRUE(TestSmartPointer()); +} diff --git a/gfx/sfntly/cpp/src/test/test_data.cc b/gfx/sfntly/cpp/src/test/test_data.cc new file mode 100644 index 0000000000..05bc7595e0 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/test_data.cc @@ -0,0 +1,75 @@ +/* + * 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 "sfntly/tag.cc" +#include "test/test_data.h" + +namespace sfntly { + +// If the TTF file used in test changed, the verify*.cc in test need to be +// changed also. +// TODO(arthurhsu): Refactor this into a test class and have all const inside. +// This way we can test multiple fonts using same set of +// code. + +const char* SAMPLE_TTF_FILE = "Tuffy.ttf"; +const char* SAMPLE_BITMAP_FONT = "AnonymousPro-Regular.ttf"; + +const size_t SAMPLE_TTF_SIZE = 183936; +const size_t SAMPLE_TTF_TABLES = 17; +const size_t SAMPLE_TTF_KNOWN_TAGS = 16; +const size_t SAMPLE_BITMAP_KNOWN_TAGS = 20; +const size_t SAMPLE_TTF_FEAT = 3; +const size_t SAMPLE_TTF_HEAD = 6; +const size_t SAMPLE_TTF_POST = 14; + +const int32_t TTF_KNOWN_TAGS[] = { + Tag::OS_2, Tag::cmap, Tag::cvt, Tag::feat, Tag::gasp, + Tag::glyf, Tag::head, Tag::hhea, Tag::hmtx, Tag::kern, + Tag::loca, Tag::maxp, Tag::morx, Tag::name, Tag::post, + Tag::prop }; + +const int32_t BITMAP_KNOWN_TAGS[] = { + Tag::EBDT, Tag::EBLC, Tag::EBSC, Tag::LTSH, Tag::OS_2, + Tag::VDMX, Tag::cmap, Tag::cvt, Tag::fpgm, Tag::gasp, + Tag::glyf, Tag::hdmx, Tag::head, Tag::hhea, Tag::hmtx, + Tag::loca, Tag::maxp, Tag::name, Tag::post, Tag::prep }; + +const int64_t TTF_CHECKSUM[] = { + 0xD463FC48, 0x252028D1, 0x0065078A, 0xC01407B5, 0xFFFF0003, + 0x9544342B, 0xFC8F16AD, 0x0EC30C7A, 0xA029CD5D, 0x32513087, + 0x05C323B0, 0x06320195, 0x3B67E701, 0xE7DB08F3, 0xD46E5E89, + 0xE6EB4A27 }; + +const int64_t TTF_OFFSET[] = { + 0x00000198, 0x00001964, 0x000025B0, 0x0002CA74, 0x0002C854, + 0x00003D34, 0x0000011C, 0x00000154, 0x000001F0, 0x000245D8, + 0x000025B8, 0x00000178, 0x0002CAB4, 0x00024860, 0x00028854, + 0x0002C85C }; + +const int32_t TTF_LENGTH[] = { + 86, 3146, 8, 64, 8, + 133284, 54, 36, 6002, 648, + 6012, 32, 944, 16371, 16383, + 536 }; + +const unsigned char TTF_FEAT_DATA[] = { + 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0x30, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0x34, + 0, 0, 1, 1, 0, 0xB, 0, 2, 0, 0, 0, 0x38, 0xC0, 0, 1, 2, + 0, 0, 1, 3, 0, 2, 1, 4, 0, 0, 1, 5, 0, 2, 1, 6 }; + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/test/test_data.h b/gfx/sfntly/cpp/src/test/test_data.h new file mode 100644 index 0000000000..d5e576fa0d --- /dev/null +++ b/gfx/sfntly/cpp/src/test/test_data.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_TEST_TEST_DATA_H_ +#define SFNTLY_CPP_SRC_TEST_TEST_DATA_H_ + +#include "sfntly/tag.h" + +namespace sfntly { + +extern const char* SAMPLE_TTF_FILE; +extern const char* SAMPLE_BITMAP_FONT; + +extern const size_t SAMPLE_TTF_SIZE; +extern const size_t SAMPLE_TTF_TABLES; +extern const size_t SAMPLE_TTF_KNOWN_TAGS; +extern const size_t SAMPLE_BITMAP_KNOWN_TAGS; +extern const size_t SAMPLE_TTF_FEAT; +extern const size_t SAMPLE_TTF_HEAD; +extern const size_t SAMPLE_TTF_POST; + +extern const int32_t TTF_KNOWN_TAGS[]; +extern const int32_t BITMAP_KNOWN_TAGS[]; +extern const int64_t TTF_CHECKSUM[]; +extern const int64_t TTF_OFFSET[]; +extern const int32_t TTF_LENGTH[]; +extern const unsigned char TTF_FEAT_DATA[]; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_TEST_TEST_DATA_H_ diff --git a/gfx/sfntly/cpp/src/test/test_font_utils.cc b/gfx/sfntly/cpp/src/test/test_font_utils.cc new file mode 100644 index 0000000000..a00a811d6c --- /dev/null +++ b/gfx/sfntly/cpp/src/test/test_font_utils.cc @@ -0,0 +1,115 @@ +/* + * 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 <stdio.h> + +#include "gtest/gtest.h" +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/data/growable_memory_byte_array.h" +#include "sfntly/port/file_input_stream.h" +#include "test/test_font_utils.h" + +namespace sfntly { + +void BuilderForFontFile(const char* font_path, FontFactory* factory, + FontBuilderArray* builders) { + assert(factory); + FileInputStream is; + is.Open(font_path); + factory->LoadFontsForBuilding(&is, builders); + EXPECT_GT(builders->size(), static_cast<size_t>(0)); +} + +void SerializeFont(const char* font_path, FontFactory* factory, Font* font) { + assert(font_path); + assert(factory); + assert(font); + MemoryOutputStream output_stream; + factory->SerializeFont(font, &output_stream); + SerializeToFile(&output_stream, font_path); +} + +void LoadFont(const char* font_path, FontFactory* factory, FontArray* fonts) { + FileInputStream is; + is.Open(font_path); + factory->LoadFonts(&is, fonts); + is.Close(); +} + +void LoadFontUsingByteVector(const char* font_path, + bool fingerprint, + FontArray* fonts) { + ByteVector bv; + LoadFile(font_path, &bv); + FontFactoryPtr factory; + factory.Attach(FontFactory::GetInstance()); + factory->FingerprintFont(fingerprint); + factory->LoadFonts(&bv, fonts); +} + +void LoadFile(const char* input_file_path, ByteVector* input_buffer) { + assert(input_file_path); + assert(input_buffer); + + FILE* input_file = NULL; +#if defined WIN32 + fopen_s(&input_file, input_file_path, "rb"); +#else + input_file = fopen(input_file_path, "rb"); +#endif + EXPECT_NE(input_file, static_cast<FILE*>(NULL)); + fseek(input_file, 0, SEEK_END); + size_t file_size = ftell(input_file); + fseek(input_file, 0, SEEK_SET); + input_buffer->resize(file_size); + size_t bytes_read = fread(&((*input_buffer)[0]), 1, file_size, input_file); + EXPECT_EQ(bytes_read, file_size); + fclose(input_file); +} + +void SerializeToFile(MemoryOutputStream* output_stream, const char* file_path) { + assert(file_path); + assert(output_stream); + + FILE* output_file = NULL; +#if defined WIN32 + fopen_s(&output_file, file_path, "wb"); +#else + output_file = fopen(file_path, "wb"); +#endif + EXPECT_NE(output_file, static_cast<FILE*>(NULL)); + fwrite(output_stream->Get(), 1, output_stream->Size(), output_file); + fflush(output_file); + fclose(output_file); +} + +void HexDump(const unsigned char* byte_data, size_t length) { + if (byte_data == NULL || length == 0) { + fprintf(stderr, "<NULL>\n"); + return; + } + + fprintf(stderr, "data length = %ld (%lx)\n", length, length); + for (size_t i = 0; i < length; ++i) { + fprintf(stderr, "%02x ", byte_data[i]); + if ((i & 0xf) == 0xf) { + fprintf(stderr, "\n"); + } + } + fprintf(stderr, "\n"); +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/test/test_font_utils.h b/gfx/sfntly/cpp/src/test/test_font_utils.h new file mode 100644 index 0000000000..57fde7a658 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/test_font_utils.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_TEST_TEST_FONT_UTILS_H_ +#define SFNTLY_CPP_SRC_TEST_TEST_FONT_UTILS_H_ + +#include "sfntly/font.h" +#include "sfntly/font_factory.h" +#include "sfntly/port/memory_output_stream.h" + +namespace sfntly { + +void BuilderForFontFile(const char* font_path, FontFactory* factory, + FontBuilderArray* builders); +void SerializeFont(const char* font_path, FontFactory* factory, Font* font); +void LoadFont(const char* font_path, FontFactory* factory, FontArray* fonts); +void LoadFontUsingByteVector(const char* font_path, + bool fingerprint, + FontArray* fonts); + +void LoadFile(const char* input_file_path, ByteVector* input_buffer); +void SerializeToFile(MemoryOutputStream* output_stream, const char* file_path); + +void HexDump(const unsigned char* byte_data, size_t length); + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_TEST_TEST_FONT_UTILS_H_ diff --git a/gfx/sfntly/cpp/src/test/test_utils.cc b/gfx/sfntly/cpp/src/test/test_utils.cc new file mode 100644 index 0000000000..4751b92625 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/test_utils.cc @@ -0,0 +1,89 @@ +/* + * 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 "test/test_utils.h" + +#include <stdio.h> +#include <unicode/ucnv.h> +#include <unicode/uchar.h> + +#include "gtest/gtest.h" +#include "sfntly/font.h" +#include "sfntly/data/memory_byte_array.h" +#include "sfntly/data/growable_memory_byte_array.h" +#include "sfntly/port/file_input_stream.h" + +namespace sfntly { +TestUtils::TestUtils() {} + +// static +// OutputStream CreateOutputStream(const char *file_path) { +// } + +// static +// void TestUtils::CreateNewFile(const char* file_path) { +// } + +// static +int32_t TestUtils::EncodeOneChar(UConverter* encoder, int16_t uchar) { + char* target = new char[ucnv_getMaxCharSize(encoder) * 2]; + char* target_end; + UChar* source = new UChar[2]; + UChar* source_end; + source[0] = (UChar)uchar; + source[1] = 0; + UErrorCode status = U_ZERO_ERROR; + source_end = source; + target_end = target; + ucnv_fromUnicode(encoder, &target_end, target + 4, + (const UChar**)&source_end, source + sizeof(UChar), + NULL, TRUE, &status); + if (!U_SUCCESS(status)) { + fprintf(stderr, "Error occured in conversion of %d: %s\n", + uchar, u_errorName(status)); + delete[] source; + delete[] target; + return 0; + } + int32_t enc_char = 0; + for (int32_t position = 0; position < target_end - target; ++position) { + enc_char <<= 8; + enc_char |= (target[position] & 0xff); + } + delete[] source; + delete[] target; + return enc_char; +} + +// static +UConverter* TestUtils::GetEncoder(const char* charset_name) { + if (charset_name == NULL || strcmp(charset_name, "") == 0) + return NULL; + UErrorCode status = U_ZERO_ERROR; + UConverter* conv = ucnv_open(charset_name, &status); + // if (!U_SUCCESS(status)) + // return NULL; + return conv; // returns NULL @ error anyway +} + +// Get a file's extension +// static +const char* TestUtils::Extension(const char* file_path) { + if (!file_path) + return NULL; + return strrchr(file_path, EXTENSION_SEPARATOR); +} +} diff --git a/gfx/sfntly/cpp/src/test/test_utils.h b/gfx/sfntly/cpp/src/test/test_utils.h new file mode 100644 index 0000000000..af3ffd6c83 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/test_utils.h @@ -0,0 +1,110 @@ +/* + * 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. + */ + +#ifndef SFNTLY_CPP_SRC_TEST_TEST_UTILS_H_ +#define SFNTLY_CPP_SRC_TEST_TEST_UTILS_H_ + +// Must include this before ICU to avoid stdint redefinition issue. +#include "sfntly/port/type.h" + +#include <unicode/ucnv.h> + +#include <string> + +#include "sfntly/font.h" +#include "sfntly/data/memory_byte_array.h" + +namespace sfntly { +class TestUtils { + TestUtils(); + + public: + // Compare sections of two byte arrays for equality + // @param b1 byte array 1 + // @param offset1 offset for comparison in byte array 1 + // @param b2 byte array 2 + // @param offset2 offset for comparison in byte array 2 + // @param length the length of the byte arrays to compare + // @return true if the array segments are equal; false otherwise + // TODO(dfilimon): implement + static bool Equals(ByteArray* b1, + int32_t offset1, + ByteArray* b2, + int32_t offset2); + + // @param offset1 offset to start comparing the first ByteArray from + // @param ba1 the first ByteArray + // @param offset2 offset to start comparing the second ByteArray from + // @param ba2 the second ByteArray + // @param length the number of bytes to compare + // @return true if all bytes in the ranges given are equal; false otherwise + // TODO(dfilimon): implement + static bool Equals(ByteArray* b1, + int32_t offset1, + ByteArray* b2, + int32_t offset2, + int32_t length); + + // TODO(dfilimon): implement FileOutputStream in port/file_output_stream.* + // static OutputStream createOutputStream(const char* file_path); + + // TODO(dfilimon): adapt & implement + // static FileChannel createFilechannelForWriting(File file); + + // Creates a new file including deleting an already existing file with the + // same path and name and creating any needed directories. + // TODO(dfilimon): implement + static void CreateNewFile(const char* file_path); + + // Converts an integer into a 4 character string using the ASCII encoding. + // @param i the value to convert + // @return the String based on the number + // TODO(dfilimon): implement + static void DumpLongAsString(int32_t i, std::string* result); + + // Calculate an OpenType checksum from the array. + // @param b the array to calculate checksum on + // @param offset the starting index in the array + // @param length the number of bytes to check; must be a multiple of 4 + // @return checksum + // TODO(dfilimon): implement + static int64_t CheckSum(ByteArray* b, int32_t offset, int32_t length); + + // Encode a single character in UTF-16. + // We only support the BMP for now + // @param encoder the encoder to use for the encoding + // @param uchar the Unicode character to encode + // @return the encoded character + static int32_t EncodeOneChar(UConverter* encoder, int16_t uchar); + + // Get an encoder for the charset name. + // If the name is null or the empty string then just return null. + // @param charsetName the charset to get an encoder for + // @return an encoder or null if no encoder available for charset name + static UConverter* GetEncoder(const char* charsetName); + + private: + static const char EXTENSION_SEPARATOR = '.'; + + public: + // Get the extension of a file's name. + // @param file the whose name to process + // @return string containing the extension or an empty string if + // there is no extension + static const char* Extension(const char* file_path); +}; +} +#endif // SFNTLY_CPP_SRC_TEST_TEST_UTILS_H_ diff --git a/gfx/sfntly/cpp/src/test/test_utils_test.cc b/gfx/sfntly/cpp/src/test/test_utils_test.cc new file mode 100644 index 0000000000..fbd5ed1a28 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/test_utils_test.cc @@ -0,0 +1,84 @@ +/* + * 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. + */ + +// Must include at the first line to avoid ICU / stdint conflict. +#include "sfntly/port/type.h" + +#include <stdio.h> +#include <unicode/ucnv.h> +#include <unicode/uchar.h> + +#include "gtest/gtest.h" +#include "test/test_utils.h" + +namespace sfntly { + +// Check if proper encoding is being performed +// Conversion is done from UTF16 to UTF8, SJIS +bool TestEncoding() { + UConverter* conv = TestUtils::GetEncoder("utf8"); + EXPECT_TRUE(conv != NULL); + // Ūnĭcōde̽ + UChar from[8] = {0x016A, 0x006E, 0x012D, 0x0063, 0x014D, 0x0064, 0x0065, + 0x033D}; + int32_t want[12] = {0xc5, 0xaa, 0x6e, 0xc4, 0xad, 0x63, 0xc5, 0x8d, 0x64, + 0x65, 0xcc, 0xbd}; + int32_t i, j = 0; + for (i = 0; i < 7; ++i) { + int32_t encoded = TestUtils::EncodeOneChar(conv, (int16_t)from[i]); + for (; encoded; encoded <<= 8) { + uint8_t b = (encoded & 0xff000000) >> 24; + if (!b) + continue; + EXPECT_EQ(want[j], b); + if (want[j++] != b) { + ucnv_close(conv); + return false; + } + } + } + ucnv_close(conv); + return true; +} + +// Check if the proper extension is obtained +bool TestExtension() { + // usual file name + const char *result; + result = TestUtils::Extension("../data/ext/tuffy.ttf"); + EXPECT_EQ(strcmp(result, ".ttf"), 0); + + // more than one 'extension' + result = TestUtils::Extension("tuffy.ttf.fake"); + EXPECT_EQ(strcmp(result, ".fake"), 0); + + // no extension + result = TestUtils::Extension("tuffy"); + EXPECT_STREQ(result, NULL); + + // bogus extension + result = TestUtils::Extension("tuffy."); + EXPECT_EQ(strcmp(result, "."), 0); + + return true; +} + +} // namespace sfntly + +TEST(TestUtils, All) { + ASSERT_TRUE(sfntly::TestExtension()); + ASSERT_TRUE(sfntly::TestEncoding()); +} diff --git a/gfx/sfntly/cpp/src/test/test_xml_utils.cc b/gfx/sfntly/cpp/src/test/test_xml_utils.cc new file mode 100644 index 0000000000..dc65add747 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/test_xml_utils.cc @@ -0,0 +1,50 @@ +/* + * 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 <map> +#include <string> +#include "test/test_xml_utils.h" +#include "test/tinyxml/tinyxml.h" + +namespace sfntly { +void InternalGetNodesWithName(const TiXmlNode* node, const std::string& name, + TiXmlNodeVector* wanted_nodes) { + if (node->ValueStr() == name) + wanted_nodes->push_back(node); + for (const TiXmlNode* child = node->FirstChild(); + child != NULL; child = child->NextSibling()) { + InternalGetNodesWithName(child, name, wanted_nodes); + } +} + +TiXmlNodeVector* GetNodesWithName(const TiXmlNode* node, + const std::string& name) { + TiXmlNodeVector* wanted_nodes = new TiXmlNodeVector; + InternalGetNodesWithName(node, name, wanted_nodes); + return wanted_nodes; +} + +const TiXmlAttribute* GetAttribute(const TiXmlNode* node, + const std::string& name) { + for (const TiXmlAttribute* attribute = node->ToElement()->FirstAttribute(); + attribute != NULL; attribute = attribute->Next()) { + if (attribute->Name() == name) { + return attribute; + } + } + return NULL; +} +} diff --git a/gfx/sfntly/cpp/src/test/test_xml_utils.h b/gfx/sfntly/cpp/src/test/test_xml_utils.h new file mode 100644 index 0000000000..7a5fe49d6b --- /dev/null +++ b/gfx/sfntly/cpp/src/test/test_xml_utils.h @@ -0,0 +1,33 @@ +/* + * 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 "sfntly/port/refcount.h" +#include "test/tinyxml/tinyxml.h" + +#ifndef SFNTLY_CPP_SRC_TEST_TEST_XML_UTILS_H_ +#define SFNTLY_CPP_SRC_TEST_TEST_XML_UTILS_H_ + +namespace sfntly { +typedef std::map<std::string, std::string> AttributeMap; +typedef std::vector<const TiXmlNode*> TiXmlNodeVector; + +TiXmlNodeVector* GetNodesWithName(const TiXmlNode* node, + const std::string& name); +const TiXmlAttribute* GetAttribute(const TiXmlNode* node, + const std::string& name); +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_TEST_TEST_XML_UTILS_H_ diff --git a/gfx/sfntly/cpp/src/test/tinyxml/tinystr.cpp b/gfx/sfntly/cpp/src/test/tinyxml/tinystr.cpp new file mode 100644 index 0000000000..0665768205 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/tinyxml/tinystr.cpp @@ -0,0 +1,111 @@ +/* +www.sourceforge.net/projects/tinyxml + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + + +#ifndef TIXML_USE_STL + +#include "tinystr.h" + +// Error value for find primitive +const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1); + + +// Null rep. +TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; + + +void TiXmlString::reserve (size_type cap) +{ + if (cap > capacity()) + { + TiXmlString tmp; + tmp.init(length(), cap); + memcpy(tmp.start(), data(), length()); + swap(tmp); + } +} + + +TiXmlString& TiXmlString::assign(const char* str, size_type len) +{ + size_type cap = capacity(); + if (len > cap || cap > 3*(len + 8)) + { + TiXmlString tmp; + tmp.init(len); + memcpy(tmp.start(), str, len); + swap(tmp); + } + else + { + memmove(start(), str, len); + set_size(len); + } + return *this; +} + + +TiXmlString& TiXmlString::append(const char* str, size_type len) +{ + size_type newsize = length() + len; + if (newsize > capacity()) + { + reserve (newsize + capacity()); + } + memmove(finish(), str, len); + set_size(newsize); + return *this; +} + + +TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) +{ + TiXmlString tmp; + tmp.reserve(a.length() + b.length()); + tmp += a; + tmp += b; + return tmp; +} + +TiXmlString operator + (const TiXmlString & a, const char* b) +{ + TiXmlString tmp; + TiXmlString::size_type b_len = static_cast<TiXmlString::size_type>( strlen(b) ); + tmp.reserve(a.length() + b_len); + tmp += a; + tmp.append(b, b_len); + return tmp; +} + +TiXmlString operator + (const char* a, const TiXmlString & b) +{ + TiXmlString tmp; + TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) ); + tmp.reserve(a_len + b.length()); + tmp.append(a, a_len); + tmp += b; + return tmp; +} + + +#endif // TIXML_USE_STL diff --git a/gfx/sfntly/cpp/src/test/tinyxml/tinystr.h b/gfx/sfntly/cpp/src/test/tinyxml/tinystr.h new file mode 100644 index 0000000000..89cca33415 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/tinyxml/tinystr.h @@ -0,0 +1,305 @@ +/* +www.sourceforge.net/projects/tinyxml + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + + +#ifndef TIXML_USE_STL + +#ifndef TIXML_STRING_INCLUDED +#define TIXML_STRING_INCLUDED + +#include <assert.h> +#include <string.h> + +/* The support for explicit isn't that universal, and it isn't really + required - it is used to check that the TiXmlString class isn't incorrectly + used. Be nice to old compilers and macro it here: +*/ +#if defined(_MSC_VER) && (_MSC_VER >= 1200 ) + // Microsoft visual studio, version 6 and higher. + #define TIXML_EXPLICIT explicit +#elif defined(__GNUC__) && (__GNUC__ >= 3 ) + // GCC version 3 and higher.s + #define TIXML_EXPLICIT explicit +#else + #define TIXML_EXPLICIT +#endif + + +/* + TiXmlString is an emulation of a subset of the std::string template. + Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. + Only the member functions relevant to the TinyXML project have been implemented. + The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase + a string and there's no more room, we allocate a buffer twice as big as we need. +*/ +class TiXmlString +{ + public : + // The size type used + typedef size_t size_type; + + // Error value for find primitive + static const size_type npos; // = -1; + + + // TiXmlString empty constructor + TiXmlString () : rep_(&nullrep_) + { + } + + // TiXmlString copy constructor + TiXmlString ( const TiXmlString & copy) : rep_(0) + { + init(copy.length()); + memcpy(start(), copy.data(), length()); + } + + // TiXmlString constructor, based on a string + TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) + { + init( static_cast<size_type>( strlen(copy) )); + memcpy(start(), copy, length()); + } + + // TiXmlString constructor, based on a string + TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) + { + init(len); + memcpy(start(), str, len); + } + + // TiXmlString destructor + ~TiXmlString () + { + quit(); + } + + TiXmlString& operator = (const char * copy) + { + return assign( copy, (size_type)strlen(copy)); + } + + TiXmlString& operator = (const TiXmlString & copy) + { + return assign(copy.start(), copy.length()); + } + + + // += operator. Maps to append + TiXmlString& operator += (const char * suffix) + { + return append(suffix, static_cast<size_type>( strlen(suffix) )); + } + + // += operator. Maps to append + TiXmlString& operator += (char single) + { + return append(&single, 1); + } + + // += operator. Maps to append + TiXmlString& operator += (const TiXmlString & suffix) + { + return append(suffix.data(), suffix.length()); + } + + + // Convert a TiXmlString into a null-terminated char * + const char * c_str () const { return rep_->str; } + + // Convert a TiXmlString into a char * (need not be null terminated). + const char * data () const { return rep_->str; } + + // Return the length of a TiXmlString + size_type length () const { return rep_->size; } + + // Alias for length() + size_type size () const { return rep_->size; } + + // Checks if a TiXmlString is empty + bool empty () const { return rep_->size == 0; } + + // Return capacity of string + size_type capacity () const { return rep_->capacity; } + + + // single char extraction + const char& at (size_type index) const + { + assert( index < length() ); + return rep_->str[ index ]; + } + + // [] operator + char& operator [] (size_type index) const + { + assert( index < length() ); + return rep_->str[ index ]; + } + + // find a char in a string. Return TiXmlString::npos if not found + size_type find (char lookup) const + { + return find(lookup, 0); + } + + // find a char in a string from an offset. Return TiXmlString::npos if not found + size_type find (char tofind, size_type offset) const + { + if (offset >= length()) return npos; + + for (const char* p = c_str() + offset; *p != '\0'; ++p) + { + if (*p == tofind) return static_cast< size_type >( p - c_str() ); + } + return npos; + } + + void clear () + { + //Lee: + //The original was just too strange, though correct: + // TiXmlString().swap(*this); + //Instead use the quit & re-init: + quit(); + init(0,0); + } + + /* Function to reserve a big amount of data when we know we'll need it. Be aware that this + function DOES NOT clear the content of the TiXmlString if any exists. + */ + void reserve (size_type cap); + + TiXmlString& assign (const char* str, size_type len); + + TiXmlString& append (const char* str, size_type len); + + void swap (TiXmlString& other) + { + Rep* r = rep_; + rep_ = other.rep_; + other.rep_ = r; + } + + private: + + void init(size_type sz) { init(sz, sz); } + void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } + char* start() const { return rep_->str; } + char* finish() const { return rep_->str + rep_->size; } + + struct Rep + { + size_type size, capacity; + char str[1]; + }; + + void init(size_type sz, size_type cap) + { + if (cap) + { + // Lee: the original form: + // rep_ = static_cast<Rep*>(operator new(sizeof(Rep) + cap)); + // doesn't work in some cases of new being overloaded. Switching + // to the normal allocation, although use an 'int' for systems + // that are overly picky about structure alignment. + const size_type bytesNeeded = sizeof(Rep) + cap; + const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); + rep_ = reinterpret_cast<Rep*>( new int[ intsNeeded ] ); + + rep_->str[ rep_->size = sz ] = '\0'; + rep_->capacity = cap; + } + else + { + rep_ = &nullrep_; + } + } + + void quit() + { + if (rep_ != &nullrep_) + { + // The rep_ is really an array of ints. (see the allocator, above). + // Cast it back before delete, so the compiler won't incorrectly call destructors. + delete [] ( reinterpret_cast<int*>( rep_ ) ); + } + } + + Rep * rep_; + static Rep nullrep_; + +} ; + + +inline bool operator == (const TiXmlString & a, const TiXmlString & b) +{ + return ( a.length() == b.length() ) // optimization on some platforms + && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare +} +inline bool operator < (const TiXmlString & a, const TiXmlString & b) +{ + return strcmp(a.c_str(), b.c_str()) < 0; +} + +inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } +inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } +inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } +inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } + +inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } +inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } +inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } +inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } + +TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); +TiXmlString operator + (const TiXmlString & a, const char* b); +TiXmlString operator + (const char* a, const TiXmlString & b); + + +/* + TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. + Only the operators that we need for TinyXML have been developped. +*/ +class TiXmlOutStream : public TiXmlString +{ +public : + + // TiXmlOutStream << operator. + TiXmlOutStream & operator << (const TiXmlString & in) + { + *this += in; + return *this; + } + + // TiXmlOutStream << operator. + TiXmlOutStream & operator << (const char * in) + { + *this += in; + return *this; + } + +} ; + +#endif // TIXML_STRING_INCLUDED +#endif // TIXML_USE_STL diff --git a/gfx/sfntly/cpp/src/test/tinyxml/tinyxml.cpp b/gfx/sfntly/cpp/src/test/tinyxml/tinyxml.cpp new file mode 100644 index 0000000000..9c161dfcb9 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/tinyxml/tinyxml.cpp @@ -0,0 +1,1886 @@ +/* +www.sourceforge.net/projects/tinyxml +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include <ctype.h> + +#ifdef TIXML_USE_STL +#include <sstream> +#include <iostream> +#endif + +#include "tinyxml.h" + +FILE* TiXmlFOpen( const char* filename, const char* mode ); + +bool TiXmlBase::condenseWhiteSpace = true; + +// Microsoft compiler security +FILE* TiXmlFOpen( const char* filename, const char* mode ) +{ + #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) + FILE* fp = 0; + errno_t err = fopen_s( &fp, filename, mode ); + if ( !err && fp ) + return fp; + return 0; + #else + return fopen( filename, mode ); + #endif +} + +void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString ) +{ + int i=0; + + while( i<(int)str.length() ) + { + unsigned char c = (unsigned char) str[i]; + + if ( c == '&' + && i < ( (int)str.length() - 2 ) + && str[i+1] == '#' + && str[i+2] == 'x' ) + { + // Hexadecimal character reference. + // Pass through unchanged. + // © -- copyright symbol, for example. + // + // The -1 is a bug fix from Rob Laveaux. It keeps + // an overflow from happening if there is no ';'. + // There are actually 2 ways to exit this loop - + // while fails (error case) and break (semicolon found). + // However, there is no mechanism (currently) for + // this function to return an error. + while ( i<(int)str.length()-1 ) + { + outString->append( str.c_str() + i, 1 ); + ++i; + if ( str[i] == ';' ) + break; + } + } + else if ( c == '&' ) + { + outString->append( entity[0].str, entity[0].strLength ); + ++i; + } + else if ( c == '<' ) + { + outString->append( entity[1].str, entity[1].strLength ); + ++i; + } + else if ( c == '>' ) + { + outString->append( entity[2].str, entity[2].strLength ); + ++i; + } + else if ( c == '\"' ) + { + outString->append( entity[3].str, entity[3].strLength ); + ++i; + } + else if ( c == '\'' ) + { + outString->append( entity[4].str, entity[4].strLength ); + ++i; + } + else if ( c < 32 ) + { + // Easy pass at non-alpha/numeric/symbol + // Below 32 is symbolic. + char buf[ 32 ]; + + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); + #else + sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); + #endif + + //*ME: warning C4267: convert 'size_t' to 'int' + //*ME: Int-Cast to make compiler happy ... + outString->append( buf, (int)strlen( buf ) ); + ++i; + } + else + { + //char realc = (char) c; + //outString->append( &realc, 1 ); + *outString += (char) c; // somewhat more efficient function call. + ++i; + } + } +} + + +TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() +{ + parent = 0; + type = _type; + firstChild = 0; + lastChild = 0; + prev = 0; + next = 0; +} + + +TiXmlNode::~TiXmlNode() +{ + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; + + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } +} + + +void TiXmlNode::CopyTo( TiXmlNode* target ) const +{ + target->SetValue (value.c_str() ); + target->userData = userData; + target->location = location; +} + + +void TiXmlNode::Clear() +{ + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; + + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } + + firstChild = 0; + lastChild = 0; +} + + +TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) +{ + assert( node->parent == 0 || node->parent == this ); + assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); + + if ( node->Type() == TiXmlNode::TINYXML_DOCUMENT ) + { + delete node; + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + node->parent = this; + + node->prev = lastChild; + node->next = 0; + + if ( lastChild ) + lastChild->next = node; + else + firstChild = node; // it was an empty list. + + lastChild = node; + return node; +} + + +TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) +{ + if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) + { + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + + return LinkEndChild( node ); +} + + +TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) +{ + if ( !beforeThis || beforeThis->parent != this ) { + return 0; + } + if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) + { + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->next = beforeThis; + node->prev = beforeThis->prev; + if ( beforeThis->prev ) + { + beforeThis->prev->next = node; + } + else + { + assert( firstChild == beforeThis ); + firstChild = node; + } + beforeThis->prev = node; + return node; +} + + +TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) +{ + if ( !afterThis || afterThis->parent != this ) { + return 0; + } + if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) + { + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->prev = afterThis; + node->next = afterThis->next; + if ( afterThis->next ) + { + afterThis->next->prev = node; + } + else + { + assert( lastChild == afterThis ); + lastChild = node; + } + afterThis->next = node; + return node; +} + + +TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) +{ + if ( !replaceThis ) + return 0; + + if ( replaceThis->parent != this ) + return 0; + + if ( withThis.ToDocument() ) { + // A document can never be a child. Thanks to Noam. + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = withThis.Clone(); + if ( !node ) + return 0; + + node->next = replaceThis->next; + node->prev = replaceThis->prev; + + if ( replaceThis->next ) + replaceThis->next->prev = node; + else + lastChild = node; + + if ( replaceThis->prev ) + replaceThis->prev->next = node; + else + firstChild = node; + + delete replaceThis; + node->parent = this; + return node; +} + + +bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) +{ + if ( !removeThis ) { + return false; + } + + if ( removeThis->parent != this ) + { + assert( 0 ); + return false; + } + + if ( removeThis->next ) + removeThis->next->prev = removeThis->prev; + else + lastChild = removeThis->prev; + + if ( removeThis->prev ) + removeThis->prev->next = removeThis->next; + else + firstChild = removeThis->next; + + delete removeThis; + return true; +} + +const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = firstChild; node; node = node->next ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = lastChild; node; node = node->prev ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const +{ + if ( !previous ) + { + return FirstChild(); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling(); + } +} + + +const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const +{ + if ( !previous ) + { + return FirstChild( val ); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling( val ); + } +} + + +const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = next; node; node = node->next ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = prev; node; node = node->prev ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +void TiXmlElement::RemoveAttribute( const char * name ) +{ + #ifdef TIXML_USE_STL + TIXML_STRING str( name ); + TiXmlAttribute* node = attributeSet.Find( str ); + #else + TiXmlAttribute* node = attributeSet.Find( name ); + #endif + if ( node ) + { + attributeSet.Remove( node ); + delete node; + } +} + +const TiXmlElement* TiXmlNode::FirstChildElement() const +{ + const TiXmlNode* node; + + for ( node = FirstChild(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const +{ + const TiXmlNode* node; + + for ( node = FirstChild( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::NextSiblingElement() const +{ + const TiXmlNode* node; + + for ( node = NextSibling(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const +{ + const TiXmlNode* node; + + for ( node = NextSibling( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlDocument* TiXmlNode::GetDocument() const +{ + const TiXmlNode* node; + + for( node = this; node; node = node->parent ) + { + if ( node->ToDocument() ) + return node->ToDocument(); + } + return 0; +} + + +TiXmlElement::TiXmlElement (const char * _value) + : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) +{ + firstChild = lastChild = 0; + value = _value; +} + + +#ifdef TIXML_USE_STL +TiXmlElement::TiXmlElement( const std::string& _value ) + : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) +{ + firstChild = lastChild = 0; + value = _value; +} +#endif + + +TiXmlElement::TiXmlElement( const TiXmlElement& copy) + : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) +{ + firstChild = lastChild = 0; + copy.CopyTo( this ); +} + + +TiXmlElement& TiXmlElement::operator=( const TiXmlElement& base ) +{ + ClearThis(); + base.CopyTo( this ); + return *this; +} + + +TiXmlElement::~TiXmlElement() +{ + ClearThis(); +} + + +void TiXmlElement::ClearThis() +{ + Clear(); + while( attributeSet.First() ) + { + TiXmlAttribute* node = attributeSet.First(); + attributeSet.Remove( node ); + delete node; + } +} + + +const char* TiXmlElement::Attribute( const char* name ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + return node->Value(); + return 0; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( attrib ) + return &attrib->ValueStr(); + return 0; +} +#endif + + +const char* TiXmlElement::Attribute( const char* name, int* i ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const char* result = 0; + + if ( attrib ) { + result = attrib->Value(); + if ( i ) { + attrib->QueryIntValue( i ); + } + } + return result; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const std::string* result = 0; + + if ( attrib ) { + result = &attrib->ValueStr(); + if ( i ) { + attrib->QueryIntValue( i ); + } + } + return result; +} +#endif + + +const char* TiXmlElement::Attribute( const char* name, double* d ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const char* result = 0; + + if ( attrib ) { + result = attrib->Value(); + if ( d ) { + attrib->QueryDoubleValue( d ); + } + } + return result; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const std::string* result = 0; + + if ( attrib ) { + result = &attrib->ValueStr(); + if ( d ) { + attrib->QueryDoubleValue( d ); + } + } + return result; +} +#endif + + +int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryIntValue( ival ); +} + + +int TiXmlElement::QueryUnsignedAttribute( const char* name, unsigned* value ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + + int ival = 0; + int result = node->QueryIntValue( &ival ); + *value = (unsigned)ival; + return result; +} + + +int TiXmlElement::QueryBoolAttribute( const char* name, bool* bval ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + + int result = TIXML_WRONG_TYPE; + if ( StringEqual( node->Value(), "true", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "yes", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "1", true, TIXML_ENCODING_UNKNOWN ) ) + { + *bval = true; + result = TIXML_SUCCESS; + } + else if ( StringEqual( node->Value(), "false", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "no", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "0", true, TIXML_ENCODING_UNKNOWN ) ) + { + *bval = false; + result = TIXML_SUCCESS; + } + return result; +} + + + +#ifdef TIXML_USE_STL +int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryIntValue( ival ); +} +#endif + + +int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryDoubleValue( dval ); +} + + +#ifdef TIXML_USE_STL +int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryDoubleValue( dval ); +} +#endif + + +void TiXmlElement::SetAttribute( const char * name, int val ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetIntValue( val ); + } +} + + +#ifdef TIXML_USE_STL +void TiXmlElement::SetAttribute( const std::string& name, int val ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetIntValue( val ); + } +} +#endif + + +void TiXmlElement::SetDoubleAttribute( const char * name, double val ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetDoubleValue( val ); + } +} + + +#ifdef TIXML_USE_STL +void TiXmlElement::SetDoubleAttribute( const std::string& name, double val ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetDoubleValue( val ); + } +} +#endif + + +void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( cname ); + if ( attrib ) { + attrib->SetValue( cvalue ); + } +} + + +#ifdef TIXML_USE_STL +void TiXmlElement::SetAttribute( const std::string& _name, const std::string& _value ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( _name ); + if ( attrib ) { + attrib->SetValue( _value ); + } +} +#endif + + +void TiXmlElement::Print( FILE* cfile, int depth ) const +{ + int i; + assert( cfile ); + for ( i=0; i<depth; i++ ) { + fprintf( cfile, " " ); + } + + fprintf( cfile, "<%s", value.c_str() ); + + const TiXmlAttribute* attrib; + for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) + { + fprintf( cfile, " " ); + attrib->Print( cfile, depth ); + } + + // There are 3 different formatting approaches: + // 1) An element without children is printed as a <foo /> node + // 2) An element with only a text child is printed as <foo> text </foo> + // 3) An element with children is printed on multiple lines. + TiXmlNode* node; + if ( !firstChild ) + { + fprintf( cfile, " />" ); + } + else if ( firstChild == lastChild && firstChild->ToText() ) + { + fprintf( cfile, ">" ); + firstChild->Print( cfile, depth + 1 ); + fprintf( cfile, "</%s>", value.c_str() ); + } + else + { + fprintf( cfile, ">" ); + + for ( node = firstChild; node; node=node->NextSibling() ) + { + if ( !node->ToText() ) + { + fprintf( cfile, "\n" ); + } + node->Print( cfile, depth+1 ); + } + fprintf( cfile, "\n" ); + for( i=0; i<depth; ++i ) { + fprintf( cfile, " " ); + } + fprintf( cfile, "</%s>", value.c_str() ); + } +} + + +void TiXmlElement::CopyTo( TiXmlElement* target ) const +{ + // superclass: + TiXmlNode::CopyTo( target ); + + // Element class: + // Clone the attributes, then clone the children. + const TiXmlAttribute* attribute = 0; + for( attribute = attributeSet.First(); + attribute; + attribute = attribute->Next() ) + { + target->SetAttribute( attribute->Name(), attribute->Value() ); + } + + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } +} + +bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const +{ + if ( visitor->VisitEnter( *this, attributeSet.First() ) ) + { + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + if ( !node->Accept( visitor ) ) + break; + } + } + return visitor->VisitExit( *this ); +} + + +TiXmlNode* TiXmlElement::Clone() const +{ + TiXmlElement* clone = new TiXmlElement( Value() ); + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +const char* TiXmlElement::GetText() const +{ + const TiXmlNode* child = this->FirstChild(); + if ( child ) { + const TiXmlText* childText = child->ToText(); + if ( childText ) { + return childText->Value(); + } + } + return 0; +} + + +TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + ClearError(); +} + +TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + value = documentName; + ClearError(); +} + + +#ifdef TIXML_USE_STL +TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + value = documentName; + ClearError(); +} +#endif + + +TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) +{ + copy.CopyTo( this ); +} + + +TiXmlDocument& TiXmlDocument::operator=( const TiXmlDocument& copy ) +{ + Clear(); + copy.CopyTo( this ); + return *this; +} + + +bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) +{ + return LoadFile( Value(), encoding ); +} + + +bool TiXmlDocument::SaveFile() const +{ + return SaveFile( Value() ); +} + +bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) +{ + TIXML_STRING filename( _filename ); + value = filename; + + // reading in binary mode so that tinyxml can normalize the EOL + FILE* file = TiXmlFOpen( value.c_str (), "rb" ); + + if ( file ) + { + bool result = LoadFile( file, encoding ); + fclose( file ); + return result; + } + else + { + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } +} + +bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) +{ + if ( !file ) + { + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // Delete the existing data: + Clear(); + location.Clear(); + + // Get the file size, so we can pre-allocate the string. HUGE speed impact. + long length = 0; + fseek( file, 0, SEEK_END ); + length = ftell( file ); + fseek( file, 0, SEEK_SET ); + + // Strange case, but good to handle up front. + if ( length <= 0 ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // Subtle bug here. TinyXml did use fgets. But from the XML spec: + // 2.11 End-of-Line Handling + // <snip> + // <quote> + // ...the XML processor MUST behave as if it normalized all line breaks in external + // parsed entities (including the document entity) on input, before parsing, by translating + // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to + // a single #xA character. + // </quote> + // + // It is not clear fgets does that, and certainly isn't clear it works cross platform. + // Generally, you expect fgets to translate from the convention of the OS to the c/unix + // convention, and not work generally. + + /* + while( fgets( buf, sizeof(buf), file ) ) + { + data += buf; + } + */ + + char* buf = new char[ length+1 ]; + buf[0] = 0; + + if ( fread( buf, length, 1, file ) != 1 ) { + delete [] buf; + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // Process the buffer in place to normalize new lines. (See comment above.) + // Copies from the 'p' to 'q' pointer, where p can advance faster if + // a newline-carriage return is hit. + // + // Wikipedia: + // Systems based on ASCII or a compatible character set use either LF (Line feed, '\n', 0x0A, 10 in decimal) or + // CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)... + // * LF: Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others + // * CR+LF: DEC RT-11 and most other early non-Unix, non-IBM OSes, CP/M, MP/M, DOS, OS/2, Microsoft Windows, Symbian OS + // * CR: Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9 + + const char* p = buf; // the read head + char* q = buf; // the write head + const char CR = 0x0d; + const char LF = 0x0a; + + buf[length] = 0; + while( *p ) { + assert( p < (buf+length) ); + assert( q <= (buf+length) ); + assert( q <= p ); + + if ( *p == CR ) { + *q++ = LF; + p++; + if ( *p == LF ) { // check for CR+LF (and skip LF) + p++; + } + } + else { + *q++ = *p++; + } + } + assert( q <= (buf+length) ); + *q = 0; + + Parse( buf, 0, encoding ); + + delete [] buf; + return !Error(); +} + + +bool TiXmlDocument::SaveFile( const char * filename ) const +{ + // The old c stuff lives on... + FILE* fp = TiXmlFOpen( filename, "w" ); + if ( fp ) + { + bool result = SaveFile( fp ); + fclose( fp ); + return result; + } + return false; +} + + +bool TiXmlDocument::SaveFile( FILE* fp ) const +{ + if ( useMicrosoftBOM ) + { + const unsigned char TIXML_UTF_LEAD_0 = 0xefU; + const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; + const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + + fputc( TIXML_UTF_LEAD_0, fp ); + fputc( TIXML_UTF_LEAD_1, fp ); + fputc( TIXML_UTF_LEAD_2, fp ); + } + Print( fp, 0 ); + return (ferror(fp) == 0); +} + + +void TiXmlDocument::CopyTo( TiXmlDocument* target ) const +{ + TiXmlNode::CopyTo( target ); + + target->error = error; + target->errorId = errorId; + target->errorDesc = errorDesc; + target->tabsize = tabsize; + target->errorLocation = errorLocation; + target->useMicrosoftBOM = useMicrosoftBOM; + + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } +} + + +TiXmlNode* TiXmlDocument::Clone() const +{ + TiXmlDocument* clone = new TiXmlDocument(); + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlDocument::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + node->Print( cfile, depth ); + fprintf( cfile, "\n" ); + } +} + + +bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const +{ + if ( visitor->VisitEnter( *this ) ) + { + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + if ( !node->Accept( visitor ) ) + break; + } + } + return visitor->VisitExit( *this ); +} + + +const TiXmlAttribute* TiXmlAttribute::Next() const +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( next->value.empty() && next->name.empty() ) + return 0; + return next; +} + +/* +TiXmlAttribute* TiXmlAttribute::Next() +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( next->value.empty() && next->name.empty() ) + return 0; + return next; +} +*/ + +const TiXmlAttribute* TiXmlAttribute::Previous() const +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( prev->value.empty() && prev->name.empty() ) + return 0; + return prev; +} + +/* +TiXmlAttribute* TiXmlAttribute::Previous() +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( prev->value.empty() && prev->name.empty() ) + return 0; + return prev; +} +*/ + +void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const +{ + TIXML_STRING n, v; + + EncodeString( name, &n ); + EncodeString( value, &v ); + + if (value.find ('\"') == TIXML_STRING::npos) { + if ( cfile ) { + fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); + } + if ( str ) { + (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; + } + } + else { + if ( cfile ) { + fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); + } + if ( str ) { + (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; + } + } +} + + +int TiXmlAttribute::QueryIntValue( int* ival ) const +{ + if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; +} + +int TiXmlAttribute::QueryDoubleValue( double* dval ) const +{ + if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; +} + +void TiXmlAttribute::SetIntValue( int _value ) +{ + char buf [64]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); + #else + sprintf (buf, "%d", _value); + #endif + SetValue (buf); +} + +void TiXmlAttribute::SetDoubleValue( double _value ) +{ + char buf [256]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "%g", _value); + #else + sprintf (buf, "%g", _value); + #endif + SetValue (buf); +} + +int TiXmlAttribute::IntValue() const +{ + return atoi (value.c_str ()); +} + +double TiXmlAttribute::DoubleValue() const +{ + return atof (value.c_str ()); +} + + +TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) +{ + copy.CopyTo( this ); +} + + +TiXmlComment& TiXmlComment::operator=( const TiXmlComment& base ) +{ + Clear(); + base.CopyTo( this ); + return *this; +} + + +void TiXmlComment::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + for ( int i=0; i<depth; i++ ) + { + fprintf( cfile, " " ); + } + fprintf( cfile, "<!--%s-->", value.c_str() ); +} + + +void TiXmlComment::CopyTo( TiXmlComment* target ) const +{ + TiXmlNode::CopyTo( target ); +} + + +bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlComment::Clone() const +{ + TiXmlComment* clone = new TiXmlComment(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlText::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + if ( cdata ) + { + int i; + fprintf( cfile, "\n" ); + for ( i=0; i<depth; i++ ) { + fprintf( cfile, " " ); + } + fprintf( cfile, "<![CDATA[%s]]>\n", value.c_str() ); // unformatted output + } + else + { + TIXML_STRING buffer; + EncodeString( value, &buffer ); + fprintf( cfile, "%s", buffer.c_str() ); + } +} + + +void TiXmlText::CopyTo( TiXmlText* target ) const +{ + TiXmlNode::CopyTo( target ); + target->cdata = cdata; +} + + +bool TiXmlText::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlText::Clone() const +{ + TiXmlText* clone = 0; + clone = new TiXmlText( "" ); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +TiXmlDeclaration::TiXmlDeclaration( const char * _version, + const char * _encoding, + const char * _standalone ) + : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) +{ + version = _version; + encoding = _encoding; + standalone = _standalone; +} + + +#ifdef TIXML_USE_STL +TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, + const std::string& _encoding, + const std::string& _standalone ) + : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) +{ + version = _version; + encoding = _encoding; + standalone = _standalone; +} +#endif + + +TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) + : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) +{ + copy.CopyTo( this ); +} + + +TiXmlDeclaration& TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) +{ + Clear(); + copy.CopyTo( this ); + return *this; +} + + +void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const +{ + if ( cfile ) fprintf( cfile, "<?xml " ); + if ( str ) (*str) += "<?xml "; + + if ( !version.empty() ) { + if ( cfile ) fprintf (cfile, "version=\"%s\" ", version.c_str ()); + if ( str ) { (*str) += "version=\""; (*str) += version; (*str) += "\" "; } + } + if ( !encoding.empty() ) { + if ( cfile ) fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ()); + if ( str ) { (*str) += "encoding=\""; (*str) += encoding; (*str) += "\" "; } + } + if ( !standalone.empty() ) { + if ( cfile ) fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ()); + if ( str ) { (*str) += "standalone=\""; (*str) += standalone; (*str) += "\" "; } + } + if ( cfile ) fprintf( cfile, "?>" ); + if ( str ) (*str) += "?>"; +} + + +void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const +{ + TiXmlNode::CopyTo( target ); + + target->version = version; + target->encoding = encoding; + target->standalone = standalone; +} + + +bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlDeclaration::Clone() const +{ + TiXmlDeclaration* clone = new TiXmlDeclaration(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlUnknown::Print( FILE* cfile, int depth ) const +{ + for ( int i=0; i<depth; i++ ) + fprintf( cfile, " " ); + fprintf( cfile, "<%s>", value.c_str() ); +} + + +void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const +{ + TiXmlNode::CopyTo( target ); +} + + +bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlUnknown::Clone() const +{ + TiXmlUnknown* clone = new TiXmlUnknown(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +TiXmlAttributeSet::TiXmlAttributeSet() +{ + sentinel.next = &sentinel; + sentinel.prev = &sentinel; +} + + +TiXmlAttributeSet::~TiXmlAttributeSet() +{ + assert( sentinel.next == &sentinel ); + assert( sentinel.prev == &sentinel ); +} + + +void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) +{ + #ifdef TIXML_USE_STL + assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. + #else + assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. + #endif + + addMe->next = &sentinel; + addMe->prev = sentinel.prev; + + sentinel.prev->next = addMe; + sentinel.prev = addMe; +} + +void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) +{ + TiXmlAttribute* node; + + for( node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node == removeMe ) + { + node->prev->next = node->next; + node->next->prev = node->prev; + node->next = 0; + node->prev = 0; + return; + } + } + assert( 0 ); // we tried to remove a non-linked attribute. +} + + +#ifdef TIXML_USE_STL +TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const +{ + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node->name == name ) + return node; + } + return 0; +} + +TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const std::string& _name ) +{ + TiXmlAttribute* attrib = Find( _name ); + if ( !attrib ) { + attrib = new TiXmlAttribute(); + Add( attrib ); + attrib->SetName( _name ); + } + return attrib; +} +#endif + + +TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const +{ + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( strcmp( node->name.c_str(), name ) == 0 ) + return node; + } + return 0; +} + + +TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const char* _name ) +{ + TiXmlAttribute* attrib = Find( _name ); + if ( !attrib ) { + attrib = new TiXmlAttribute(); + Add( attrib ); + attrib->SetName( _name ); + } + return attrib; +} + + +#ifdef TIXML_USE_STL +std::istream& operator>> (std::istream & in, TiXmlNode & base) +{ + TIXML_STRING tag; + tag.reserve( 8 * 1000 ); + base.StreamIn( &in, &tag ); + + base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); + return in; +} +#endif + + +#ifdef TIXML_USE_STL +std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) +{ + TiXmlPrinter printer; + printer.SetStreamPrinting(); + base.Accept( &printer ); + out << printer.Str(); + + return out; +} + + +std::string& operator<< (std::string& out, const TiXmlNode& base ) +{ + TiXmlPrinter printer; + printer.SetStreamPrinting(); + base.Accept( &printer ); + out.append( printer.Str() ); + + return out; +} +#endif + + +TiXmlHandle TiXmlHandle::FirstChild() const +{ + if ( node ) + { + TiXmlNode* child = node->FirstChild(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const +{ + if ( node ) + { + TiXmlNode* child = node->FirstChild( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChildElement() const +{ + if ( node ) + { + TiXmlElement* child = node->FirstChildElement(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const +{ + if ( node ) + { + TiXmlElement* child = node->FirstChildElement( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::Child( int count ) const +{ + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild(); + for ( i=0; + child && i<count; + child = child->NextSibling(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const +{ + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild( value ); + for ( i=0; + child && i<count; + child = child->NextSibling( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::ChildElement( int count ) const +{ + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement(); + for ( i=0; + child && i<count; + child = child->NextSiblingElement(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const +{ + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement( value ); + for ( i=0; + child && i<count; + child = child->NextSiblingElement( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) +{ + return true; +} + +bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) +{ + return true; +} + +bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) +{ + DoIndent(); + buffer += "<"; + buffer += element.Value(); + + for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) + { + buffer += " "; + attrib->Print( 0, 0, &buffer ); + } + + if ( !element.FirstChild() ) + { + buffer += " />"; + DoLineBreak(); + } + else + { + buffer += ">"; + if ( element.FirstChild()->ToText() + && element.LastChild() == element.FirstChild() + && element.FirstChild()->ToText()->CDATA() == false ) + { + simpleTextPrint = true; + // no DoLineBreak()! + } + else + { + DoLineBreak(); + } + } + ++depth; + return true; +} + + +bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) +{ + --depth; + if ( !element.FirstChild() ) + { + // nothing. + } + else + { + if ( simpleTextPrint ) + { + simpleTextPrint = false; + } + else + { + DoIndent(); + } + buffer += "</"; + buffer += element.Value(); + buffer += ">"; + DoLineBreak(); + } + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlText& text ) +{ + if ( text.CDATA() ) + { + DoIndent(); + buffer += "<![CDATA["; + buffer += text.Value(); + buffer += "]]>"; + DoLineBreak(); + } + else if ( simpleTextPrint ) + { + TIXML_STRING str; + TiXmlBase::EncodeString( text.ValueTStr(), &str ); + buffer += str; + } + else + { + DoIndent(); + TIXML_STRING str; + TiXmlBase::EncodeString( text.ValueTStr(), &str ); + buffer += str; + DoLineBreak(); + } + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) +{ + DoIndent(); + declaration.Print( 0, 0, &buffer ); + DoLineBreak(); + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlComment& comment ) +{ + DoIndent(); + buffer += "<!--"; + buffer += comment.Value(); + buffer += "-->"; + DoLineBreak(); + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) +{ + DoIndent(); + buffer += "<"; + buffer += unknown.Value(); + buffer += ">"; + DoLineBreak(); + return true; +} + diff --git a/gfx/sfntly/cpp/src/test/tinyxml/tinyxml.h b/gfx/sfntly/cpp/src/test/tinyxml/tinyxml.h new file mode 100644 index 0000000000..a3589e5b26 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/tinyxml/tinyxml.h @@ -0,0 +1,1805 @@ +/* +www.sourceforge.net/projects/tinyxml +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + + +#ifndef TINYXML_INCLUDED +#define TINYXML_INCLUDED + +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4530 ) +#pragma warning( disable : 4786 ) +#endif + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +// Help out windows: +#if defined( _DEBUG ) && !defined( DEBUG ) +#define DEBUG +#endif + +#ifdef TIXML_USE_STL + #include <string> + #include <iostream> + #include <sstream> + #define TIXML_STRING std::string +#else + #include "tinystr.h" + #define TIXML_STRING TiXmlString +#endif + +// Deprecated library function hell. Compilers want to use the +// new safe versions. This probably doesn't fully address the problem, +// but it gets closer. There are too many compilers for me to fully +// test. If you get compilation troubles, undefine TIXML_SAFE +#define TIXML_SAFE + +#ifdef TIXML_SAFE + #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) + // Microsoft visual studio, version 2005 and higher. + #define TIXML_SNPRINTF _snprintf_s + #define TIXML_SSCANF sscanf_s + #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) + // Microsoft visual studio, version 6 and higher. + //#pragma message( "Using _sn* functions." ) + #define TIXML_SNPRINTF _snprintf + #define TIXML_SSCANF sscanf + #elif defined(__GNUC__) && (__GNUC__ >= 3 ) + // GCC version 3 and higher.s + //#warning( "Using sn* functions." ) + #define TIXML_SNPRINTF snprintf + #define TIXML_SSCANF sscanf + #else + #define TIXML_SNPRINTF snprintf + #define TIXML_SSCANF sscanf + #endif +#endif + +class TiXmlDocument; +class TiXmlElement; +class TiXmlComment; +class TiXmlUnknown; +class TiXmlAttribute; +class TiXmlText; +class TiXmlDeclaration; +class TiXmlParsingData; + +const int TIXML_MAJOR_VERSION = 2; +const int TIXML_MINOR_VERSION = 6; +const int TIXML_PATCH_VERSION = 2; + +/* Internal structure for tracking location of items + in the XML file. +*/ +struct TiXmlCursor +{ + TiXmlCursor() { Clear(); } + void Clear() { row = col = -1; } + + int row; // 0 based. + int col; // 0 based. +}; + + +/** + Implements the interface to the "Visitor pattern" (see the Accept() method.) + If you call the Accept() method, it requires being passed a TiXmlVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves + are simply called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, <b>no children of this node or its sibilings</b> will be Visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting. + + You should never change the document from a callback. + + @sa TiXmlNode::Accept() +*/ +class TiXmlVisitor +{ +public: + virtual ~TiXmlVisitor() {} + + /// Visit a document. + virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; } + /// Visit a document. + virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; } + + /// Visit an element. + virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; } + /// Visit an element. + virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; } + + /// Visit a declaration + virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; } + /// Visit a text node + virtual bool Visit( const TiXmlText& /*text*/ ) { return true; } + /// Visit a comment node + virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; } + /// Visit an unknown node + virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; } +}; + +// Only used by Attribute::Query functions +enum +{ + TIXML_SUCCESS, + TIXML_NO_ATTRIBUTE, + TIXML_WRONG_TYPE +}; + + +// Used by the parsing routines. +enum TiXmlEncoding +{ + TIXML_ENCODING_UNKNOWN, + TIXML_ENCODING_UTF8, + TIXML_ENCODING_LEGACY +}; + +const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; + +/** TiXmlBase is a base class for every class in TinyXml. + It does little except to establish that TinyXml classes + can be printed and provide some utility functions. + + In XML, the document and elements can contain + other elements and other types of nodes. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + A Decleration contains: Attributes (not on tree) + @endverbatim +*/ +class TiXmlBase +{ + friend class TiXmlNode; + friend class TiXmlElement; + friend class TiXmlDocument; + +public: + TiXmlBase() : userData(0) {} + virtual ~TiXmlBase() {} + + /** All TinyXml classes can print themselves to a filestream + or the string class (TiXmlString in non-STL mode, std::string + in STL mode.) Either or both cfile and str can be null. + + This is a formatted print, and will insert + tabs and newlines. + + (For an unformatted stream, use the << operator.) + */ + virtual void Print( FILE* cfile, int depth ) const = 0; + + /** The world does not agree on whether white space should be kept or + not. In order to make everyone happy, these global, static functions + are provided to set whether or not TinyXml will condense all white space + into a single space or not. The default is to condense. Note changing this + value is not thread safe. + */ + static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } + + /// Return the current white space setting. + static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } + + /** Return the position, in the original source file, of this node or attribute. + The row and column are 1-based. (That is the first row and first column is + 1,1). If the returns values are 0 or less, then the parser does not have + a row and column value. + + Generally, the row and column value will be set when the TiXmlDocument::Load(), + TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set + when the DOM was created from operator>>. + + The values reflect the initial load. Once the DOM is modified programmatically + (by adding or changing nodes and attributes) the new values will NOT update to + reflect changes in the document. + + There is a minor performance cost to computing the row and column. Computation + can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. + + @sa TiXmlDocument::SetTabSize() + */ + int Row() const { return location.row + 1; } + int Column() const { return location.col + 1; } ///< See Row() + + void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data. + void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data. + const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data. + + // Table that returs, for a given lead byte, the total number of bytes + // in the UTF-8 sequence. + static const int utf8ByteTable[256]; + + virtual const char* Parse( const char* p, + TiXmlParsingData* data, + TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; + + /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc, + or they will be transformed into entities! + */ + static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out ); + + enum + { + TIXML_NO_ERROR = 0, + TIXML_ERROR, + TIXML_ERROR_OPENING_FILE, + TIXML_ERROR_PARSING_ELEMENT, + TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, + TIXML_ERROR_READING_ELEMENT_VALUE, + TIXML_ERROR_READING_ATTRIBUTES, + TIXML_ERROR_PARSING_EMPTY, + TIXML_ERROR_READING_END_TAG, + TIXML_ERROR_PARSING_UNKNOWN, + TIXML_ERROR_PARSING_COMMENT, + TIXML_ERROR_PARSING_DECLARATION, + TIXML_ERROR_DOCUMENT_EMPTY, + TIXML_ERROR_EMBEDDED_NULL, + TIXML_ERROR_PARSING_CDATA, + TIXML_ERROR_DOCUMENT_TOP_ONLY, + + TIXML_ERROR_STRING_COUNT + }; + +protected: + + static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); + + inline static bool IsWhiteSpace( char c ) + { + return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); + } + inline static bool IsWhiteSpace( int c ) + { + if ( c < 256 ) + return IsWhiteSpace( (char) c ); + return false; // Again, only truly correct for English/Latin...but usually works. + } + + #ifdef TIXML_USE_STL + static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ); + static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag ); + #endif + + /* Reads an XML name into the string provided. Returns + a pointer just past the last character of the name, + or 0 if the function has an error. + */ + static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); + + /* Reads text. Returns a pointer past the given end tag. + Wickedly complex options, but it keeps the (sensitive) code in one place. + */ + static const char* ReadText( const char* in, // where to start + TIXML_STRING* text, // the string read + bool ignoreWhiteSpace, // whether to keep the white space + const char* endTag, // what ends this text + bool ignoreCase, // whether to ignore case in the end tag + TiXmlEncoding encoding ); // the current encoding + + // If an entity has been found, transform it into a character. + static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); + + // Get a character, while interpreting entities. + // The length can be from 0 to 4 bytes. + inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) + { + assert( p ); + if ( encoding == TIXML_ENCODING_UTF8 ) + { + *length = utf8ByteTable[ *((const unsigned char*)p) ]; + assert( *length >= 0 && *length < 5 ); + } + else + { + *length = 1; + } + + if ( *length == 1 ) + { + if ( *p == '&' ) + return GetEntity( p, _value, length, encoding ); + *_value = *p; + return p+1; + } + else if ( *length ) + { + //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), + // and the null terminator isn't needed + for( int i=0; p[i] && i<*length; ++i ) { + _value[i] = p[i]; + } + return p + (*length); + } + else + { + // Not valid text. + return 0; + } + } + + // Return true if the next characters in the stream are any of the endTag sequences. + // Ignore case only works for english, and should only be relied on when comparing + // to English words: StringEqual( p, "version", true ) is fine. + static bool StringEqual( const char* p, + const char* endTag, + bool ignoreCase, + TiXmlEncoding encoding ); + + static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; + + TiXmlCursor location; + + /// Field containing a generic user pointer + void* userData; + + // None of these methods are reliable for any language except English. + // Good for approximation, not great for accuracy. + static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); + static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); + inline static int ToLower( int v, TiXmlEncoding encoding ) + { + if ( encoding == TIXML_ENCODING_UTF8 ) + { + if ( v < 128 ) return tolower( v ); + return v; + } + else + { + return tolower( v ); + } + } + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); + +private: + TiXmlBase( const TiXmlBase& ); // not implemented. + void operator=( const TiXmlBase& base ); // not allowed. + + struct Entity + { + const char* str; + unsigned int strLength; + char chr; + }; + enum + { + NUM_ENTITY = 5, + MAX_ENTITY_LENGTH = 6 + + }; + static Entity entity[ NUM_ENTITY ]; + static bool condenseWhiteSpace; +}; + + +/** The parent class for everything in the Document Object Model. + (Except for attributes). + Nodes have siblings, a parent, and children. A node can be + in a document, or stand on its own. The type of a TiXmlNode + can be queried, and it can be cast to its more defined type. +*/ +class TiXmlNode : public TiXmlBase +{ + friend class TiXmlDocument; + friend class TiXmlElement; + +public: + #ifdef TIXML_USE_STL + + /** An input stream operator, for every class. Tolerant of newlines and + formatting, but doesn't expect them. + */ + friend std::istream& operator >> (std::istream& in, TiXmlNode& base); + + /** An output stream operator, for every class. Note that this outputs + without any newlines or formatting, as opposed to Print(), which + includes tabs and new lines. + + The operator<< and operator>> are not completely symmetric. Writing + a node to a stream is very well defined. You'll get a nice stream + of output, without any extra whitespace or newlines. + + But reading is not as well defined. (As it always is.) If you create + a TiXmlElement (for example) and read that from an input stream, + the text needs to define an element or junk will result. This is + true of all input streams, but it's worth keeping in mind. + + A TiXmlDocument will read nodes until it reads a root element, and + all the children of that root element. + */ + friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); + + /// Appends the XML node or attribute to a std::string. + friend std::string& operator<< (std::string& out, const TiXmlNode& base ); + + #endif + + /** The types of XML nodes supported by TinyXml. (All the + unsupported types are picked up by UNKNOWN.) + */ + enum NodeType + { + TINYXML_DOCUMENT, + TINYXML_ELEMENT, + TINYXML_COMMENT, + TINYXML_UNKNOWN, + TINYXML_TEXT, + TINYXML_DECLARATION, + TINYXML_TYPECOUNT + }; + + virtual ~TiXmlNode(); + + /** The meaning of 'value' changes for the specific type of + TiXmlNode. + @verbatim + Document: filename of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + + The subclasses will wrap this function. + */ + const char *Value() const { return value.c_str (); } + + #ifdef TIXML_USE_STL + /** Return Value() as a std::string. If you only use STL, + this is more efficient than calling Value(). + Only available in STL mode. + */ + const std::string& ValueStr() const { return value; } + #endif + + const TIXML_STRING& ValueTStr() const { return value; } + + /** Changes the value of the node. Defined as: + @verbatim + Document: filename of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + void SetValue(const char * _value) { value = _value;} + + #ifdef TIXML_USE_STL + /// STL std::string form. + void SetValue( const std::string& _value ) { value = _value; } + #endif + + /// Delete all the children of this node. Does not affect 'this'. + void Clear(); + + /// One step up the DOM. + TiXmlNode* Parent() { return parent; } + const TiXmlNode* Parent() const { return parent; } + + const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. + TiXmlNode* FirstChild() { return firstChild; } + const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. + /// The first child of this node with the matching 'value'. Will be null if none found. + TiXmlNode* FirstChild( const char * _value ) { + // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) + // call the method, cast the return back to non-const. + return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value )); + } + const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. + TiXmlNode* LastChild() { return lastChild; } + + const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. + TiXmlNode* LastChild( const char * _value ) { + return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value )); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form. + const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form. + #endif + + /** An alternate way to walk the children of a node. + One way to iterate over nodes is: + @verbatim + for( child = parent->FirstChild(); child; child = child->NextSibling() ) + @endverbatim + + IterateChildren does the same thing with the syntax: + @verbatim + child = 0; + while( child = parent->IterateChildren( child ) ) + @endverbatim + + IterateChildren takes the previous child as input and finds + the next one. If the previous child is null, it returns the + first. IterateChildren will return null when done. + */ + const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const; + TiXmlNode* IterateChildren( const TiXmlNode* previous ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) ); + } + + /// This flavor of IterateChildren searches for children with a particular 'value' + const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const; + TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. + TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. + #endif + + /** Add a new node related to this. Adds a child past the LastChild. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); + + + /** Add a new node related to this. Adds a child past the LastChild. + + NOTE: the node to be added is passed by pointer, and will be + henceforth owned (and deleted) by tinyXml. This method is efficient + and avoids an extra copy, but should be used with care as it + uses a different memory model than the other insert functions. + + @sa InsertEndChild + */ + TiXmlNode* LinkEndChild( TiXmlNode* addThis ); + + /** Add a new node related to this. Adds a child before the specified child. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); + + /** Add a new node related to this. Adds a child after the specified child. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); + + /** Replace a child of this node. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); + + /// Delete a child of this node. + bool RemoveChild( TiXmlNode* removeThis ); + + /// Navigate to a sibling node. + const TiXmlNode* PreviousSibling() const { return prev; } + TiXmlNode* PreviousSibling() { return prev; } + + /// Navigate to a sibling node. + const TiXmlNode* PreviousSibling( const char * ) const; + TiXmlNode* PreviousSibling( const char *_prev ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. + const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form. + #endif + + /// Navigate to a sibling node. + const TiXmlNode* NextSibling() const { return next; } + TiXmlNode* NextSibling() { return next; } + + /// Navigate to a sibling node with the given 'value'. + const TiXmlNode* NextSibling( const char * ) const; + TiXmlNode* NextSibling( const char* _next ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) ); + } + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + const TiXmlElement* NextSiblingElement() const; + TiXmlElement* NextSiblingElement() { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() ); + } + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + const TiXmlElement* NextSiblingElement( const char * ) const; + TiXmlElement* NextSiblingElement( const char *_next ) { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. + TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. + #endif + + /// Convenience function to get through elements. + const TiXmlElement* FirstChildElement() const; + TiXmlElement* FirstChildElement() { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() ); + } + + /// Convenience function to get through elements. + const TiXmlElement* FirstChildElement( const char * _value ) const; + TiXmlElement* FirstChildElement( const char * _value ) { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. + TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. + #endif + + /** Query the type (as an enumerated value, above) of this node. + The possible types are: TINYXML_DOCUMENT, TINYXML_ELEMENT, TINYXML_COMMENT, + TINYXML_UNKNOWN, TINYXML_TEXT, and TINYXML_DECLARATION. + */ + int Type() const { return type; } + + /** Return a pointer to the Document this node lives in. + Returns null if not in a document. + */ + const TiXmlDocument* GetDocument() const; + TiXmlDocument* GetDocument() { + return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() ); + } + + /// Returns true if this node has no children. + bool NoChildren() const { return !firstChild; } + + virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + + virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + + /** Create an exact duplicate of this node and return it. The memory must be deleted + by the caller. + */ + virtual TiXmlNode* Clone() const = 0; + + /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the TiXmlVisitor interface. + + This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + TiXmlPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept( TiXmlVisitor* visitor ) const = 0; + +protected: + TiXmlNode( NodeType _type ); + + // Copy to the allocated object. Shared functionality between Clone, Copy constructor, + // and the assignment operator. + void CopyTo( TiXmlNode* target ) const; + + #ifdef TIXML_USE_STL + // The real work of the input operator. + virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0; + #endif + + // Figure out what is at *p, and parse it. Returns null if it is not an xml node. + TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); + + TiXmlNode* parent; + NodeType type; + + TiXmlNode* firstChild; + TiXmlNode* lastChild; + + TIXML_STRING value; + + TiXmlNode* prev; + TiXmlNode* next; + +private: + TiXmlNode( const TiXmlNode& ); // not implemented. + void operator=( const TiXmlNode& base ); // not allowed. +}; + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not TiXmlNodes, since they are not + part of the tinyXML document object model. There are other + suggested ways to look at this problem. +*/ +class TiXmlAttribute : public TiXmlBase +{ + friend class TiXmlAttributeSet; + +public: + /// Construct an empty attribute. + TiXmlAttribute() : TiXmlBase() + { + document = 0; + prev = next = 0; + } + + #ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlAttribute( const std::string& _name, const std::string& _value ) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } + #endif + + /// Construct an attribute with a name and value. + TiXmlAttribute( const char * _name, const char * _value ) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } + + const char* Name() const { return name.c_str(); } ///< Return the name of this attribute. + const char* Value() const { return value.c_str(); } ///< Return the value of this attribute. + #ifdef TIXML_USE_STL + const std::string& ValueStr() const { return value; } ///< Return the value of this attribute. + #endif + int IntValue() const; ///< Return the value of this attribute, converted to an integer. + double DoubleValue() const; ///< Return the value of this attribute, converted to a double. + + // Get the tinyxml string representation + const TIXML_STRING& NameTStr() const { return name; } + + /** QueryIntValue examines the value string. It is an alternative to the + IntValue() method with richer error checking. + If the value is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. + + A specialized but useful call. Note that for success it returns 0, + which is the opposite of almost all other TinyXml calls. + */ + int QueryIntValue( int* _value ) const; + /// QueryDoubleValue examines the value string. See QueryIntValue(). + int QueryDoubleValue( double* _value ) const; + + void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. + void SetValue( const char* _value ) { value = _value; } ///< Set the value. + + void SetIntValue( int _value ); ///< Set the value from an integer. + void SetDoubleValue( double _value ); ///< Set the value from a double. + + #ifdef TIXML_USE_STL + /// STL std::string form. + void SetName( const std::string& _name ) { name = _name; } + /// STL std::string form. + void SetValue( const std::string& _value ) { value = _value; } + #endif + + /// Get the next sibling attribute in the DOM. Returns null at end. + const TiXmlAttribute* Next() const; + TiXmlAttribute* Next() { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); + } + + /// Get the previous sibling attribute in the DOM. Returns null at beginning. + const TiXmlAttribute* Previous() const; + TiXmlAttribute* Previous() { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); + } + + bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } + bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } + bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } + + /* Attribute parsing starts: first letter of the name + returns: the next char after the value end quote + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + // Prints this Attribute to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const { + Print( cfile, depth, 0 ); + } + void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; + + // [internal use] + // Set the document pointer so the attribute can report errors. + void SetDocument( TiXmlDocument* doc ) { document = doc; } + +private: + TiXmlAttribute( const TiXmlAttribute& ); // not implemented. + void operator=( const TiXmlAttribute& base ); // not allowed. + + TiXmlDocument* document; // A pointer back to a document, for error reporting. + TIXML_STRING name; + TIXML_STRING value; + TiXmlAttribute* prev; + TiXmlAttribute* next; +}; + + +/* A class used to manage a group of attributes. + It is only used internally, both by the ELEMENT and the DECLARATION. + + The set can be changed transparent to the Element and Declaration + classes that use it, but NOT transparent to the Attribute + which has to implement a next() and previous() method. Which makes + it a bit problematic and prevents the use of STL. + + This version is implemented with circular lists because: + - I like circular lists + - it demonstrates some independence from the (typical) doubly linked list. +*/ +class TiXmlAttributeSet +{ +public: + TiXmlAttributeSet(); + ~TiXmlAttributeSet(); + + void Add( TiXmlAttribute* attribute ); + void Remove( TiXmlAttribute* attribute ); + + const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } + TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } + const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } + TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } + + TiXmlAttribute* Find( const char* _name ) const; + TiXmlAttribute* FindOrCreate( const char* _name ); + +# ifdef TIXML_USE_STL + TiXmlAttribute* Find( const std::string& _name ) const; + TiXmlAttribute* FindOrCreate( const std::string& _name ); +# endif + + +private: + //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), + //*ME: this class must be also use a hidden/disabled copy-constructor !!! + TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed + void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute) + + TiXmlAttribute sentinel; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TiXmlElement : public TiXmlNode +{ +public: + /// Construct an element. + TiXmlElement (const char * in_value); + + #ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlElement( const std::string& _value ); + #endif + + TiXmlElement( const TiXmlElement& ); + + TiXmlElement& operator=( const TiXmlElement& base ); + + virtual ~TiXmlElement(); + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + */ + const char* Attribute( const char* name ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an integer, + the integer value will be put in the return 'i', if 'i' + is non-null. + */ + const char* Attribute( const char* name, int* i ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an double, + the double value will be put in the return 'd', if 'd' + is non-null. + */ + const char* Attribute( const char* name, double* d ) const; + + /** QueryIntAttribute examines the attribute - it is an alternative to the + Attribute() method with richer error checking. + If the attribute is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. If the attribute + does not exist, then TIXML_NO_ATTRIBUTE is returned. + */ + int QueryIntAttribute( const char* name, int* _value ) const; + /// QueryUnsignedAttribute examines the attribute - see QueryIntAttribute(). + int QueryUnsignedAttribute( const char* name, unsigned* _value ) const; + /** QueryBoolAttribute examines the attribute - see QueryIntAttribute(). + Note that '1', 'true', or 'yes' are considered true, while '0', 'false' + and 'no' are considered false. + */ + int QueryBoolAttribute( const char* name, bool* _value ) const; + /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). + int QueryDoubleAttribute( const char* name, double* _value ) const; + /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). + int QueryFloatAttribute( const char* name, float* _value ) const { + double d; + int result = QueryDoubleAttribute( name, &d ); + if ( result == TIXML_SUCCESS ) { + *_value = (float)d; + } + return result; + } + + #ifdef TIXML_USE_STL + /// QueryStringAttribute examines the attribute - see QueryIntAttribute(). + int QueryStringAttribute( const char* name, std::string* _value ) const { + const char* cstr = Attribute( name ); + if ( cstr ) { + *_value = std::string( cstr ); + return TIXML_SUCCESS; + } + return TIXML_NO_ATTRIBUTE; + } + + /** Template form of the attribute query which will try to read the + attribute into the specified type. Very easy, very powerful, but + be careful to make sure to call this with the correct type. + + NOTE: This method doesn't work correctly for 'string' types that contain spaces. + + @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE + */ + template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const + { + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + + std::stringstream sstream( node->ValueStr() ); + sstream >> *outValue; + if ( !sstream.fail() ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; + } + + int QueryValueAttribute( const std::string& name, std::string* outValue ) const + { + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + *outValue = node->ValueStr(); + return TIXML_SUCCESS; + } + #endif + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute( const char* name, const char * _value ); + + #ifdef TIXML_USE_STL + const std::string* Attribute( const std::string& name ) const; + const std::string* Attribute( const std::string& name, int* i ) const; + const std::string* Attribute( const std::string& name, double* d ) const; + int QueryIntAttribute( const std::string& name, int* _value ) const; + int QueryDoubleAttribute( const std::string& name, double* _value ) const; + + /// STL std::string form. + void SetAttribute( const std::string& name, const std::string& _value ); + ///< STL std::string form. + void SetAttribute( const std::string& name, int _value ); + ///< STL std::string form. + void SetDoubleAttribute( const std::string& name, double value ); + #endif + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute( const char * name, int value ); + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetDoubleAttribute( const char * name, double value ); + + /** Deletes an attribute with the given name. + */ + void RemoveAttribute( const char * name ); + #ifdef TIXML_USE_STL + void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. + #endif + + const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. + TiXmlAttribute* FirstAttribute() { return attributeSet.First(); } + const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. + TiXmlAttribute* LastAttribute() { return attributeSet.Last(); } + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the TiXmlText child + and accessing it directly. + + If the first child of 'this' is a TiXmlText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + <foo>This is text</foo> + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + <foo><b>This is text</b></foo> + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + <foo>This is <b>text</b></foo> + @endverbatim + GetText() will return "This is ". + + WARNING: GetText() accesses a child node - don't become confused with the + similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are + safe type casts on the referenced node. + */ + const char* GetText() const; + + /// Creates a new Element and returns it - the returned element is a copy. + virtual TiXmlNode* Clone() const; + // Print the Element to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /* Attribtue parsing starts: next char past '<' + returns: next char past '>' + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + + void CopyTo( TiXmlElement* target ) const; + void ClearThis(); // like clear, but initializes 'this' object as well + + // Used to be public [internal use] + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + /* [internal use] + Reads the "value" of the element -- another element, or text. + This should terminate with the current end tag. + */ + const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); + +private: + TiXmlAttributeSet attributeSet; +}; + + +/** An XML comment. +*/ +class TiXmlComment : public TiXmlNode +{ +public: + /// Constructs an empty comment. + TiXmlComment() : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) {} + /// Construct a comment from text. + TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) { + SetValue( _value ); + } + TiXmlComment( const TiXmlComment& ); + TiXmlComment& operator=( const TiXmlComment& base ); + + virtual ~TiXmlComment() {} + + /// Returns a copy of this Comment. + virtual TiXmlNode* Clone() const; + // Write this Comment to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /* Attribtue parsing starts: at the ! of the !-- + returns: next char past '>' + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + void CopyTo( TiXmlComment* target ) const; + + // used to be public + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif +// virtual void StreamOut( TIXML_OSTREAM * out ) const; + +private: + +}; + + +/** XML text. A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCDATA() and query it with CDATA(). +*/ +class TiXmlText : public TiXmlNode +{ + friend class TiXmlElement; +public: + /** Constructor for text element. By default, it is treated as + normal, encoded text. If you want it be output as a CDATA text + element, set the parameter _cdata to 'true' + */ + TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) + { + SetValue( initValue ); + cdata = false; + } + virtual ~TiXmlText() {} + + #ifdef TIXML_USE_STL + /// Constructor. + TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) + { + SetValue( initValue ); + cdata = false; + } + #endif + + TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TINYXML_TEXT ) { copy.CopyTo( this ); } + TiXmlText& operator=( const TiXmlText& base ) { base.CopyTo( this ); return *this; } + + // Write this text object to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /// Queries whether this represents text using a CDATA section. + bool CDATA() const { return cdata; } + /// Turns on or off a CDATA representation of text. + void SetCDATA( bool _cdata ) { cdata = _cdata; } + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected : + /// [internal use] Creates a new Element and returns it. + virtual TiXmlNode* Clone() const; + void CopyTo( TiXmlText* target ) const; + + bool Blank() const; // returns true if all white space and new lines + // [internal use] + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + bool cdata; // true if this should be input and output as a CDATA style text element +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + <?xml version="1.0" standalone="yes"?> + @endverbatim + + TinyXml will happily read or write files without a declaration, + however. There are 3 possible attributes to the declaration: + version, encoding, and standalone. + + Note: In this version of the code, the attributes are + handled as special cases, not generic attributes, simply + because there can only be at most 3 and they are always the same. +*/ +class TiXmlDeclaration : public TiXmlNode +{ +public: + /// Construct an empty declaration. + TiXmlDeclaration() : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) {} + +#ifdef TIXML_USE_STL + /// Constructor. + TiXmlDeclaration( const std::string& _version, + const std::string& _encoding, + const std::string& _standalone ); +#endif + + /// Construct. + TiXmlDeclaration( const char* _version, + const char* _encoding, + const char* _standalone ); + + TiXmlDeclaration( const TiXmlDeclaration& copy ); + TiXmlDeclaration& operator=( const TiXmlDeclaration& copy ); + + virtual ~TiXmlDeclaration() {} + + /// Version. Will return an empty string if none was found. + const char *Version() const { return version.c_str (); } + /// Encoding. Will return an empty string if none was found. + const char *Encoding() const { return encoding.c_str (); } + /// Is this a standalone document? + const char *Standalone() const { return standalone.c_str (); } + + /// Creates a copy of this Declaration and returns it. + virtual TiXmlNode* Clone() const; + // Print this declaration to a FILE stream. + virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; + virtual void Print( FILE* cfile, int depth ) const { + Print( cfile, depth, 0 ); + } + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + void CopyTo( TiXmlDeclaration* target ) const; + // used to be public + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + + TIXML_STRING version; + TIXML_STRING encoding; + TIXML_STRING standalone; +}; + + +/** Any tag that tinyXml doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into TiXmlUnknowns. +*/ +class TiXmlUnknown : public TiXmlNode +{ +public: + TiXmlUnknown() : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) {} + virtual ~TiXmlUnknown() {} + + TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) { copy.CopyTo( this ); } + TiXmlUnknown& operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); return *this; } + + /// Creates a copy of this Unknown and returns it. + virtual TiXmlNode* Clone() const; + // Print this Unknown to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected: + void CopyTo( TiXmlUnknown* target ) const; + + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + +}; + + +/** Always the top level node. A document binds together all the + XML pieces. It can be saved, loaded, and printed to the screen. + The 'value' of a document node is the xml file name. +*/ +class TiXmlDocument : public TiXmlNode +{ +public: + /// Create an empty document, that has no name. + TiXmlDocument(); + /// Create a document with a name. The name of the document is also the filename of the xml. + TiXmlDocument( const char * documentName ); + + #ifdef TIXML_USE_STL + /// Constructor. + TiXmlDocument( const std::string& documentName ); + #endif + + TiXmlDocument( const TiXmlDocument& copy ); + TiXmlDocument& operator=( const TiXmlDocument& copy ); + + virtual ~TiXmlDocument() {} + + /** Load a file using the current document value. + Returns true if successful. Will delete any existing + document data before loading. + */ + bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the current document value. Returns true if successful. + bool SaveFile() const; + /// Load a file using the given filename. Returns true if successful. + bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the given filename. Returns true if successful. + bool SaveFile( const char * filename ) const; + /** Load a file using the given FILE*. Returns true if successful. Note that this method + doesn't stream - the entire object pointed at by the FILE* + will be interpreted as an XML file. TinyXML doesn't stream in XML from the current + file location. Streaming may be added in the future. + */ + bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the given FILE*. Returns true if successful. + bool SaveFile( FILE* ) const; + + #ifdef TIXML_USE_STL + bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. + { + return LoadFile( filename.c_str(), encoding ); + } + bool SaveFile( const std::string& filename ) const ///< STL std::string version. + { + return SaveFile( filename.c_str() ); + } + #endif + + /** Parse the given null terminated block of xml data. Passing in an encoding to this + method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml + to use that encoding, regardless of what TinyXml might otherwise try to detect. + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + + /** Get the root element -- the only top level element -- of the document. + In well formed XML, there should only be one. TinyXml is tolerant of + multiple elements at the document level. + */ + const TiXmlElement* RootElement() const { return FirstChildElement(); } + TiXmlElement* RootElement() { return FirstChildElement(); } + + /** If an error occurs, Error will be set to true. Also, + - The ErrorId() will contain the integer identifier of the error (not generally useful) + - The ErrorDesc() method will return the name of the error. (very useful) + - The ErrorRow() and ErrorCol() will return the location of the error (if known) + */ + bool Error() const { return error; } + + /// Contains a textual (english) description of the error if one occurs. + const char * ErrorDesc() const { return errorDesc.c_str (); } + + /** Generally, you probably want the error string ( ErrorDesc() ). But if you + prefer the ErrorId, this function will fetch it. + */ + int ErrorId() const { return errorId; } + + /** Returns the location (if known) of the error. The first column is column 1, + and the first row is row 1. A value of 0 means the row and column wasn't applicable + (memory errors, for example, have no row/column) or the parser lost the error. (An + error in the error reporting, in that case.) + + @sa SetTabSize, Row, Column + */ + int ErrorRow() const { return errorLocation.row+1; } + int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() + + /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) + to report the correct values for row and column. It does not change the output + or input in any way. + + By calling this method, with a tab size + greater than 0, the row and column of each node and attribute is stored + when the file is loaded. Very useful for tracking the DOM back in to + the source file. + + The tab size is required for calculating the location of nodes. If not + set, the default of 4 is used. The tabsize is set per document. Setting + the tabsize to 0 disables row/column tracking. + + Note that row and column tracking is not supported when using operator>>. + + The tab size needs to be enabled before the parse or load. Correct usage: + @verbatim + TiXmlDocument doc; + doc.SetTabSize( 8 ); + doc.Load( "myfile.xml" ); + @endverbatim + + @sa Row, Column + */ + void SetTabSize( int _tabsize ) { tabsize = _tabsize; } + + int TabSize() const { return tabsize; } + + /** If you have handled the error, it can be reset with this call. The error + state is automatically cleared if you Parse a new XML block. + */ + void ClearError() { error = false; + errorId = 0; + errorDesc = ""; + errorLocation.row = errorLocation.col = 0; + //errorLocation.last = 0; + } + + /** Write the document to standard out using formatted printing ("pretty print"). */ + void Print() const { Print( stdout, 0 ); } + + /* Write the document to a string using formatted printing ("pretty print"). This + will allocate a character array (new char[]) and return it as a pointer. The + calling code pust call delete[] on the return char* to avoid a memory leak. + */ + //char* PrintToMemory() const; + + /// Print this Document to a FILE stream. + virtual void Print( FILE* cfile, int depth = 0 ) const; + // [internal use] + void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); + + virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected : + // [internal use] + virtual TiXmlNode* Clone() const; + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + void CopyTo( TiXmlDocument* target ) const; + + bool error; + int errorId; + TIXML_STRING errorDesc; + int tabsize; + TiXmlCursor errorLocation; + bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. +}; + + +/** + A TiXmlHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + <Document> + <Element attributeA = "valueA"> + <Child attributeB = "value1" /> + <Child attributeB = "value2" /> + </Element> + <Document> + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + TiXmlElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + TiXmlElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + TiXmlElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + TiXmlElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity + of such code. A TiXmlHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + TiXmlHandle docHandle( &document ); + TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + TiXmlHandle handleCopy = handle; + @endverbatim + + What they should not be used for is iteration: + + @verbatim + int i=0; + while ( true ) + { + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); + if ( !child ) + break; + // do something + ++i; + } + @endverbatim + + It seems reasonable, but it is in fact two embedded while loops. The Child method is + a linear walk to find the element, so this code would iterate much more than it needs + to. Instead, prefer: + + @verbatim + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); + + for( child; child; child=child->NextSiblingElement() ) + { + // do something + } + @endverbatim +*/ +class TiXmlHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } + /// Copy constructor + TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } + TiXmlHandle operator=( const TiXmlHandle& ref ) { if ( &ref != this ) this->node = ref.node; return *this; } + + /// Return a handle to the first child node. + TiXmlHandle FirstChild() const; + /// Return a handle to the first child node with the given name. + TiXmlHandle FirstChild( const char * value ) const; + /// Return a handle to the first child element. + TiXmlHandle FirstChildElement() const; + /// Return a handle to the first child element with the given name. + TiXmlHandle FirstChildElement( const char * value ) const; + + /** Return a handle to the "index" child with the given name. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child( const char* value, int index ) const; + /** Return a handle to the "index" child. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child( int index ) const; + /** Return a handle to the "index" child element with the given name. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement( const char* value, int index ) const; + /** Return a handle to the "index" child element. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement( int index ) const; + + #ifdef TIXML_USE_STL + TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } + TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } + + TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } + TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } + #endif + + /** Return the handle as a TiXmlNode. This may return null. + */ + TiXmlNode* ToNode() const { return node; } + /** Return the handle as a TiXmlElement. This may return null. + */ + TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } + /** Return the handle as a TiXmlText. This may return null. + */ + TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } + /** Return the handle as a TiXmlUnknown. This may return null. + */ + TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } + + /** @deprecated use ToNode. + Return the handle as a TiXmlNode. This may return null. + */ + TiXmlNode* Node() const { return ToNode(); } + /** @deprecated use ToElement. + Return the handle as a TiXmlElement. This may return null. + */ + TiXmlElement* Element() const { return ToElement(); } + /** @deprecated use ToText() + Return the handle as a TiXmlText. This may return null. + */ + TiXmlText* Text() const { return ToText(); } + /** @deprecated use ToUnknown() + Return the handle as a TiXmlUnknown. This may return null. + */ + TiXmlUnknown* Unknown() const { return ToUnknown(); } + +private: + TiXmlNode* node; +}; + + +/** Print to memory functionality. The TiXmlPrinter is useful when you need to: + + -# Print to memory (especially in non-STL mode) + -# Control formatting (line endings, etc.) + + When constructed, the TiXmlPrinter is in its default "pretty printing" mode. + Before calling Accept() you can call methods to control the printing + of the XML document. After TiXmlNode::Accept() is called, the printed document can + be accessed via the CStr(), Str(), and Size() methods. + + TiXmlPrinter uses the Visitor API. + @verbatim + TiXmlPrinter printer; + printer.SetIndent( "\t" ); + + doc.Accept( &printer ); + fprintf( stdout, "%s", printer.CStr() ); + @endverbatim +*/ +class TiXmlPrinter : public TiXmlVisitor +{ +public: + TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ), + buffer(), indent( " " ), lineBreak( "\n" ) {} + + virtual bool VisitEnter( const TiXmlDocument& doc ); + virtual bool VisitExit( const TiXmlDocument& doc ); + + virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ); + virtual bool VisitExit( const TiXmlElement& element ); + + virtual bool Visit( const TiXmlDeclaration& declaration ); + virtual bool Visit( const TiXmlText& text ); + virtual bool Visit( const TiXmlComment& comment ); + virtual bool Visit( const TiXmlUnknown& unknown ); + + /** Set the indent characters for printing. By default 4 spaces + but tab (\t) is also useful, or null/empty string for no indentation. + */ + void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; } + /// Query the indention string. + const char* Indent() { return indent.c_str(); } + /** Set the line breaking string. By default set to newline (\n). + Some operating systems prefer other characters, or can be + set to the null/empty string for no indenation. + */ + void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; } + /// Query the current line breaking string. + const char* LineBreak() { return lineBreak.c_str(); } + + /** Switch over to "stream printing" which is the most dense formatting without + linebreaks. Common when the XML is needed for network transmission. + */ + void SetStreamPrinting() { indent = ""; + lineBreak = ""; + } + /// Return the result. + const char* CStr() { return buffer.c_str(); } + /// Return the length of the result string. + size_t Size() { return buffer.size(); } + + #ifdef TIXML_USE_STL + /// Return the result. + const std::string& Str() { return buffer; } + #endif + +private: + void DoIndent() { + for( int i=0; i<depth; ++i ) + buffer += indent; + } + void DoLineBreak() { + buffer += lineBreak; + } + + int depth; + bool simpleTextPrint; + TIXML_STRING buffer; + TIXML_STRING indent; + TIXML_STRING lineBreak; +}; + + +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + +#endif diff --git a/gfx/sfntly/cpp/src/test/tinyxml/tinyxmlerror.cpp b/gfx/sfntly/cpp/src/test/tinyxml/tinyxmlerror.cpp new file mode 100644 index 0000000000..538c21d0bd --- /dev/null +++ b/gfx/sfntly/cpp/src/test/tinyxml/tinyxmlerror.cpp @@ -0,0 +1,52 @@ +/* +www.sourceforge.net/projects/tinyxml +Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "tinyxml.h" + +// The goal of the seperate error file is to make the first +// step towards localization. tinyxml (currently) only supports +// english error messages, but the could now be translated. +// +// It also cleans up the code a bit. +// + +const char* TiXmlBase::errorString[ TiXmlBase::TIXML_ERROR_STRING_COUNT ] = +{ + "No error", + "Error", + "Failed to open file", + "Error parsing Element.", + "Failed to read Element name", + "Error reading Element value.", + "Error reading Attributes.", + "Error: empty tag.", + "Error reading end tag.", + "Error parsing Unknown.", + "Error parsing Comment.", + "Error parsing Declaration.", + "Error document empty.", + "Error null (0) or unexpected EOF found in input stream.", + "Error parsing CDATA.", + "Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.", +}; diff --git a/gfx/sfntly/cpp/src/test/tinyxml/tinyxmlparser.cpp b/gfx/sfntly/cpp/src/test/tinyxml/tinyxmlparser.cpp new file mode 100644 index 0000000000..81b7eae96b --- /dev/null +++ b/gfx/sfntly/cpp/src/test/tinyxml/tinyxmlparser.cpp @@ -0,0 +1,1638 @@ +/* +www.sourceforge.net/projects/tinyxml +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include <ctype.h> +#include <stddef.h> + +#include "tinyxml.h" + +//#define DEBUG_PARSER +#if defined( DEBUG_PARSER ) +# if defined( DEBUG ) && defined( _MSC_VER ) +# include <windows.h> +# define TIXML_LOG OutputDebugString +# else +# define TIXML_LOG printf +# endif +#endif + +// Note tha "PutString" hardcodes the same list. This +// is less flexible than it appears. Changing the entries +// or order will break putstring. +TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = +{ + { "&", 5, '&' }, + { "<", 4, '<' }, + { ">", 4, '>' }, + { """, 6, '\"' }, + { "'", 6, '\'' } +}; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// Including the basic of this table, which determines the #bytes in the +// sequence from the lead byte. 1 placed for invalid sequences -- +// although the result will be junk, pass it through as much as possible. +// Beware of the non-characters in UTF-8: +// ef bb bf (Microsoft "lead bytes") +// ef bf be +// ef bf bf + +const unsigned char TIXML_UTF_LEAD_0 = 0xefU; +const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; +const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + +const int TiXmlBase::utf8ByteTable[256] = +{ + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 + 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte + 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid +}; + + +void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) +{ + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) + *length = 1; + else if ( input < 0x800 ) + *length = 2; + else if ( input < 0x10000 ) + *length = 3; + else if ( input < 0x200000 ) + *length = 4; + else + { *length = 0; return; } // This code won't covert this correctly anyway. + + output += *length; + + // Scary scary fall throughs. + switch (*length) + { + case 4: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 3: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 2: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 1: + --output; + *output = (char)(input | FIRST_BYTE_MARK[*length]); + } +} + + +/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) +{ + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. + +// if ( encoding == TIXML_ENCODING_UTF8 ) +// { + if ( anyByte < 127 ) + return isalpha( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. +// } +// else +// { +// return isalpha( anyByte ); +// } +} + + +/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) +{ + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. + +// if ( encoding == TIXML_ENCODING_UTF8 ) +// { + if ( anyByte < 127 ) + return isalnum( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. +// } +// else +// { +// return isalnum( anyByte ); +// } +} + + +class TiXmlParsingData +{ + friend class TiXmlDocument; + public: + void Stamp( const char* now, TiXmlEncoding encoding ); + + const TiXmlCursor& Cursor() const { return cursor; } + + private: + // Only used by the document! + TiXmlParsingData( const char* start, int _tabsize, int row, int col ) + { + assert( start ); + stamp = start; + tabsize = _tabsize; + cursor.row = row; + cursor.col = col; + } + + TiXmlCursor cursor; + const char* stamp; + int tabsize; +}; + + +void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) +{ + assert( now ); + + // Do nothing if the tabsize is 0. + if ( tabsize < 1 ) + { + return; + } + + // Get the current row, column. + int row = cursor.row; + int col = cursor.col; + const char* p = stamp; + assert( p ); + + while ( p < now ) + { + // Treat p as unsigned, so we have a happy compiler. + const unsigned char* pU = (const unsigned char*)p; + + // Code contributed by Fletcher Dunn: (modified by lee) + switch (*pU) { + case 0: + // We *should* never get here, but in case we do, don't + // advance past the terminating null character, ever + return; + + case '\r': + // bump down to the next line + ++row; + col = 0; + // Eat the character + ++p; + + // Check for \r\n sequence, and treat this as a single character + if (*p == '\n') { + ++p; + } + break; + + case '\n': + // bump down to the next line + ++row; + col = 0; + + // Eat the character + ++p; + + // Check for \n\r sequence, and treat this as a single + // character. (Yes, this bizarre thing does occur still + // on some arcane platforms...) + if (*p == '\r') { + ++p; + } + break; + + case '\t': + // Eat the character + ++p; + + // Skip to next tab stop + col = (col / tabsize + 1) * tabsize; + break; + + case TIXML_UTF_LEAD_0: + if ( encoding == TIXML_ENCODING_UTF8 ) + { + if ( *(p+1) && *(p+2) ) + { + // In these cases, don't advance the column. These are + // 0-width spaces. + if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) + p += 3; + else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) + p += 3; + else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) + p += 3; + else + { p +=3; ++col; } // A normal character. + } + } + else + { + ++p; + ++col; + } + break; + + default: + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // Eat the 1 to 4 byte utf8 character. + int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; + if ( step == 0 ) + step = 1; // Error case from bad encoding, but handle gracefully. + p += step; + + // Just advance one column, of course. + ++col; + } + else + { + ++p; + ++col; + } + break; + } + } + cursor.row = row; + cursor.col = col; + assert( cursor.row >= -1 ); + assert( cursor.col >= -1 ); + stamp = p; + assert( stamp ); +} + + +const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) +{ + if ( !p || !*p ) + { + return 0; + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + while ( *p ) + { + const unsigned char* pU = (const unsigned char*)p; + + // Skip the stupid Microsoft UTF-8 Byte order marks + if ( *(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==TIXML_UTF_LEAD_1 + && *(pU+2)==TIXML_UTF_LEAD_2 ) + { + p += 3; + continue; + } + else if(*(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==0xbfU + && *(pU+2)==0xbeU ) + { + p += 3; + continue; + } + else if(*(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==0xbfU + && *(pU+2)==0xbfU ) + { + p += 3; + continue; + } + + if ( IsWhiteSpace( *p ) ) // Still using old rules for white space. + ++p; + else + break; + } + } + else + { + while ( *p && IsWhiteSpace( *p ) ) + ++p; + } + + return p; +} + +#ifdef TIXML_USE_STL +/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) +{ + for( ;; ) + { + if ( !in->good() ) return false; + + int c = in->peek(); + // At this scope, we can't get to a document. So fail silently. + if ( !IsWhiteSpace( c ) || c <= 0 ) + return true; + + *tag += (char) in->get(); + } +} + +/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) +{ + //assert( character > 0 && character < 128 ); // else it won't work in utf-8 + while ( in->good() ) + { + int c = in->peek(); + if ( c == character ) + return true; + if ( c <= 0 ) // Silent failure: can't get document at this scope + return false; + + in->get(); + *tag += (char) c; + } + return false; +} +#endif + +// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The +// "assign" optimization removes over 10% of the execution time. +// +const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) +{ + // Oddly, not supported on some comilers, + //name->clear(); + // So use this: + *name = ""; + assert( p ); + + // Names start with letters or underscores. + // Of course, in unicode, tinyxml has no idea what a letter *is*. The + // algorithm is generous. + // + // After that, they can be letters, underscores, numbers, + // hyphens, or colons. (Colons are valid ony for namespaces, + // but tinyxml can't tell namespaces from names.) + if ( p && *p + && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) + { + const char* start = p; + while( p && *p + && ( IsAlphaNum( (unsigned char ) *p, encoding ) + || *p == '_' + || *p == '-' + || *p == '.' + || *p == ':' ) ) + { + //(*name) += *p; // expensive + ++p; + } + if ( p-start > 0 ) { + name->assign( start, p-start ); + } + return p; + } + return 0; +} + +const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) +{ + // Presume an entity, and pull it out. + TIXML_STRING ent; + int i; + *length = 0; + + if ( *(p+1) && *(p+1) == '#' && *(p+2) ) + { + unsigned long ucs = 0; + ptrdiff_t delta = 0; + unsigned mult = 1; + + if ( *(p+2) == 'x' ) + { + // Hexadecimal. + if ( !*(p+3) ) return 0; + + const char* q = p+3; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != 'x' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else if ( *q >= 'a' && *q <= 'f' ) + ucs += mult * (*q - 'a' + 10); + else if ( *q >= 'A' && *q <= 'F' ) + ucs += mult * (*q - 'A' + 10 ); + else + return 0; + mult *= 16; + --q; + } + } + else + { + // Decimal. + if ( !*(p+2) ) return 0; + + const char* q = p+2; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != '#' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else + return 0; + mult *= 10; + --q; + } + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + } + else + { + *value = (char)ucs; + *length = 1; + } + return p + delta + 1; + } + + // Now try to match it. + for( i=0; i<NUM_ENTITY; ++i ) + { + if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 ) + { + assert( strlen( entity[i].str ) == entity[i].strLength ); + *value = entity[i].chr; + *length = 1; + return ( p + entity[i].strLength ); + } + } + + // So it wasn't an entity, its unrecognized, or something like that. + *value = *p; // Don't put back the last one, since we return it! + //*length = 1; // Leave unrecognized entities - this doesn't really work. + // Just writes strange XML. + return p+1; +} + + +bool TiXmlBase::StringEqual( const char* p, + const char* tag, + bool ignoreCase, + TiXmlEncoding encoding ) +{ + assert( p ); + assert( tag ); + if ( !p || !*p ) + { + assert( 0 ); + return false; + } + + const char* q = p; + + if ( ignoreCase ) + { + while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) ) + { + ++q; + ++tag; + } + + if ( *tag == 0 ) + return true; + } + else + { + while ( *q && *tag && *q == *tag ) + { + ++q; + ++tag; + } + + if ( *tag == 0 ) // Have we found the end of the tag, and everything equal? + return true; + } + return false; +} + +const char* TiXmlBase::ReadText( const char* p, + TIXML_STRING * text, + bool trimWhiteSpace, + const char* endTag, + bool caseInsensitive, + TiXmlEncoding encoding ) +{ + *text = ""; + if ( !trimWhiteSpace // certain tags always keep whitespace + || !condenseWhiteSpace ) // if true, whitespace is always kept + { + // Keep all the white space. + while ( p && *p + && !StringEqual( p, endTag, caseInsensitive, encoding ) + ) + { + int len; + char cArr[4] = { 0, 0, 0, 0 }; + p = GetChar( p, cArr, &len, encoding ); + text->append( cArr, len ); + } + } + else + { + bool whitespace = false; + + // Remove leading white space: + p = SkipWhiteSpace( p, encoding ); + while ( p && *p + && !StringEqual( p, endTag, caseInsensitive, encoding ) ) + { + if ( *p == '\r' || *p == '\n' ) + { + whitespace = true; + ++p; + } + else if ( IsWhiteSpace( *p ) ) + { + whitespace = true; + ++p; + } + else + { + // If we've found whitespace, add it before the + // new character. Any whitespace just becomes a space. + if ( whitespace ) + { + (*text) += ' '; + whitespace = false; + } + int len; + char cArr[4] = { 0, 0, 0, 0 }; + p = GetChar( p, cArr, &len, encoding ); + if ( len == 1 ) + (*text) += cArr[0]; // more efficient + else + text->append( cArr, len ); + } + } + } + if ( p && *p ) + p += strlen( endTag ); + return ( p && *p ) ? p : 0; +} + +#ifdef TIXML_USE_STL + +void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + // The basic issue with a document is that we don't know what we're + // streaming. Read something presumed to be a tag (and hope), then + // identify it, and call the appropriate stream method on the tag. + // + // This "pre-streaming" will never read the closing ">" so the + // sub-tag can orient itself. + + if ( !StreamTo( in, '<', tag ) ) + { + SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + while ( in->good() ) + { + int tagIndex = (int) tag->length(); + while ( in->good() && in->peek() != '>' ) + { + int c = in->get(); + if ( c <= 0 ) + { + SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + break; + } + (*tag) += (char) c; + } + + if ( in->good() ) + { + // We now have something we presume to be a node of + // some sort. Identify it, and call the node to + // continue streaming. + TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); + + if ( node ) + { + node->StreamIn( in, tag ); + bool isElement = node->ToElement() != 0; + delete node; + node = 0; + + // If this is the root element, we're done. Parsing will be + // done by the >> operator. + if ( isElement ) + { + return; + } + } + else + { + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + } + } + // We should have returned sooner. + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); +} + +#endif + +const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) +{ + ClearError(); + + // Parse away, at the document level. Since a document + // contains nothing but other tags, most of what happens + // here is skipping white space. + if ( !p || !*p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + // Note that, for a document, this needs to come + // before the while space skip, so that parsing + // starts from the pointer we are given. + location.Clear(); + if ( prevData ) + { + location.row = prevData->cursor.row; + location.col = prevData->cursor.col; + } + else + { + location.row = 0; + location.col = 0; + } + TiXmlParsingData data( p, TabSize(), location.row, location.col ); + location = data.Cursor(); + + if ( encoding == TIXML_ENCODING_UNKNOWN ) + { + // Check for the Microsoft UTF-8 lead bytes. + const unsigned char* pU = (const unsigned char*)p; + if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 + && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 + && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) + { + encoding = TIXML_ENCODING_UTF8; + useMicrosoftBOM = true; + } + } + + p = SkipWhiteSpace( p, encoding ); + if ( !p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + while ( p && *p ) + { + TiXmlNode* node = Identify( p, encoding ); + if ( node ) + { + p = node->Parse( p, &data, encoding ); + LinkEndChild( node ); + } + else + { + break; + } + + // Did we get encoding info? + if ( encoding == TIXML_ENCODING_UNKNOWN + && node->ToDeclaration() ) + { + TiXmlDeclaration* dec = node->ToDeclaration(); + const char* enc = dec->Encoding(); + assert( enc ); + + if ( *enc == 0 ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice + else + encoding = TIXML_ENCODING_LEGACY; + } + + p = SkipWhiteSpace( p, encoding ); + } + + // Was this empty? + if ( !firstChild ) { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); + return 0; + } + + // All is well. + return p; +} + +void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + // The first error in a chain is more accurate - don't set again! + if ( error ) + return; + + assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); + error = true; + errorId = err; + errorDesc = errorString[ errorId ]; + + errorLocation.Clear(); + if ( pError && data ) + { + data->Stamp( pError, encoding ); + errorLocation = data->Cursor(); + } +} + + +TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) +{ + TiXmlNode* returnNode = 0; + + p = SkipWhiteSpace( p, encoding ); + if( !p || !*p || *p != '<' ) + { + return 0; + } + + p = SkipWhiteSpace( p, encoding ); + + if ( !p || !*p ) + { + return 0; + } + + // What is this thing? + // - Elements start with a letter or underscore, but xml is reserved. + // - Comments: <!-- + // - Decleration: <?xml + // - Everthing else is unknown to tinyxml. + // + + const char* xmlHeader = { "<?xml" }; + const char* commentHeader = { "<!--" }; + const char* dtdHeader = { "<!" }; + const char* cdataHeader = { "<![CDATA[" }; + + if ( StringEqual( p, xmlHeader, true, encoding ) ) + { + #ifdef DEBUG_PARSER + TIXML_LOG( "XML parsing Declaration\n" ); + #endif + returnNode = new TiXmlDeclaration(); + } + else if ( StringEqual( p, commentHeader, false, encoding ) ) + { + #ifdef DEBUG_PARSER + TIXML_LOG( "XML parsing Comment\n" ); + #endif + returnNode = new TiXmlComment(); + } + else if ( StringEqual( p, cdataHeader, false, encoding ) ) + { + #ifdef DEBUG_PARSER + TIXML_LOG( "XML parsing CDATA\n" ); + #endif + TiXmlText* text = new TiXmlText( "" ); + text->SetCDATA( true ); + returnNode = text; + } + else if ( StringEqual( p, dtdHeader, false, encoding ) ) + { + #ifdef DEBUG_PARSER + TIXML_LOG( "XML parsing Unknown(1)\n" ); + #endif + returnNode = new TiXmlUnknown(); + } + else if ( IsAlpha( *(p+1), encoding ) + || *(p+1) == '_' ) + { + #ifdef DEBUG_PARSER + TIXML_LOG( "XML parsing Element\n" ); + #endif + returnNode = new TiXmlElement( "" ); + } + else + { + #ifdef DEBUG_PARSER + TIXML_LOG( "XML parsing Unknown(2)\n" ); + #endif + returnNode = new TiXmlUnknown(); + } + + if ( returnNode ) + { + // Set the parent, so it can report errors + returnNode->parent = this; + } + return returnNode; +} + +#ifdef TIXML_USE_STL + +void TiXmlElement::StreamIn (std::istream * in, TIXML_STRING * tag) +{ + // We're called with some amount of pre-parsing. That is, some of "this" + // element is in "tag". Go ahead and stream to the closing ">" + while( in->good() ) + { + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + (*tag) += (char) c ; + + if ( c == '>' ) + break; + } + + if ( tag->length() < 3 ) return; + + // Okay...if we are a "/>" tag, then we're done. We've read a complete tag. + // If not, identify and stream. + + if ( tag->at( tag->length() - 1 ) == '>' + && tag->at( tag->length() - 2 ) == '/' ) + { + // All good! + return; + } + else if ( tag->at( tag->length() - 1 ) == '>' ) + { + // There is more. Could be: + // text + // cdata text (which looks like another node) + // closing tag + // another node. + for ( ;; ) + { + StreamWhiteSpace( in, tag ); + + // Do we have text? + if ( in->good() && in->peek() != '<' ) + { + // Yep, text. + TiXmlText text( "" ); + text.StreamIn( in, tag ); + + // What follows text is a closing tag or another node. + // Go around again and figure it out. + continue; + } + + // We now have either a closing tag...or another node. + // We should be at a "<", regardless. + if ( !in->good() ) return; + assert( in->peek() == '<' ); + int tagIndex = (int) tag->length(); + + bool closingTag = false; + bool firstCharFound = false; + + for( ;; ) + { + if ( !in->good() ) + return; + + int c = in->peek(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + if ( c == '>' ) + break; + + *tag += (char) c; + in->get(); + + // Early out if we find the CDATA id. + if ( c == '[' && tag->size() >= 9 ) + { + size_t len = tag->size(); + const char* start = tag->c_str() + len - 9; + if ( strcmp( start, "<![CDATA[" ) == 0 ) { + assert( !closingTag ); + break; + } + } + + if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) ) + { + firstCharFound = true; + if ( c == '/' ) + closingTag = true; + } + } + // If it was a closing tag, then read in the closing '>' to clean up the input stream. + // If it was not, the streaming will be done by the tag. + if ( closingTag ) + { + if ( !in->good() ) + return; + + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + assert( c == '>' ); + *tag += (char) c; + + // We are done, once we've found our closing tag. + return; + } + else + { + // If not a closing tag, id it, and stream. + const char* tagloc = tag->c_str() + tagIndex; + TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING ); + if ( !node ) + return; + node->StreamIn( in, tag ); + delete node; + node = 0; + + // No return: go around from the beginning: text, closing tag, or node. + } + } + } +} +#endif + +const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + p = SkipWhiteSpace( p, encoding ); + TiXmlDocument* document = GetDocument(); + + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding ); + return 0; + } + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + + if ( *p != '<' ) + { + if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding ); + return 0; + } + + p = SkipWhiteSpace( p+1, encoding ); + + // Read the name. + const char* pErr = p; + + p = ReadName( p, &value, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding ); + return 0; + } + + TIXML_STRING endTag ("</"); + endTag += value; + + // Check for and read attributes. Also look for an empty + // tag or an end tag. + while ( p && *p ) + { + pErr = p; + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); + return 0; + } + if ( *p == '/' ) + { + ++p; + // Empty tag. + if ( *p != '>' ) + { + if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding ); + return 0; + } + return (p+1); + } + else if ( *p == '>' ) + { + // Done with attributes (if there were any.) + // Read the value -- which can include other + // elements -- read the end tag, and return. + ++p; + p = ReadValue( p, data, encoding ); // Note this is an Element method, and will set the error if one happens. + if ( !p || !*p ) { + // We were looking for the end tag, but found nothing. + // Fix for [ 1663758 ] Failure to report error on bad XML + if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); + return 0; + } + + // We should find the end tag now + // note that: + // </foo > and + // </foo> + // are both valid end tags. + if ( StringEqual( p, endTag.c_str(), false, encoding ) ) + { + p += endTag.length(); + p = SkipWhiteSpace( p, encoding ); + if ( p && *p && *p == '>' ) { + ++p; + return p; + } + if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); + return 0; + } + else + { + if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); + return 0; + } + } + else + { + // Try to read an attribute: + TiXmlAttribute* attrib = new TiXmlAttribute(); + if ( !attrib ) + { + return 0; + } + + attrib->SetDocument( document ); + pErr = p; + p = attrib->Parse( p, data, encoding ); + + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding ); + delete attrib; + return 0; + } + + // Handle the strange case of double attributes: + #ifdef TIXML_USE_STL + TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() ); + #else + TiXmlAttribute* node = attributeSet.Find( attrib->Name() ); + #endif + if ( node ) + { + if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding ); + delete attrib; + return 0; + } + + attributeSet.Add( attrib ); + } + } + return p; +} + + +const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + TiXmlDocument* document = GetDocument(); + + // Read in text and elements in any order. + const char* pWithWhiteSpace = p; + p = SkipWhiteSpace( p, encoding ); + + while ( p && *p ) + { + if ( *p != '<' ) + { + // Take what we have, make a text element. + TiXmlText* textNode = new TiXmlText( "" ); + + if ( !textNode ) + { + return 0; + } + + if ( TiXmlBase::IsWhiteSpaceCondensed() ) + { + p = textNode->Parse( p, data, encoding ); + } + else + { + // Special case: we want to keep the white space + // so that leading spaces aren't removed. + p = textNode->Parse( pWithWhiteSpace, data, encoding ); + } + + if ( !textNode->Blank() ) + LinkEndChild( textNode ); + else + delete textNode; + } + else + { + // We hit a '<' + // Have we hit a new element or an end tag? This could also be + // a TiXmlText in the "CDATA" style. + if ( StringEqual( p, "</", false, encoding ) ) + { + return p; + } + else + { + TiXmlNode* node = Identify( p, encoding ); + if ( node ) + { + p = node->Parse( p, data, encoding ); + LinkEndChild( node ); + } + else + { + return 0; + } + } + } + pWithWhiteSpace = p; + p = SkipWhiteSpace( p, encoding ); + } + + if ( !p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding ); + } + return p; +} + + +#ifdef TIXML_USE_STL +void TiXmlUnknown::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + (*tag) += (char) c; + + if ( c == '>' ) + { + // All is well. + return; + } + } +} +#endif + + +const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + TiXmlDocument* document = GetDocument(); + p = SkipWhiteSpace( p, encoding ); + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + if ( !p || !*p || *p != '<' ) + { + if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding ); + return 0; + } + ++p; + value = ""; + + while ( p && *p && *p != '>' ) + { + value += *p; + ++p; + } + + if ( !p ) + { + if ( document ) + document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding ); + } + if ( p && *p == '>' ) + return p+1; + return p; +} + +#ifdef TIXML_USE_STL +void TiXmlComment::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + (*tag) += (char) c; + + if ( c == '>' + && tag->at( tag->length() - 2 ) == '-' + && tag->at( tag->length() - 3 ) == '-' ) + { + // All is well. + return; + } + } +} +#endif + + +const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + TiXmlDocument* document = GetDocument(); + value = ""; + + p = SkipWhiteSpace( p, encoding ); + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + const char* startTag = "<!--"; + const char* endTag = "-->"; + + if ( !StringEqual( p, startTag, false, encoding ) ) + { + if ( document ) + document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); + return 0; + } + p += strlen( startTag ); + + // [ 1475201 ] TinyXML parses entities in comments + // Oops - ReadText doesn't work, because we don't want to parse the entities. + // p = ReadText( p, &value, false, endTag, false, encoding ); + // + // from the XML spec: + /* + [Definition: Comments may appear anywhere in a document outside other markup; in addition, + they may appear within the document type declaration at places allowed by the grammar. + They are not part of the document's character data; an XML processor MAY, but need not, + make it possible for an application to retrieve the text of comments. For compatibility, + the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity + references MUST NOT be recognized within comments. + + An example of a comment: + + <!-- declarations for <head> & <body> --> + */ + + value = ""; + // Keep all the white space. + while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) + { + value.append( p, 1 ); + ++p; + } + if ( p && *p ) + p += strlen( endTag ); + + return p; +} + + +const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) return 0; + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + // Read the name, the '=' and the value. + const char* pErr = p; + p = ReadName( p, &name, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); + return 0; + } + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p || *p != '=' ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + ++p; // skip '=' + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + const char* end; + const char SINGLE_QUOTE = '\''; + const char DOUBLE_QUOTE = '\"'; + + if ( *p == SINGLE_QUOTE ) + { + ++p; + end = "\'"; // single quote in string + p = ReadText( p, &value, false, end, false, encoding ); + } + else if ( *p == DOUBLE_QUOTE ) + { + ++p; + end = "\""; // double quote in string + p = ReadText( p, &value, false, end, false, encoding ); + } + else + { + // All attribute values should be in single or double quotes. + // But this is such a common error that the parser will try + // its best, even without them. + value = ""; + while ( p && *p // existence + && !IsWhiteSpace( *p ) // whitespace + && *p != '/' && *p != '>' ) // tag end + { + if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { + // [ 1451649 ] Attribute values with trailing quotes not handled correctly + // We did not have an opening quote but seem to have a + // closing one. Give up and throw an error. + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + value += *p; + ++p; + } + } + return p; +} + +#ifdef TIXML_USE_STL +void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->peek(); + if ( !cdata && (c == '<' ) ) + { + return; + } + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + (*tag) += (char) c; + in->get(); // "commits" the peek made above + + if ( cdata && c == '>' && tag->size() >= 3 ) { + size_t len = tag->size(); + if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { + // terminator of cdata. + return; + } + } + } +} +#endif + +const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + value = ""; + TiXmlDocument* document = GetDocument(); + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + + const char* const startTag = "<![CDATA["; + const char* const endTag = "]]>"; + + if ( cdata || StringEqual( p, startTag, false, encoding ) ) + { + cdata = true; + + if ( !StringEqual( p, startTag, false, encoding ) ) + { + if ( document ) + document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); + return 0; + } + p += strlen( startTag ); + + // Keep all the white space, ignore the encoding, etc. + while ( p && *p + && !StringEqual( p, endTag, false, encoding ) + ) + { + value += *p; + ++p; + } + + TIXML_STRING dummy; + p = ReadText( p, &dummy, false, endTag, false, encoding ); + return p; + } + else + { + bool ignoreWhite = true; + + const char* end = "<"; + p = ReadText( p, &value, ignoreWhite, end, false, encoding ); + if ( p && *p ) + return p-1; // don't truncate the '<' + return 0; + } +} + +#ifdef TIXML_USE_STL +void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + (*tag) += (char) c; + + if ( c == '>' ) + { + // All is well. + return; + } + } +} +#endif + +const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) +{ + p = SkipWhiteSpace( p, _encoding ); + // Find the beginning, find the end, and look for + // the stuff in-between. + TiXmlDocument* document = GetDocument(); + if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) ) + { + if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); + return 0; + } + if ( data ) + { + data->Stamp( p, _encoding ); + location = data->Cursor(); + } + p += 5; + + version = ""; + encoding = ""; + standalone = ""; + + while ( p && *p ) + { + if ( *p == '>' ) + { + ++p; + return p; + } + + p = SkipWhiteSpace( p, _encoding ); + if ( StringEqual( p, "version", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + version = attrib.Value(); + } + else if ( StringEqual( p, "encoding", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + encoding = attrib.Value(); + } + else if ( StringEqual( p, "standalone", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + standalone = attrib.Value(); + } + else + { + // Read over whatever it is. + while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) + ++p; + } + } + return 0; +} + +bool TiXmlText::Blank() const +{ + for ( unsigned i=0; i<value.length(); i++ ) + if ( !IsWhiteSpace( value[i] ) ) + return false; + return true; +} + diff --git a/gfx/sfntly/cpp/src/test/verify_glyf.cc b/gfx/sfntly/cpp/src/test/verify_glyf.cc new file mode 100644 index 0000000000..abfe1ab8aa --- /dev/null +++ b/gfx/sfntly/cpp/src/test/verify_glyf.cc @@ -0,0 +1,59 @@ +/* + * 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 "gtest/gtest.h" +#include "sfntly/font.h" +#include "sfntly/table/truetype/glyph_table.h" +#include "test/serialization_test.h" + +namespace sfntly { + +// We spot check only glyph id 33. +const int32_t GLYPH33_OFFSET = 0xAC8; +const int32_t GLYPH33_LENGTH = 40; +const int32_t GLYPH33_XMIN = 92; +const int32_t GLYPH33_YMIN = 20; +const int32_t GLYPH33_XMAX = 797; +const int32_t GLYPH33_YMAX = 1235; + +// TODO(arthurhsu): Tuffy does not have composite glyphs. Need better testing. +static bool VerifyGLYF(Table* table) { + GlyphTablePtr glyf_table = down_cast<GlyphTable*>(table); + if (glyf_table == NULL) { + return false; + } + + GlyphPtr glyf; + glyf.Attach(glyf_table->GetGlyph(GLYPH33_OFFSET, GLYPH33_LENGTH)); + if (glyf == NULL) { + return false; + } + + EXPECT_EQ(glyf->XMin(), GLYPH33_XMIN); + EXPECT_EQ(glyf->YMin(), GLYPH33_YMIN); + EXPECT_EQ(glyf->XMax(), GLYPH33_XMAX); + EXPECT_EQ(glyf->YMax(), GLYPH33_YMAX); + + return true; +} + +bool VerifyGLYF(Table* original, Table* target) { + EXPECT_TRUE(VerifyGLYF(original)); + EXPECT_TRUE(VerifyGLYF(target)); + return true; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/test/verify_hhea.cc b/gfx/sfntly/cpp/src/test/verify_hhea.cc new file mode 100644 index 0000000000..1e1001cd66 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/verify_hhea.cc @@ -0,0 +1,63 @@ +/* + * 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 "gtest/gtest.h" +#include "sfntly/font.h" +#include "sfntly/math/fixed1616.h" +#include "sfntly/table/core/horizontal_header_table.h" +#include "test/serialization_test.h" + +namespace sfntly { + +const int32_t HHEA_ASCENDER = 2023; +const int32_t HHEA_DESCENDER = -648; +// const int32_t HHEA_LINE_GAP = 93; +const int32_t HHEA_ADVANCE_WIDTH_MAX = 2753; +const int32_t HHEA_MIN_LSB = -968; +const int32_t HHEA_MIN_RSB = -411; +const int32_t HHEA_X_MAX_EXTENT = 2628; +const int32_t HHEA_METRIC_DATA_FORMAT = 0; +const int32_t HHEA_NUM_METRICS = 1499; + +static bool VerifyHHEA(Table* table) { + HorizontalHeaderTablePtr hhea = down_cast<HorizontalHeaderTable*>(table); + if (hhea == NULL) { + return false; + } + + EXPECT_EQ(hhea->TableVersion(), Fixed1616::Fixed(1, 0)); + EXPECT_EQ(hhea->Ascender(), HHEA_ASCENDER); + EXPECT_EQ(hhea->Descender(), HHEA_DESCENDER); + EXPECT_EQ(hhea->AdvanceWidthMax(), HHEA_ADVANCE_WIDTH_MAX); + EXPECT_EQ(hhea->MinLeftSideBearing(), HHEA_MIN_LSB); + EXPECT_EQ(hhea->MinRightSideBearing(), HHEA_MIN_RSB); + EXPECT_EQ(hhea->XMaxExtent(), HHEA_X_MAX_EXTENT); + // TODO(arthurhsu): CaretSlopeRise() not tested + // TODO(arthurhsu): CaretSlopeRun() not tested + // TODO(arthurhsu): CaretOffset() not tested + EXPECT_EQ(hhea->MetricDataFormat(), HHEA_METRIC_DATA_FORMAT); + EXPECT_EQ(hhea->NumberOfHMetrics(), HHEA_NUM_METRICS); + + return true; +} + +bool VerifyHHEA(Table* original, Table* target) { + EXPECT_TRUE(VerifyHHEA(original)); + EXPECT_TRUE(VerifyHHEA(target)); + return true; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/test/verify_hmtx.cc b/gfx/sfntly/cpp/src/test/verify_hmtx.cc new file mode 100644 index 0000000000..d37bba98b2 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/verify_hmtx.cc @@ -0,0 +1,76 @@ +/* + * 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 "gtest/gtest.h" +#include "sfntly/font.h" +#include "sfntly/table/core/horizontal_metrics_table.h" +#include "test/serialization_test.h" + +namespace sfntly { + +const int32_t HMTX_ENTRIES_COUNT = 1499; +const int32_t HMTX_LSB_COUNT = 3; + +struct HmtxEntry { + int32_t advance_width_; + int32_t lsb_; + + HmtxEntry(int32_t advance_width, int32_t lsb) + : advance_width_(advance_width), lsb_(lsb) {} +}; + +const HmtxEntry HMTX_ENTRIES[] = { + HmtxEntry(748, 68), // 0 + HmtxEntry(0, 0), // 1 + HmtxEntry(682, 0), // 2 + HmtxEntry(616, 0), // 3 + HmtxEntry(421, 103), // 4 + HmtxEntry(690, 129), // 5 + HmtxEntry(1589, 129), // 6 + HmtxEntry(1017, 25), // 7 + HmtxEntry(1402, 104), // 8 + HmtxEntry(1241, 100), // 9 +}; +const int32_t NUM_HMTX_ENTRIES = 10; + +static bool VerifyHMTX(Table* table) { + HorizontalMetricsTablePtr hmtx = down_cast<HorizontalMetricsTable*>(table); + if (hmtx == NULL) { + return false; + } + + EXPECT_EQ(hmtx->NumberOfHMetrics(), HMTX_ENTRIES_COUNT); + EXPECT_EQ(hmtx->NumberOfLSBs(), HMTX_LSB_COUNT); + + for (int32_t i = 0; i < NUM_HMTX_ENTRIES; ++i) { + EXPECT_EQ(hmtx->AdvanceWidth(i), HMTX_ENTRIES[i].advance_width_); + EXPECT_EQ(hmtx->LeftSideBearing(i), HMTX_ENTRIES[i].lsb_); + } + + // No such element case. + EXPECT_EQ(hmtx->AdvanceWidth(HMTX_ENTRIES_COUNT), + HMTX_ENTRIES[0].advance_width_); + EXPECT_EQ(hmtx->LeftSideBearing(HMTX_ENTRIES_COUNT), HMTX_ENTRIES[0].lsb_); + return true; +} + +bool VerifyHMTX(Table* original, Table* target) { + EXPECT_TRUE(VerifyHMTX(original)); + EXPECT_TRUE(VerifyHMTX(target)); + return true; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/test/verify_loca.cc b/gfx/sfntly/cpp/src/test/verify_loca.cc new file mode 100644 index 0000000000..4a32928875 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/verify_loca.cc @@ -0,0 +1,62 @@ +/* + * 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 "gtest/gtest.h" +#include "sfntly/font.h" +#include "sfntly/table/truetype/loca_table.h" +#include "test/serialization_test.h" + +namespace sfntly { + +const int32_t LOCA_NUM_LOCAS = 1503; +const int32_t LOCAS[] = { + 0x00000, // 0 + 0x00058, // 1 + 0x00058, // 2 + 0x00058, // 3 + 0x00058, // 4 + 0x000B8, // 5 + 0x00138, // 6 + 0x001A4, // 7 + 0x0025C, // 8 + 0x00328, // 9 + 0x003B8, // 10 +}; +const int32_t NUM_TEST_LOCAS = 11; + +static bool VerifyLOCA(Table* table) { + LocaTablePtr loca = down_cast<LocaTable*>(table); + if (loca == NULL) { + return false; + } + + EXPECT_EQ(loca->NumLocas(), LOCA_NUM_LOCAS); + EXPECT_EQ(loca->num_glyphs(), LOCA_NUM_LOCAS - 1); + + for (int32_t i = 0; i < NUM_TEST_LOCAS - 1; ++i) { + EXPECT_EQ(loca->GlyphOffset(i), LOCAS[i]); + EXPECT_EQ(loca->GlyphLength(i), LOCAS[i + 1] - LOCAS[i]); + } + return true; +} + +bool VerifyLOCA(Table* original, Table* target) { + EXPECT_TRUE(VerifyLOCA(original)); + EXPECT_TRUE(VerifyLOCA(target)); + return true; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/test/verify_maxp.cc b/gfx/sfntly/cpp/src/test/verify_maxp.cc new file mode 100644 index 0000000000..074042a0b9 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/verify_maxp.cc @@ -0,0 +1,72 @@ +/* + * 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 "gtest/gtest.h" +#include "sfntly/font.h" +#include "sfntly/math/fixed1616.h" +#include "sfntly/table/core/maximum_profile_table.h" +#include "test/serialization_test.h" + +namespace sfntly { + +const int32_t MAXP_NUM_GLYPHS = 1502; +const int32_t MAXP_MAX_POINTS = 181; +const int32_t MAXP_MAX_CONTOURS = 9; +const int32_t MAXP_MAX_COMPOSITE_POINTS = 172; +const int32_t MAXP_MAX_COMPOSITE_CONTOURS = 5; +const int32_t MAXP_MAX_ZONES = 2; +const int32_t MAXP_MAX_TWILIGHT_POINTS = 0; +const int32_t MAXP_MAX_STORAGE = 1; +const int32_t MAXP_MAX_FUNCTION_DEFS = 1; +// const int32_t MAXP_MAX_INSTR_DEFS = 0; +const int32_t MAXP_MAX_STACK_ELEMENTS = 64; +const int32_t MAXP_MAX_INSTR_SIZE = 46; +const int32_t MAXP_MAX_COMPONENT_ELEMENTS = 4; +const int32_t MAXP_MAX_COMPONENT_DEPTH = 3; + +static bool VerifyMAXP(Table* table) { + MaximumProfileTablePtr maxp = down_cast<MaximumProfileTable*>(table); + if (maxp == NULL) { + return false; + } + + EXPECT_EQ(maxp->TableVersion(), Fixed1616::Fixed(1, 0)); + EXPECT_EQ(maxp->NumGlyphs(), MAXP_NUM_GLYPHS); + EXPECT_EQ(maxp->MaxPoints(), MAXP_MAX_POINTS); + EXPECT_EQ(maxp->MaxContours(), MAXP_MAX_CONTOURS); + EXPECT_EQ(maxp->MaxCompositePoints(), MAXP_MAX_COMPOSITE_POINTS); + EXPECT_EQ(maxp->MaxCompositeContours(), MAXP_MAX_COMPOSITE_CONTOURS); + EXPECT_EQ(maxp->MaxZones(), MAXP_MAX_ZONES); + EXPECT_EQ(maxp->MaxTwilightPoints(), MAXP_MAX_TWILIGHT_POINTS); + EXPECT_EQ(maxp->MaxStorage(), MAXP_MAX_STORAGE); + EXPECT_EQ(maxp->MaxFunctionDefs(), MAXP_MAX_FUNCTION_DEFS); + // TODO(arthurhsu): maxInstructionDefs observed in Microsoft TTF report. + // Check with stuartg and see if this is a miss. + EXPECT_EQ(maxp->MaxStackElements(), MAXP_MAX_STACK_ELEMENTS); + EXPECT_EQ(maxp->MaxSizeOfInstructions(), MAXP_MAX_INSTR_SIZE); + EXPECT_EQ(maxp->MaxComponentElements(), MAXP_MAX_COMPONENT_ELEMENTS); + EXPECT_EQ(maxp->MaxComponentDepth(), MAXP_MAX_COMPONENT_DEPTH); + + return true; +} + +bool VerifyMAXP(Table* original, Table* target) { + EXPECT_TRUE(VerifyMAXP(original)); + EXPECT_TRUE(VerifyMAXP(target)); + return true; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/test/verify_name.cc b/gfx/sfntly/cpp/src/test/verify_name.cc new file mode 100644 index 0000000000..e1101c078f --- /dev/null +++ b/gfx/sfntly/cpp/src/test/verify_name.cc @@ -0,0 +1,68 @@ +/* + * 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 "gtest/gtest.h" +#include "sfntly/font.h" +#include "sfntly/table/core/name_table.h" +#include "test/serialization_test.h" + +namespace sfntly { + +const int32_t NAME_FORMAT = 0; +const int32_t NAME_COUNT = 75; +const NameTable::NameEntryId NAME_IDS[] = { + NameTable::NameEntryId(1, 0, 0, 0), // 0 + NameTable::NameEntryId(1, 0, 0, 1), // 1 + NameTable::NameEntryId(1, 0, 0, 2), // 2 + NameTable::NameEntryId(1, 0, 0, 3), // 3 + NameTable::NameEntryId(1, 0, 0, 4), // 4 + NameTable::NameEntryId(1, 0, 0, 5), // 5 + NameTable::NameEntryId(1, 0, 0, 6), // 6 + NameTable::NameEntryId(1, 0, 0, 9), // 7 + NameTable::NameEntryId(1, 0, 0, 11), // 8 + NameTable::NameEntryId(1, 0, 0, 12), // 9 +}; +const int32_t NAME_IDS_TEST = 10; + +static bool VerifyNAME(Table* table) { + // TODO(arthurhsu): Better testing can be done here. Right now we just + // iterate through the entries and get entry ids. + NameTablePtr name = down_cast<NameTable*>(table); + if (name == NULL) { + return false; + } + + EXPECT_EQ(name->Format(), NAME_FORMAT); + EXPECT_EQ(name->NameCount(), NAME_COUNT); + fprintf(stderr, "checking name entry: "); + for (int32_t i = 0; i < NAME_IDS_TEST; ++i) { + fprintf(stderr, "%d ", i); + EXPECT_EQ(name->PlatformId(i), NAME_IDS[i].platform_id()); + EXPECT_EQ(name->EncodingId(i), NAME_IDS[i].encoding_id()); + EXPECT_EQ(name->LanguageId(i), NAME_IDS[i].language_id()); + EXPECT_EQ(name->NameId(i), NAME_IDS[i].name_id()); + } + fprintf(stderr, "\n"); + return true; +} + +bool VerifyNAME(Table* original, Table* target) { + EXPECT_TRUE(VerifyNAME(original)); + EXPECT_TRUE(VerifyNAME(target)); + return true; +} + +} // namespace sfntly diff --git a/gfx/sfntly/cpp/src/test/verify_os2.cc b/gfx/sfntly/cpp/src/test/verify_os2.cc new file mode 100644 index 0000000000..c80c58a8f5 --- /dev/null +++ b/gfx/sfntly/cpp/src/test/verify_os2.cc @@ -0,0 +1,125 @@ +/* + * 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 "gtest/gtest.h" +#include "sfntly/font.h" +#include "sfntly/table/core/os2_table.h" +#include "test/serialization_test.h" + +namespace sfntly { + +const int32_t OS2_VERSION = 1; +const int32_t OS2_XAVG_CHAR_WIDTH = 863; +const int32_t OS2_US_WEIGHT_CLASS = 500; +const int32_t OS2_US_WIDTH_CLASS = 5; +const int32_t OS2_FS_TYPE = 0; +const int32_t OS2_YSUBS_XSIZE = 0; +const int32_t OS2_YSUBS_YSIZE = 2; +const int32_t OS2_YSUBS_XOFFSET = -16560; +const int32_t OS2_YSUBS_YOFFSET = 0; +const int32_t OS2_YSUPS_XSIZE = -25944; +const int32_t OS2_YSUPS_YSIZE = -27176; +const int32_t OS2_YSUPS_XOFFSET = -16376; +const int32_t OS2_YSUPS_YOFFSET = 1; +const int32_t OS2_YSTRIKEOUT_SIZE = 12312; +const int32_t OS2_YSTRIKEOUT_POS = -16224; +const int32_t OS2_SFAMILY_CLASS = 0; +const uint8_t OS2_PANOSE[] = { 2, 11, 6, 3, 6, 1, 0, 0, 0, 0 }; +const int64_t OS2_UL_UNICODE_RANGE1 = 0xE00002FFL; +const int64_t OS2_UL_UNICODE_RANGE2 = 0x520020FBL; +const int64_t OS2_UL_UNICODE_RANGE3 = 0L; +const int64_t OS2_UL_UNICODE_RANGE4 = 0L; +const uint8_t OS2_ACH_VEND_ID[] = { 'P', 'f', 'E', 'd' }; +const int32_t OS2_FS_SELECTION = 0x0040; +const int32_t OS2_US_FIRST_CHAR_IDX = 0x0020; +const int32_t OS2_US_LAST_CHAR_IDX = 0xFFFF; +const int32_t OS2_STYPO_ASCENDER = 1597; +const int32_t OS2_STYPO_DESCENDER = -451; +const int32_t OS2_STYPO_LINE_GAP = 0; +const int32_t OS2_US_WIN_ASCENT = 2023; +const int32_t OS2_US_WIN_DESCENT = 648; +const int64_t OS2_UL_CODE_PAGE_RANGE1 = 0x2000019FL; +const int64_t OS2_UL_CODE_PAGE_RANGE2 = 0x00000000L; + +static bool VerifyOS_2(Table* table) { + OS2TablePtr os2 = down_cast<OS2Table*>(table); + if (os2 == NULL) { + return false; + } + + EXPECT_EQ(os2->TableVersion(), OS2_VERSION); + EXPECT_EQ(os2->XAvgCharWidth(), OS2_XAVG_CHAR_WIDTH); + EXPECT_EQ(os2->UsWeightClass(), OS2_US_WEIGHT_CLASS); + EXPECT_EQ(os2->UsWidthClass(), OS2_US_WIDTH_CLASS); + EXPECT_EQ(os2->FsType(), OS2_FS_TYPE); + EXPECT_EQ(os2->YSubscriptXSize(), OS2_YSUBS_XSIZE); + EXPECT_EQ(os2->YSubscriptYSize(), OS2_YSUBS_YSIZE); + EXPECT_EQ(os2->YSubscriptXOffset(), OS2_YSUBS_XOFFSET); + EXPECT_EQ(os2->YSubscriptYOffset(), OS2_YSUBS_YOFFSET); + EXPECT_EQ(os2->YSuperscriptXSize(), OS2_YSUPS_XSIZE); + EXPECT_EQ(os2->YSuperscriptYSize(), OS2_YSUPS_YSIZE); + EXPECT_EQ(os2->YSuperscriptXOffset(), OS2_YSUPS_XOFFSET); + EXPECT_EQ(os2->YSuperscriptYOffset(), OS2_YSUPS_YOFFSET); + EXPECT_EQ(os2->YStrikeoutSize(), OS2_YSTRIKEOUT_SIZE); + EXPECT_EQ(os2->YStrikeoutPosition(), OS2_YSTRIKEOUT_POS); + EXPECT_EQ(os2->SFamilyClass(), OS2_SFAMILY_CLASS); + + ByteVector panose; + os2->Panose(&panose); + EXPECT_EQ(panose.size(), sizeof(OS2_PANOSE)); + for (size_t i = 0; i < panose.size(); ++i) { + EXPECT_EQ(panose[i], OS2_PANOSE[i]); + } + + EXPECT_EQ(os2->UlUnicodeRange1(), OS2_UL_UNICODE_RANGE1); + EXPECT_EQ(os2->UlUnicodeRange2(), OS2_UL_UNICODE_RANGE2); + EXPECT_EQ(os2->UlUnicodeRange3(), OS2_UL_UNICODE_RANGE3); + EXPECT_EQ(os2->UlUnicodeRange4(), OS2_UL_UNICODE_RANGE4); + + ByteVector vend_id; + os2->AchVendId(&vend_id); + EXPECT_EQ(vend_id.size(), sizeof(OS2_ACH_VEND_ID)); + for (size_t i = 0; i < vend_id.size(); ++i) { + EXPECT_EQ(vend_id[i], OS2_ACH_VEND_ID[i]); + } + + EXPECT_EQ(os2->FsSelection(), OS2_FS_SELECTION); + EXPECT_EQ(os2->UsFirstCharIndex(), OS2_US_FIRST_CHAR_IDX); + EXPECT_EQ(os2->UsLastCharIndex(), OS2_US_LAST_CHAR_IDX); + EXPECT_EQ(os2->STypoAscender(), OS2_STYPO_ASCENDER); + EXPECT_EQ(os2->STypoDescender(), OS2_STYPO_DESCENDER); + EXPECT_EQ(os2->STypoLineGap(), OS2_STYPO_LINE_GAP); + EXPECT_EQ(os2->UsWinAscent(), OS2_US_WIN_ASCENT); + EXPECT_EQ(os2->UsWinDescent(), OS2_US_WIN_DESCENT); + EXPECT_EQ(os2->UlCodePageRange1(), OS2_UL_CODE_PAGE_RANGE1); + EXPECT_EQ(os2->UlCodePageRange2(), OS2_UL_CODE_PAGE_RANGE2); + + // TODO(arthurhsu): SxHeight() not tested + // TODO(arthurhsu): SCapHeight() not tested + // TODO(arthurhsu): UsDefaultChar() not tested + // TODO(arthurhsu): UsBreakChar() not tested + // TODO(arthurhsu): UsMaxContext() not tested + + return true; +} + +bool VerifyOS_2(Table* original, Table* target) { + EXPECT_TRUE(VerifyOS_2(original)); + EXPECT_TRUE(VerifyOS_2(target)); + return true; +} + +} // namespace sfntly |