summaryrefslogtreecommitdiff
path: root/sfntly/table/core
diff options
context:
space:
mode:
Diffstat (limited to 'sfntly/table/core')
-rw-r--r--sfntly/table/core/cmap_table.cc1287
-rw-r--r--sfntly/table/core/cmap_table.h709
-rw-r--r--sfntly/table/core/font_header_table.cc265
-rw-r--r--sfntly/table/core/font_header_table.h168
-rw-r--r--sfntly/table/core/horizontal_device_metrics_table.cc124
-rw-r--r--sfntly/table/core/horizontal_device_metrics_table.h82
-rw-r--r--sfntly/table/core/horizontal_header_table.cc213
-rw-r--r--sfntly/table/core/horizontal_header_table.h111
-rw-r--r--sfntly/table/core/horizontal_metrics_table.cc138
-rw-r--r--sfntly/table/core/horizontal_metrics_table.h87
-rw-r--r--sfntly/table/core/maximum_profile_table.cc240
-rw-r--r--sfntly/table/core/maximum_profile_table.h120
-rw-r--r--sfntly/table/core/name_table.cc723
-rw-r--r--sfntly/table/core/name_table.h743
-rw-r--r--sfntly/table/core/os2_table.cc610
-rw-r--r--sfntly/table/core/os2_table.h508
16 files changed, 6128 insertions, 0 deletions
diff --git a/sfntly/table/core/cmap_table.cc b/sfntly/table/core/cmap_table.cc
new file mode 100644
index 0000000..1c83d2e
--- /dev/null
+++ b/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(reinterpret_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);
+ byte_t high_byte = (c >> 8) & 0xff;
+ byte_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)))
+ : reinterpret_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)))
+ : reinterpret_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,
+ IntegerList* glyph_id_array,
+ const CMapId& cmap_id)
+ : CMap::Builder(reinterpret_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(reinterpret_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();
+}
+
+IntegerList* 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(IntegerList* 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/sfntly/table/core/cmap_table.h b/sfntly/table/core/cmap_table.h
new file mode 100644
index 0000000..b264b07
--- /dev/null
+++ b/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);
+ IntegerList* glyph_id_array();
+ void set_glyph_id_array(IntegerList* 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, IntegerList* 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_;
+ IntegerList 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/sfntly/table/core/font_header_table.cc b/sfntly/table/core/font_header_table.cc
new file mode 100644
index 0000000..60015ca
--- /dev/null
+++ b/sfntly/table/core/font_header_table.cc
@@ -0,0 +1,265 @@
+/*
+ * 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) {
+ IntegerList 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() {
+ return down_cast<FontHeaderTable*>(GetTable())->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/sfntly/table/core/font_header_table.h b/sfntly/table/core/font_header_table.h
new file mode 100644
index 0000000..841955b
--- /dev/null
+++ b/sfntly/table/core/font_header_table.h
@@ -0,0 +1,168 @@
+/*
+ * 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 {
+ 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/sfntly/table/core/horizontal_device_metrics_table.cc b/sfntly/table/core/horizontal_device_metrics_table.cc
new file mode 100644
index 0000000..50b0cf5
--- /dev/null
+++ b/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/sfntly/table/core/horizontal_device_metrics_table.h b/sfntly/table/core/horizontal_device_metrics_table.h
new file mode 100644
index 0000000..4a27ba0
--- /dev/null
+++ b/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/sfntly/table/core/horizontal_header_table.cc b/sfntly/table/core/horizontal_header_table.cc
new file mode 100644
index 0000000..43c2058
--- /dev/null
+++ b/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/sfntly/table/core/horizontal_header_table.h b/sfntly/table/core/horizontal_header_table.h
new file mode 100644
index 0000000..71f30b4
--- /dev/null
+++ b/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/sfntly/table/core/horizontal_metrics_table.cc b/sfntly/table/core/horizontal_metrics_table.cc
new file mode 100644
index 0000000..156387d
--- /dev/null
+++ b/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/sfntly/table/core/horizontal_metrics_table.h b/sfntly/table/core/horizontal_metrics_table.h
new file mode 100644
index 0000000..44b51f2
--- /dev/null
+++ b/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/sfntly/table/core/maximum_profile_table.cc b/sfntly/table/core/maximum_profile_table.cc
new file mode 100644
index 0000000..a8ac3bc
--- /dev/null
+++ b/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/sfntly/table/core/maximum_profile_table.h b/sfntly/table/core/maximum_profile_table.h
new file mode 100644
index 0000000..e7c5abb
--- /dev/null
+++ b/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/sfntly/table/core/name_table.cc b/sfntly/table/core/name_table.cc
new file mode 100644
index 0000000..8d2f64f
--- /dev/null
+++ b/sfntly/table/core/name_table.cc
@@ -0,0 +1,723 @@
+/*
+ * 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 <unicode/unistr.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 ByteVector& 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 ByteVector& name_bytes) {
+ Init(platform_id, encoding_id, language_id, name_id, &name_bytes);
+}
+
+NameTable::NameEntry::~NameEntry() {}
+
+ByteVector* 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 ByteVector* 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 ByteVector& 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 ByteVector& 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 ByteVector& 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 ByteVector* 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, ByteVector* b) {
+ assert(b);
+ int32_t length = NameLength(index);
+ b->clear();
+ b->resize(length);
+ if (length > 0) {
+ data_->ReadBytes(NameOffset(index), &((*b)[0]), 0, length);
+ }
+}
+
+void NameTable::NameAsBytes(int32_t platform_id,
+ int32_t encoding_id,
+ int32_t language_id,
+ int32_t name_id,
+ ByteVector* b) {
+ assert(b);
+ NameEntryPtr entry;
+ entry.Attach(GetNameEntry(platform_id, encoding_id, language_id, name_id));
+ if (entry) {
+ ByteVector* name = entry->NameAsBytes();
+ std::copy(name->begin(), name->end(), b->begin());
+ }
+}
+
+UChar* NameTable::Name(int32_t index) {
+ ByteVector 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) {
+ ByteVector 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,
+ ByteVector* 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(ByteVector* 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/sfntly/table/core/name_table.h b/sfntly/table/core/name_table.h
new file mode 100644
index 0000000..4eaafbb
--- /dev/null
+++ b/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 ByteVector& name_bytes);
+ NameEntry(int32_t platform_id,
+ int32_t encoding_id,
+ int32_t language_id,
+ int32_t name_id,
+ const ByteVector& 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.
+ ByteVector* 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 ByteVector* name_bytes);
+
+ NameEntryId name_entry_id_;
+ ByteVector 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 ByteVector& 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 ByteVector& name_bytes);
+ virtual void SetName(const ByteVector& 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 ByteVector* 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, ByteVector* b);
+ virtual void NameAsBytes(int32_t platform_id, int32_t encoding_id,
+ int32_t language_id, int32_t name_id,
+ ByteVector* 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 ByteVector* 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, ByteVector* b);
+
+ // Note: ICU UChar* convention requires caller to delete[] it.
+ static UChar* ConvertFromNameBytes(ByteVector* 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/sfntly/table/core/os2_table.cc b/sfntly/table/core/os2_table.cc
new file mode 100644
index 0000000..1fef309
--- /dev/null
+++ b/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(ByteVector* 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(ByteVector* 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(ByteVector* value) {
+ assert(value);
+ value->clear();
+ value->resize(Offset::kPanoseLength);
+ InternalReadData()->ReadBytes(Offset::kPanose,
+ &((*value)[0]),
+ 0,
+ Offset::kPanoseLength);
+}
+
+void OS2Table::Builder::SetPanose(ByteVector* 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(ByteVector* b) {
+ assert(b);
+ b->clear();
+ b->resize(4);
+ InternalReadData()->ReadBytes(Offset::kAchVendId, &((*b)[0]), 0, 4);
+}
+
+void OS2Table::Builder::SetAchVendId(ByteVector* b) {
+ assert(b);
+ assert(b->size());
+ InternalWriteData()->WriteBytesPad(Offset::kAchVendId,
+ b,
+ 0,
+ std::min<size_t>(
+ (size_t)Offset::kAchVendIdLength,
+ b->size()),
+ static_cast<byte_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/sfntly/table/core/os2_table.h b/sfntly/table/core/os2_table.h
new file mode 100644
index 0000000..00d26d2
--- /dev/null
+++ b/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(ByteVector* value);
+ void SetPanose(ByteVector* 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(ByteVector* 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(ByteVector* 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(ByteVector* value);
+ int64_t UlUnicodeRange1();
+ int64_t UlUnicodeRange2();
+ int64_t UlUnicodeRange3();
+ int64_t UlUnicodeRange4();
+ // UNIMPLEMENTED: public EnumSet<UnicodeRange> UlUnicodeRange()
+ void AchVendId(ByteVector* 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_