diff options
Diffstat (limited to 'sfntly/table/core')
-rw-r--r-- | sfntly/table/core/cmap_table.cc | 1287 | ||||
-rw-r--r-- | sfntly/table/core/cmap_table.h | 709 | ||||
-rw-r--r-- | sfntly/table/core/font_header_table.cc | 265 | ||||
-rw-r--r-- | sfntly/table/core/font_header_table.h | 168 | ||||
-rw-r--r-- | sfntly/table/core/horizontal_device_metrics_table.cc | 124 | ||||
-rw-r--r-- | sfntly/table/core/horizontal_device_metrics_table.h | 82 | ||||
-rw-r--r-- | sfntly/table/core/horizontal_header_table.cc | 213 | ||||
-rw-r--r-- | sfntly/table/core/horizontal_header_table.h | 111 | ||||
-rw-r--r-- | sfntly/table/core/horizontal_metrics_table.cc | 138 | ||||
-rw-r--r-- | sfntly/table/core/horizontal_metrics_table.h | 87 | ||||
-rw-r--r-- | sfntly/table/core/maximum_profile_table.cc | 240 | ||||
-rw-r--r-- | sfntly/table/core/maximum_profile_table.h | 120 | ||||
-rw-r--r-- | sfntly/table/core/name_table.cc | 723 | ||||
-rw-r--r-- | sfntly/table/core/name_table.h | 743 | ||||
-rw-r--r-- | sfntly/table/core/os2_table.cc | 610 | ||||
-rw-r--r-- | sfntly/table/core/os2_table.h | 508 |
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_ |