| /* |
| * 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: |
| #if defined (SFNTLY_DEBUG_CMAP) |
| fprintf(stderr, "Requesting Format4 builder, but it's unsupported; " |
| "returning NULL\n"); |
| #endif |
| 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: |
| #if defined (SFNTLY_DEBUG_CMAP) |
| fprintf(stderr, "Requesting Format4 builder, but it's unsupported; " |
| "returning NULL\n"); |
| #endif |
| 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::Builder class |
| ******************************************************************************/ |
| CMapTable::Builder::Builder(Header* header, WritableFontData* data) |
| : SubTableContainerTable::Builder(header, data) { |
| } |
| |
| CMapTable::Builder::Builder(Header* header, ReadableFontData* data) |
| : SubTableContainerTable::Builder(header, data) { |
| } |
| |
| 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 |