summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordfilimon@google.com <dfilimon@google.com@672e30a5-4c29-85ac-ac6d-611c735e0a51>2011-09-15 19:14:16 +0000
committerdfilimon@google.com <dfilimon@google.com@672e30a5-4c29-85ac-ac6d-611c735e0a51>2011-09-15 19:14:16 +0000
commitbb035e4061737ef1ac7ee3e1263c443b55c123e9 (patch)
treefe2e3d830309ea94416c645841be87820a712508
parenta2725711c28771ab66670264bdf0caa797ebb22a (diff)
downloadsrc-bb035e4061737ef1ac7ee3e1263c443b55c123e9.tar.gz
Adding CMapTable support for Format0.
git-svn-id: http://sfntly.googlecode.com/svn/trunk/cpp/src@76 672e30a5-4c29-85ac-ac6d-611c735e0a51
-rw-r--r--sfntly/table/core/cmap_table.cc454
-rw-r--r--sfntly/table/core/cmap_table.h192
-rw-r--r--sfntly/table/table.cc6
3 files changed, 506 insertions, 146 deletions
diff --git a/sfntly/table/core/cmap_table.cc b/sfntly/table/core/cmap_table.cc
index dd43996..bbe4497 100644
--- a/sfntly/table/core/cmap_table.cc
+++ b/sfntly/table/core/cmap_table.cc
@@ -14,24 +14,93 @@
* limitations under the License.
*/
-// TODO(arthurhsu): IMPLEMENT: not really used and tested, need cleanup
+#include "sfntly/table/core/cmap_table.h"
-#include <cstdlib>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <utility>
-#include "sfntly/table/core/cmap_table.h"
-#include "sfntly/table/core/name_table.h"
#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 reinterpret_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 = new CMapIdFilter(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());
+ delete id_filter;
+ return cmap.Detach();
+ }
+ delete id_filter;
+#ifndef SFNTLY_NO_EXCEPTION
+ throw NoSuchElementException();
+#else
+ return NULL;
+#endif
+}
+
int32_t CMapTable::Version() {
return data_->ReadUShort(Offset::kVersion);
}
@@ -41,7 +110,7 @@ int32_t CMapTable::NumCMaps() {
}
CMapTable::CMapId CMapTable::GetCMapId(int32_t index) {
- return CMapId(PlatformId(index), EncodingId(index));
+ return NewCMapId(PlatformId(index), EncodingId(index));
}
int32_t CMapTable::PlatformId(int32_t index) {
@@ -59,53 +128,101 @@ int32_t CMapTable::Offset(int32_t index) {
OffsetForEncodingRecord(index));
}
-CMapTable::CMapTable(Header* header, ReadableFontData* data)
- : SubTableContainerTable(header, data) {
-}
-
int32_t CMapTable::OffsetForEncodingRecord(int32_t index) {
return Offset::kEncodingRecordStart + index * Offset::kEncodingRecordSize;
}
-/******************************************************************************
- * CMapTable::CMapId class
- ******************************************************************************/
-CMapTable::CMapId::CMapId(int32_t platform_id, int32_t encoding_id)
- : platform_id_(platform_id), encoding_id_(encoding_id) {
+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::CMapId(const CMapId& obj)
- : platform_id_(obj.platform_id_), encoding_id_(obj.encoding_id_) {
+CMapTable::CMapId CMapTable::NewCMapId(const CMapId& obj) {
+ CMapId result;
+ result.platform_id = obj.platform_id;
+ result.encoding_id = obj.encoding_id;
+ return result;
}
-bool CMapTable::CMapId::operator==(const CMapTable::CMapId& obj) {
- return obj.platform_id_ == platform_id_ && obj.encoding_id_ == encoding_id_;
+/******************************************************************************
+ * CMapTable::CMapIterator class
+ ******************************************************************************/
+CMapTable::CMapIterator::CMapIterator(CMapTable* table,
+ const CMapFilter* filter)
+ : table_index_(0), filter_(filter), table_(table) {
}
-const CMapTable::CMapId& CMapTable::CMapId::operator=(
- const CMapTable::CMapId& obj) {
- platform_id_ = obj.platform_id_;
- encoding_id_ = obj.encoding_id_;
- return *this;
+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;
}
-int CMapTable::CMapId::HashCode() const {
- return platform_id_ << 8 | encoding_id_;
+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 WINDOWS_BMP(PlatformId::kWindows,
- WindowsEncodingId::kUnicodeUCS2);
-CMapTable::CMapId WINDOWS_UCS4(PlatformId::kWindows,
- WindowsEncodingId::kUnicodeUCS4);
-CMapTable::CMapId MAC_ROMAN(PlatformId::kWindows, MacintoshEncodingId::kRoman);
+/******************************************************************************
+ * CMapTable::CMapId class
+ ******************************************************************************/
/******************************************************************************
* CMapTable::CMapIdComparator class
******************************************************************************/
bool CMapTable::CMapIdComparator::operator()(const CMapId& lhs,
- const CMapId& rhs) {
- return lhs.HashCode() > rhs.HashCode();
+ 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);
}
/******************************************************************************
@@ -126,20 +243,59 @@ CMapTable::CMap::Builder::~Builder() {
}
CALLER_ATTACH CMapTable::CMap::Builder*
- CMapTable::CMap::Builder::GetBuilder(ReadableFontData* data,
- int32_t offset,
+ 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 = new CMapFormat0::Builder(data, offset, cmap_id);
+ builder.Attach(CMapFormat0::Builder::NewInstance(data, offset, cmap_id));
break;
case CMapFormat::kFormat2:
- builder = new CMapFormat0::Builder(data, offset, cmap_id);
+#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();
@@ -150,7 +306,8 @@ CMapTable::CMap::Builder::Builder(ReadableFontData* data,
const CMapId& cmap_id)
: SubTable::Builder(data),
format_(format),
- cmap_id_(cmap_id) {
+ cmap_id_(cmap_id),
+ language_(0) {
}
CMapTable::CMap::Builder::Builder(WritableFontData* data,
@@ -158,7 +315,8 @@ CMapTable::CMap::Builder::Builder(WritableFontData* data,
const CMapId& cmap_id)
: SubTable::Builder(data),
format_(format),
- cmap_id_(cmap_id) {
+ cmap_id_(cmap_id),
+ language_(0) {
}
int32_t CMapTable::CMap::Builder::SubSerialize(WritableFontData* new_data) {
@@ -170,7 +328,10 @@ bool CMapTable::CMap::Builder::SubReadyToSerialize() {
}
int32_t CMapTable::CMap::Builder::SubDataSizeToSerialize() {
- return InternalReadData()->Length();
+ ReadableFontDataPtr read_data = InternalReadData();
+ if (!read_data)
+ return 0;
+ return read_data->Length();
}
void CMapTable::CMap::Builder::SubDataSet() {
@@ -191,7 +352,7 @@ int32_t CMapTable::CMapFormat0::GlyphId(int32_t character) {
if (character < 0 || character > 255) {
return CMapTable::NOTDEF;
}
- return data_->ReadByte(character + Offset::kFormat0GlyphIdArray);
+ return data_->ReadUByte(character + Offset::kFormat0GlyphIdArray);
}
CMapTable::CMapFormat0::CMapFormat0(ReadableFontData* data,
@@ -199,29 +360,94 @@ CMapTable::CMapFormat0::CMapFormat0(ReadableFontData* data,
: CMap(data, CMapFormat::kFormat0, cmap_id) {
}
+void
+CMapTable::CMapFormat0::Iterator(CMapTable::CMap::CharacterIterator* output) {
+ output = 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
******************************************************************************/
-CMapTable::CMapFormat0::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::kFormat0, cmap_id) {
- // TODO(arthurhsu): FIXIT: heavy lifting and leak, need fix.
+// 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);
}
-CMapTable::CMapFormat0::Builder::Builder(ReadableFontData* data,
- int32_t offset,
+// 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 ? down_cast<ReadableFontData*>(
- data->Slice(offset, data->ReadUShort(
- offset + Offset::kFormat0Length)))
- : reinterpret_cast<WritableFontData*>(NULL),
- CMapFormat::kFormat0, cmap_id) {
- // TODO(arthurhsu): FIXIT: heavy lifting and leak, need fix.
+ : 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() {
@@ -364,28 +590,6 @@ CALLER_ATTACH FontDataTable*
}
/******************************************************************************
- * CMapTable::Iterator class
- ******************************************************************************/
-CMapTable::CMapIterator::CMapIterator(CMapTable* table, 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;
-}
-
-/******************************************************************************
* CMapTable::Builder class
******************************************************************************/
CMapTable::Builder::Builder(Header* header, WritableFontData* data)
@@ -403,12 +607,12 @@ 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,
- cmap_builders_.size());
+ GetCMapBuilders()->size());
int32_t index_offset = size;
- size += cmap_builders_.size() * CMapTable::Offset::kEncodingRecordSize;
- for (CMapBuilderMap::iterator it = cmap_builders_.begin(),
- e = cmap_builders_.end(); it != e; ++it) {
+ 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());
@@ -424,12 +628,12 @@ int32_t CMapTable::Builder::SubSerialize(WritableFontData* new_data) {
}
bool CMapTable::Builder::SubReadyToSerialize() {
- if (cmap_builders_.empty())
+ if (GetCMapBuilders()->empty())
return false;
// check each table
- for (CMapBuilderMap::iterator it = cmap_builders_.begin(),
- e = cmap_builders_.end(); it != e; ++it) {
+ for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(),
+ e = GetCMapBuilders()->end(); it != e; ++it) {
if (!it->second->SubReadyToSerialize())
return false;
}
@@ -437,16 +641,16 @@ bool CMapTable::Builder::SubReadyToSerialize() {
}
int32_t CMapTable::Builder::SubDataSizeToSerialize() {
- if (cmap_builders_.empty())
+ if (GetCMapBuilders()->empty())
return 0;
bool variable = false;
int32_t size = CMapTable::Offset::kEncodingRecordStart +
- cmap_builders_.size() * CMapTable::Offset::kEncodingRecordSize;
+ GetCMapBuilders()->size() * CMapTable::Offset::kEncodingRecordSize;
// calculate size of each table
- for (CMapBuilderMap::iterator it = cmap_builders_.begin(),
- e = cmap_builders_.end(); it != e; ++it) {
+ 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;
@@ -455,8 +659,8 @@ int32_t CMapTable::Builder::SubDataSizeToSerialize() {
}
void CMapTable::Builder::SubDataSet() {
- cmap_builders_.clear();
- Table::Builder::set_model_changed(false);
+ GetCMapBuilders()->clear();
+ Table::Builder::set_model_changed();
}
CALLER_ATTACH FontDataTable*
@@ -473,6 +677,7 @@ CALLER_ATTACH CMapTable::Builder*
return builder.Detach();
}
+// static
CALLER_ATTACH CMapTable::CMap::Builder*
CMapTable::Builder::CMapBuilder(ReadableFontData* data, int32_t index) {
if (index < 0 || index > NumCMaps(data)) {
@@ -489,10 +694,11 @@ CALLER_ATTACH CMapTable::CMap::Builder*
OffsetForEncodingRecord(index));
int32_t offset = data->ReadULongAsInt(Offset::kEncodingRecordOffset +
OffsetForEncodingRecord(index));
- CMapId cmap_id(platform_id, encoding_id);
- return CMap::Builder::GetBuilder(data, offset, cmap_id);
+ return CMap::Builder::GetBuilder(data, offset,
+ NewCMapId(platform_id, encoding_id));
}
+// static
int32_t CMapTable::Builder::NumCMaps(ReadableFontData* data) {
if (data == NULL) {
return 0;
@@ -500,4 +706,64 @@ int32_t CMapTable::Builder::NumCMaps(ReadableFontData* data) {
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) {
+ Ptr<CMapTable::CMap::Builder> cmap_builder;
+ cmap_builder.Attach(CMapBuilder(data, i));
+ if (!cmap_builder)
+ continue;
+ cmap_builders_[cmap_builder->cmap_id()] = cmap_builder;
+ cmap_builders_.insert(std::make_pair(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
index 6455ef6..2242613 100644
--- a/sfntly/table/core/cmap_table.h
+++ b/sfntly/table/core/cmap_table.h
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-// TODO(arthurhsu): IMPLEMENT: not really used and tested, need cleanup
#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_
#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_
@@ -46,23 +45,12 @@ struct CMapFormat {
class CMapTable : public SubTableContainerTable, public RefCounted<CMapTable> {
public:
// CMapTable::CMapId
- class CMapId {
- public:
- CMapId(int32_t platform_id, int32_t encoding_id);
- CMapId(const CMapId& obj);
-
- int32_t platform_id() { return platform_id_; }
- int32_t encoding_id() { return encoding_id_; }
-
- bool operator==(const CMapId& obj);
- const CMapId& operator=(const CMapId& obj);
- int HashCode() const;
-
- friend class CMapIdComparator;
-
- private:
- int32_t platform_id_;
- int32_t encoding_id_;
+ 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;
@@ -71,7 +59,7 @@ public:
// CMapTable::CMapIdComparator
class CMapIdComparator {
public:
- bool operator()(const CMapId& lhs, const CMapId& rhs);
+ bool operator()(const CMapId& lhs, const CMapId& rhs) const;
};
// A filter on cmap
@@ -81,11 +69,28 @@ 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(CMapId cmap_id) = 0;
+ 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:
+ 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
@@ -93,7 +98,7 @@ public:
// with a given cmap id (pair of platform and encoding ids) no matter what the
// type of the cmap is.
//
- // The cmap implements {@code Iterable<Integer>} to allow iteration over
+ // 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
@@ -101,7 +106,7 @@ public:
// 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
+ // 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;
@@ -116,11 +121,17 @@ public:
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 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,
@@ -138,16 +149,31 @@ public:
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:
+ CharacterIterator() {}
+ 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;
+ };
CMap(ReadableFontData* data, int32_t format, const CMapId& cmap_id);
virtual ~CMap();
+
+ virtual void Iterator(CMapTable::CMap::CharacterIterator* output) = 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(); }
+ 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.
//
@@ -173,32 +199,63 @@ public:
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:
- // CMapTable::CMapFormat0::Builder
+ // 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);
- virtual ~Builder();
+ Builder(
+ const CMapId& cmap_id);
+ };
- protected:
- virtual CALLER_ATTACH FontDataTable*
- SubBuildTable(ReadableFontData* data);
+ // 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);
+ virtual void Iterator(CMap::CharacterIterator* output);
private:
CMapFormat0(ReadableFontData* data, const CMapId& cmap_id);
@@ -225,8 +282,17 @@ public:
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 ~CMapFormat2();
virtual int32_t Language();
virtual int32_t GlyphId(int32_t character);
@@ -236,6 +302,8 @@ public:
// 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);
@@ -244,14 +312,15 @@ public:
int32_t EntryCount(int32_t sub_header_index);
int32_t IdRangeOffset(int32_t sub_header_index);
int32_t IdDelta(int32_t sub_header_index);
+ void Iterator(CMapTable::CMap::CharacterIterator* output) { }
};
// CMapTable::Builder
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.
+ // 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();
@@ -265,18 +334,54 @@ public:
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;
- virtual ~CMapTable();
+ 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();
@@ -296,9 +401,11 @@ public:
// The offset is from the beginning of the table.
virtual int32_t Offset(int32_t index);
- private:
+ 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.
@@ -411,19 +518,6 @@ public:
};
};
- class CMapIterator {
- public:
- // If filter is NULL, filter through all tables.
- CMapIterator(CMapTable* table, CMapFilter* filter);
- bool HasNext();
- CMap* Next();
-
- private:
- int32_t table_index_;
- CMapFilter* filter_;
- CMapTable* table_;
- };
-
CMapTable(Header* header, ReadableFontData* data);
// Get the offset in the table data for the encoding record for the cmap with
diff --git a/sfntly/table/table.cc b/sfntly/table/table.cc
index 7183d38..02f13e7 100644
--- a/sfntly/table/table.cc
+++ b/sfntly/table/table.cc
@@ -74,10 +74,10 @@ Table::Builder* Table::Builder::GetBuilder(Header* header,
// Note: Tables are commented out when they are not used/ported.
// TODO(arthurhsu): IMPLEMENT: finish tables that are not ported.
- /*if (tag == Tag::cmap) {
+ if (tag == Tag::cmap) {
builder_raw = static_cast<Table::Builder*>(
- CMapTable::CreateBuilder(font_builder, header, table_data));
- } else*/ if (tag == Tag::head) {
+ CMapTable::Builder::CreateBuilder(header, table_data));
+ } else if (tag == Tag::head) {
builder_raw = static_cast<Table::Builder*>(
FontHeaderTable::Builder::CreateBuilder(header, table_data));
} else if (tag == Tag::hhea) {