diff options
author | arthurhsu <arthurhsu@google.com> | 2011-10-11 01:01:16 +0000 |
---|---|---|
committer | arthurhsu <arthurhsu@google.com> | 2011-10-11 01:01:16 +0000 |
commit | 158cdcb9cf09418ba8b49f4be7be69e37aa8e9fa (patch) | |
tree | d45ec0d71e59ea8df58331b5005d6e920daedf3e /cpp | |
parent | b4e699e152543000a5825791e1c26826924a256f (diff) | |
download | sfntly-158cdcb9cf09418ba8b49f4be7be69e37aa8e9fa.tar.gz |
Update to Sep 30 snapshot, include all current EBXX support.
Refine Iterator ports: all java-style Iterator objects are ref-counted and have automatic memory management now.
Diffstat (limited to 'cpp')
65 files changed, 4452 insertions, 633 deletions
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index ef3f2db..9a0a189 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -107,4 +107,4 @@ endif(CMAKE_COMPILER_IS_GNUCXX) target_link_libraries(subtly_debug subtly sfntly icuuc) if(CMAKE_COMPILER_IS_GNUCXX) target_link_libraries(subtly_debug pthread) -endif(CMAKE_COMPILER_IS_GNUCXX)
\ No newline at end of file +endif(CMAKE_COMPILER_IS_GNUCXX) diff --git a/cpp/README.txt b/cpp/README.txt index 7472290..ac2b43a 100644 --- a/cpp/README.txt +++ b/cpp/README.txt @@ -1,118 +1,3 @@ -Documentations -============== -Please refer to Java version of this library for APIs and design documents. - - -Build Environment Requirements -============================== -* cmake 2.6 or above -* C++ compiler requirement - ** Windows: Visual C++ 2008, Visual C++ 2010 - ** Linux: g++ 4.3 or above. g++ must support built-in atomic ops and has - companion libstd++. - ** Mac: Apple XCode 3.2.5 or above - - -Before You Build -================ -sfntly is dependent on several external packages. Please follow the -instructions in ext/README-sfntly.txt to download and setup dependent packages. - - -Building on Windows -=================== -1. Open sfntly.vc10.sln (if using Visual C++ 2010) or sfntly.vc9.sln (if using - Visual C++ 2008). Since sfntly use STL extensively, please patch your - Visual Studio for any STL-related hotfixes/service packs. -2. Build the solution. - - -Building on Linux/Mac -===================== -1. Run "cmake ." at the sfntly folder -2. make - - -Porting Guidelines -================== -1. Follow Google C++ Style Guide ( - http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml) with - following exceptions: - a. Exception handling is used. This is unavoidable when we port Java - programs. - b. Nested class are allowed. We try to keep the same class structure for - better maintainability between C++ and Java branches. - c. Functions/members are not grouped in the order of - public/protected/private. Instead, they follow the order appearing in - Java code (except when the order affects compilation). - -2. File structure mapping: - a. src/sfntly maps to java/com/google/typography/fonts/sfntly and all - include files stay with the source. Keep its folder structures intact. - b. All C++ port specific files are placed under src/port. - c. All external dependencies are placed under ext/. - d. All data files are placed under data/. - e. Tests and samples does not map to their Java counterpart since we have - different set of tests and samples. Tests are placed under src/test/ - and samples are placed in src/sample/. - f. Output files are in bin/ and lib/ folder. - g. We have a vc/ folder to store all vcprojects, and two solution files in - root. The goal is to perform everything through cmake and sunset these - files. - -3. Keep existing class structures, except: - a. Namespaces are flatten to sfntly to simplify usage. - b. Public enums are promoted to sfntly namespace within a struct. - c. When we need to get around compiler bugs. - -4. Keep existing naming. Variable names are converted to conform C++ style guide - but should be easily associated with their Java counterpart. - -5. For container data types, they are not returned as object references. - Instead, use an additional function parameter to pass it in. For example: - - byte[] getBuffer(); // Java version, callee new the byte array. - void getBuffer(ByteVector* buffer); // C++ version, caller allocate buffer. - -6. C++ port uses reference-counted object. Please refer to src/port/refcount.h - for usage. - -7. Existing comments in Java code will be copied and maintained in a - best-effort manner. - - -Useful Tips for Debugging Ref-Counting Issue -============================================ - -1. Define ENABLE_OBJECT_COUNTER and REF_COUNT_DEBUGGING. All ref-count related - activity will be ouput to stderr. - -2. The logs will look like (under VC 2010) - - A class RefCounted<class sfntly::Table::Header> const *:oc=2,oid=2,rc=3 - - Use your favorite editor to transform them into SQL statements, e.g. - - regex pattern: - ^([ACDR]) class RefCounted<class sfntly::([A-Za-z0-9:]+)>[ *const]+:oc=([-0-9]+),oid=([0-9]+),rc=([-0-9]+) - - replace to: - - insert into log values('\1', '\2', \3, \4, \5); - -3. Add one line to the beginning of log: - - create table log(action char(1), class_name char(30), oc integer, oid integer, rc integer); - -4. Run sqlite shell, use .read to input the SQL file. -5. Run following commands to get the leaking object class and object id: - - create table todrop(class_name char(30), oid integer); - insert into todrop select class_name, oid from log where action='D'; - create table tocreate (class_name char(30), oid integer); - insert into tocreate select class_name, oid from log where action='C'; - select * from tocreate except select * from todrop; - -6. Once you know which object is leaking, it's much easier to setup conditional - breakpoints to identify the real culprit. +Please refer to http://code.google.com/p/sfntly/wiki/build_cpp regarding how to build sfntly. +sfntly wiki contains other useful documents: http://code.google.com/p/sfntly/w/list
\ No newline at end of file diff --git a/cpp/ext/README-sfntly.txt b/cpp/ext/README-sfntly.txt deleted file mode 100644 index f8c4755..0000000 --- a/cpp/ext/README-sfntly.txt +++ /dev/null @@ -1,24 +0,0 @@ -sfntly is dependent on the following components: - -1. Google C++ Testing Framework. - -Please download from http://code.google.com/p/googletest/, extract it into -this folder, and rename/symbolic link to gtest. - -Tested with gTest 1.6.0. - -2. ICU - -For Linux/Mac, default ICU headers in system will be used. Linux users -please make sure you have dev packages for ICU. For example, you can - -sudo apt-get install libicu-dev - -in Ubuntu and see if the required library is installed. - -For Windows, download from http://site.icu-project.org/download. Tested with -ICU 4.6.1 binary release. You can also provide your own ICU package. However, -you need to alter the include path, library path, and provide icudt.dll. - -We have included gtest and icu in ext/redist. - diff --git a/cpp/src/sfntly/data/byte_array.cc b/cpp/src/sfntly/data/byte_array.cc index c820adc..915a40c 100644 --- a/cpp/src/sfntly/data/byte_array.cc +++ b/cpp/src/sfntly/data/byte_array.cc @@ -115,13 +115,7 @@ int32_t ByteArray::CopyTo(int32_t dst_offset, ByteArray* array, while ((bytes_read = Get(index + src_offset, &(b[0]), 0, buffer_length)) > 0) { int bytes_written = array->Put(index + dst_offset, &(b[0]), 0, bytes_read); - if (bytes_written != bytes_read) { -#if defined (SFNTLY_NO_EXCEPTION) - return 0; -#else - throw IOException("Error writing bytes."); -#endif - } + UNREFERENCED_PARAMETER(bytes_written); index += bytes_read; remaining_length -= bytes_read; buffer_length = std::min<int32_t>(b.size(), remaining_length); diff --git a/cpp/src/sfntly/data/font_data.cc b/cpp/src/sfntly/data/font_data.cc index ccc2a19..d2b95ea 100644 --- a/cpp/src/sfntly/data/font_data.cc +++ b/cpp/src/sfntly/data/font_data.cc @@ -58,7 +58,9 @@ FontData::FontData(FontData* data, int32_t offset, int32_t length) { FontData::FontData(FontData* data, int32_t offset) { Init(data->array_); - Bound(data->bound_offset_ + offset); + Bound(data->bound_offset_ + offset, + (data->bound_length_ == GROWABLE_SIZE) + ? GROWABLE_SIZE : data->bound_length_ - offset); } FontData::~FontData() {} @@ -66,7 +68,7 @@ FontData::~FontData() {} void FontData::Init(ByteArray* ba) { array_ = ba; bound_offset_ = 0; - bound_length_ = INT_MAX; + bound_length_ = GROWABLE_SIZE; } int32_t FontData::BoundOffset(int32_t offset) { diff --git a/cpp/src/sfntly/data/font_data.h b/cpp/src/sfntly/data/font_data.h index ec87c72..d02e8b7 100644 --- a/cpp/src/sfntly/data/font_data.h +++ b/cpp/src/sfntly/data/font_data.h @@ -17,6 +17,8 @@ #ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_ #define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_ +#include <limits.h> + #include <vector> #include "sfntly/port/type.h" @@ -110,12 +112,15 @@ class FontData : virtual public RefCount { // @return the bound compensated offset int32_t BoundOffset(int32_t offset); - // Gets the length in the underlying data taking into account any bounds on the data. + // Gets the length in the underlying data taking into account any bounds on + // the data. // @param offset the offset that the length is being used at // @param length the length to get the bound compensated length for // @return the bound compensated length int32_t BoundLength(int32_t offset, int32_t length); + static const int32_t GROWABLE_SIZE = INT_MAX; + // TODO(arthurhsu): style guide violation: refactor this protected member ByteArrayPtr array_; diff --git a/cpp/src/sfntly/data/readable_font_data.cc b/cpp/src/sfntly/data/readable_font_data.cc index fb083cb..bb58c26 100644 --- a/cpp/src/sfntly/data/readable_font_data.cc +++ b/cpp/src/sfntly/data/readable_font_data.cc @@ -121,6 +121,13 @@ int32_t ReadableFontData::ReadULongAsInt(int32_t index) { return static_cast<int32_t>(ulong); } +int64_t ReadableFontData::ReadULongLE(int32_t index) { + return 0xffffffffL & (ReadUByte(index) | + ReadUByte(index + 1) << 8 | + ReadUByte(index + 2) << 16 | + ReadUByte(index + 3) << 24); +} + int32_t ReadableFontData::ReadLong(int32_t index) { return ReadByte(index) << 24 | ReadUByte(index + 1) << 16 | diff --git a/cpp/src/sfntly/data/readable_font_data.h b/cpp/src/sfntly/data/readable_font_data.h index c5833e8..b43c626 100644 --- a/cpp/src/sfntly/data/readable_font_data.h +++ b/cpp/src/sfntly/data/readable_font_data.h @@ -128,6 +128,12 @@ class ReadableFontData : public FontData, // @throws IndexOutOfBoundsException if index is outside the FontData's range virtual int32_t ReadULongAsInt(int32_t index); + // Read the ULONG at the given index, little-endian variant + // @param index index into the font data + // @return the ULONG + // @throws IndexOutOfBoundsException if index is outside the FontData's range + virtual int64_t ReadULongLE(int32_t index); + // Read the LONG at the given index. // @param index index into the font data // @return the LONG diff --git a/cpp/src/sfntly/data/writable_font_data.cc b/cpp/src/sfntly/data/writable_font_data.cc index 0b271a3..ace387c 100644 --- a/cpp/src/sfntly/data/writable_font_data.cc +++ b/cpp/src/sfntly/data/writable_font_data.cc @@ -82,12 +82,22 @@ int32_t WritableFontData::WriteBytesPad(int32_t index, offset, BoundLength(index, std::min<int32_t>(length, b->size() - offset))); - for (; written < length; written++) { - array_->Put(written + index, pad); - } + written += WritePadding(written + index, length - written, pad); return written; } +int32_t WritableFontData::WritePadding(int32_t index, int32_t count) { + return WritePadding(index, count, (byte_t)0); +} + +int32_t WritableFontData::WritePadding(int32_t index, int32_t count, + byte_t pad) { + for (int32_t i = 0; i < count; ++i) { + array_->Put(index + i, pad); + } + return count; +} + int32_t WritableFontData::WriteChar(int32_t index, byte_t c) { return WriteByte(index, c); } diff --git a/cpp/src/sfntly/data/writable_font_data.h b/cpp/src/sfntly/data/writable_font_data.h index 9a9bd7b..f88a986 100644 --- a/cpp/src/sfntly/data/writable_font_data.h +++ b/cpp/src/sfntly/data/writable_font_data.h @@ -85,6 +85,19 @@ class WritableFontData : public ReadableFontData { int32_t length, byte_t pad); + // Writes padding to the FontData. The padding byte written is 0x00.
+ // @param index index into the font data
+ // @param count the number of pad bytes to write
+ // @return the number of pad bytes written + virtual int32_t WritePadding(int32_t index, int32_t count); + + // Writes padding to the FontData.
+ // @param index index into the font data
+ // @param count the number of pad bytes to write
+ // @param pad the byte value to use as padding
+ // @return the number of pad bytes written + virtual int32_t WritePadding(int32_t index, int32_t count, byte_t pad); + // Write the CHAR at the given index. // @param index index into the font data // @param c the CHAR diff --git a/cpp/src/sfntly/font.cc b/cpp/src/sfntly/font.cc index 524932b..3fa77b0 100644 --- a/cpp/src/sfntly/font.cc +++ b/cpp/src/sfntly/font.cc @@ -295,15 +295,9 @@ Table::Builder* Font::Builder::NewTableBuilder(int32_t tag, assert(src_data); WritableFontDataPtr data; data.Attach(WritableFontData::CreateWritableFontData(src_data->Length())); -#if !defined (SFNTLY_NO_EXCEPTION) - try { -#endif - src_data->CopyTo(data); -#if !defined (SFNTLY_NO_EXCEPTION) - } catch (IOException& e) { - return NULL; - } -#endif + // TODO(stuarg): take over original data instead? + src_data->CopyTo(data); + HeaderPtr header = new Header(tag, data->Length()); TableBuilderPtr builder; builder.Attach(Table::Builder::GetBuilder(header, data)); @@ -378,19 +372,7 @@ void Font::Builder::BuildTablesFromBuilders(Font* font, builder != builder_end; ++builder) { TablePtr table; if (builder->second && builder->second->ReadyToBuild()) { -#if !defined (SFNTLY_NO_EXCEPTION) - try { -#endif - table.Attach(down_cast<Table*>(builder->second->Build())); -#if !defined (SFNTLY_NO_EXCEPTION) - } catch(IOException& e) { - std::string builder_string = "Unable to build table - "; - char* table_name = TagToString(builder->first); - builder_string += table_name; - delete[] table_name; - throw RuntimeException(builder_string.c_str()); - } -#endif + table.Attach(down_cast<Table*>(builder->second->Build())); } if (table == NULL) { table_map->clear(); diff --git a/cpp/src/sfntly/math/font_math.h b/cpp/src/sfntly/math/font_math.h index c469347..f1cd2d2 100644 --- a/cpp/src/sfntly/math/font_math.h +++ b/cpp/src/sfntly/math/font_math.h @@ -31,6 +31,17 @@ class FontMath { } return r - 1; } + + // Calculates the amount of padding needed. The values provided need to be in + // the same units. So, if the size is given as the number of bytes then the + // alignment size must also be specified as byte size to align to. + // @param size the size of the data that may need padding + // @param alignmentSize the number of units to align to + // @return the number of units needing to be added for alignment + static int32_t PaddingRequired(int32_t size, int32_t alignment_size) { + int32_t padding = alignment_size - (size % alignment_size); + return padding == alignment_size ? 0 : padding; + } }; } // namespace sfntly diff --git a/cpp/src/sfntly/port/java_iterator.h b/cpp/src/sfntly/port/java_iterator.h new file mode 100644 index 0000000..0a99bca --- /dev/null +++ b/cpp/src/sfntly/port/java_iterator.h @@ -0,0 +1,94 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_ +#define SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_ + +#include "sfntly/port/refcount.h" + +// Interface of Java iterator. +// This is a forward read-only iterator that represents java.util.Iterator<E> + +namespace sfntly { + +template <typename ReturnType, typename ContainerBase> +class Iterator : public virtual RefCount { + public: + virtual ~Iterator() {} + virtual ContainerBase* container_base() = 0; + + protected: + Iterator() {} + NO_COPY_AND_ASSIGN(Iterator); +}; + +template <typename ReturnType, typename Container, + typename ContainerBase = Container> +class PODIterator : public Iterator<ReturnType, ContainerBase>, + public RefCounted< PODIterator<ReturnType, Container> > { + public: + explicit PODIterator(Container* container) : container_(container) {} + virtual ~PODIterator() {} + virtual ContainerBase* container_base() { + return static_cast<ContainerBase*>(container_); + } + + virtual bool HasNext() = 0; + virtual ReturnType Next() = 0; + virtual void Remove() { +#if !defined (SFNTLY_NO_EXCEPTION) + // Default to no support. + throw UnsupportedOperationException(); +#endif + } + + protected: + Container* container() { return container_; } + + private: + Container* container_; // Dumb pointer is used to avoid circular ref-counting +}; + +template <typename ReturnType, typename Container, + typename ContainerBase = Container> +class RefIterator : public Iterator<ReturnType, ContainerBase>, + public RefCounted< RefIterator<ReturnType, Container> > { + public: + explicit RefIterator(Container* container) : container_(container) {} + virtual ~RefIterator() {} + virtual ContainerBase* container_base() { + return static_cast<ContainerBase*>(container_); + } + + virtual bool HasNext() = 0; + CALLER_ATTACH virtual ReturnType* Next() = 0; + virtual void Remove() { +#if !defined (SFNTLY_NO_EXCEPTION) + // Default to no support. + throw UnsupportedOperationException(); +#endif + } + + protected: + Container* container() { return container_; } + + private: + Container* container_; // Dumb pointer is used to avoid circular ref-counting +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_ diff --git a/cpp/src/sfntly/table/bitmap/big_glyph_metrics.cc b/cpp/src/sfntly/table/bitmap/big_glyph_metrics.cc new file mode 100644 index 0000000..d2519cd --- /dev/null +++ b/cpp/src/sfntly/table/bitmap/big_glyph_metrics.cc @@ -0,0 +1,162 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/big_glyph_metrics.h" + +namespace sfntly { +/****************************************************************************** + * BigGlyphMetrics class + ******************************************************************************/ +BigGlyphMetrics::BigGlyphMetrics(ReadableFontData* data) + : GlyphMetrics(data) { +} + +BigGlyphMetrics::~BigGlyphMetrics() { +} + +int32_t BigGlyphMetrics::Height() { + return data_->ReadByte(Offset::kHeight); +} + +int32_t BigGlyphMetrics::Width() { + return data_->ReadByte(Offset::kWidth); +} + +int32_t BigGlyphMetrics::HoriBearingX() { + return data_->ReadByte(Offset::kHoriBearingX); +} + +int32_t BigGlyphMetrics::HoriBearingY() { + return data_->ReadByte(Offset::kHoriBearingY); +} + +int32_t BigGlyphMetrics::HoriAdvance() { + return data_->ReadByte(Offset::kHoriAdvance); +} + +int32_t BigGlyphMetrics::VertBearingX() { + return data_->ReadByte(Offset::kVertBearingX); +} + +int32_t BigGlyphMetrics::VertBearingY() { + return data_->ReadByte(Offset::kVertBearingY); +} + +int32_t BigGlyphMetrics::VertAdvance() { + return data_->ReadByte(Offset::kVertAdvance); +} + +/****************************************************************************** + * BigGlyphMetrics::Builder class + ******************************************************************************/ +BigGlyphMetrics::Builder::Builder(WritableFontData* data) + : GlyphMetrics::Builder(data) { +} + +BigGlyphMetrics::Builder::Builder(ReadableFontData* data) + : GlyphMetrics::Builder(data) { +} + +BigGlyphMetrics::Builder::~Builder() { +} + +int32_t BigGlyphMetrics::Builder::Height() { + return InternalReadData()->ReadByte(Offset::kHeight); +} + +void BigGlyphMetrics::Builder::SetHeight(byte_t height) { + InternalWriteData()->WriteByte(Offset::kHeight, height); +} + +int32_t BigGlyphMetrics::Builder::Width() { + return InternalReadData()->ReadByte(Offset::kWidth); +} + +void BigGlyphMetrics::Builder::SetWidth(byte_t width) { + InternalWriteData()->WriteByte(Offset::kWidth, width); +} + +int32_t BigGlyphMetrics::Builder::HoriBearingX() { + return InternalReadData()->ReadByte(Offset::kHoriBearingX); +} + +void BigGlyphMetrics::Builder::SetHoriBearingX(byte_t bearing) { + InternalWriteData()->WriteByte(Offset::kHoriBearingX, bearing); +} + +int32_t BigGlyphMetrics::Builder::HoriBearingY() { + return InternalReadData()->ReadByte(Offset::kHoriBearingY); +} + +void BigGlyphMetrics::Builder::SetHoriBearingY(byte_t bearing) { + InternalWriteData()->WriteByte(Offset::kHoriBearingY, bearing); +} + +int32_t BigGlyphMetrics::Builder::HoriAdvance() { + return InternalReadData()->ReadByte(Offset::kHoriAdvance); +} + +void BigGlyphMetrics::Builder::SetHoriAdvance(byte_t advance) { + InternalWriteData()->WriteByte(Offset::kHoriAdvance, advance); +} + +int32_t BigGlyphMetrics::Builder::VertBearingX() { + return InternalReadData()->ReadByte(Offset::kVertBearingX); +} + +void BigGlyphMetrics::Builder::SetVertBearingX(byte_t bearing) { + InternalWriteData()->WriteByte(Offset::kVertBearingX, bearing); +} + +int32_t BigGlyphMetrics::Builder::VertBearingY() { + return InternalReadData()->ReadByte(Offset::kVertBearingY); +} + +void BigGlyphMetrics::Builder::SetVertBearingY(byte_t bearing) { + InternalWriteData()->WriteByte(Offset::kVertBearingY, bearing); +} + +int32_t BigGlyphMetrics::Builder::VertAdvance() { + return InternalReadData()->ReadByte(Offset::kVertAdvance); +} + +void BigGlyphMetrics::Builder::SetVertAdvance(byte_t advance) { + InternalWriteData()->WriteByte(Offset::kVertAdvance, advance); +} + +CALLER_ATTACH FontDataTable* + BigGlyphMetrics::Builder::SubBuildTable(ReadableFontData* data) { + BigGlyphMetricsPtr output = new BigGlyphMetrics(data); + return output.Detach(); +} + +void BigGlyphMetrics::Builder::SubDataSet() { + // NOP. +} + +int32_t BigGlyphMetrics::Builder::SubDataSizeToSerialize() { + return 0; +} + +bool BigGlyphMetrics::Builder::SubReadyToSerialize() { + return false; +} + +int32_t BigGlyphMetrics::Builder::SubSerialize(WritableFontData* new_data) { + return Data()->CopyTo(new_data); +} + +} // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/big_glyph_metrics.h b/cpp/src/sfntly/table/bitmap/big_glyph_metrics.h new file mode 100644 index 0000000..55963b4 --- /dev/null +++ b/cpp/src/sfntly/table/bitmap/big_glyph_metrics.h @@ -0,0 +1,92 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_ + +#include "sfntly/table/bitmap/glyph_metrics.h" + +namespace sfntly { + +class BigGlyphMetrics : public GlyphMetrics, + public RefCounted<BigGlyphMetrics> { + public: + struct Offset { + enum { + kMetricsLength = 8, + + kHeight = 0, + kWidth = 1, + kHoriBearingX = 2, + kHoriBearingY = 3, + kHoriAdvance = 4, + kVertBearingX = 5, + kVertBearingY = 6, + kVertAdvance = 7, + }; + }; + + class Builder : public GlyphMetrics::Builder, + public RefCounted<Builder> { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + explicit Builder(WritableFontData* data); + explicit Builder(ReadableFontData* data); + virtual ~Builder(); + + int32_t Height(); + void SetHeight(byte_t height); + int32_t Width(); + void SetWidth(byte_t width); + int32_t HoriBearingX(); + void SetHoriBearingX(byte_t bearing); + int32_t HoriBearingY(); + void SetHoriBearingY(byte_t bearing); + int32_t HoriAdvance(); + void SetHoriAdvance(byte_t advance); + int32_t VertBearingX(); + void SetVertBearingX(byte_t bearing); + int32_t VertBearingY(); + void SetVertBearingY(byte_t bearing); + int32_t VertAdvance(); + void SetVertAdvance(byte_t advance); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + }; + + explicit BigGlyphMetrics(ReadableFontData* data); + virtual ~BigGlyphMetrics(); + + int32_t Height(); + int32_t Width(); + int32_t HoriBearingX(); + int32_t HoriBearingY(); + int32_t HoriAdvance(); + int32_t VertBearingX(); + int32_t VertBearingY(); + int32_t VertAdvance(); +}; +typedef Ptr<BigGlyphMetrics> BigGlyphMetricsPtr; +typedef Ptr<BigGlyphMetrics::Builder> BigGlyphMetricsBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_ diff --git a/cpp/src/sfntly/table/bitmap/bitmap_glyph.cc b/cpp/src/sfntly/table/bitmap/bitmap_glyph.cc index 82d78b3..334a0c0 100644 --- a/cpp/src/sfntly/table/bitmap/bitmap_glyph.cc +++ b/cpp/src/sfntly/table/bitmap/bitmap_glyph.cc @@ -15,6 +15,8 @@ */ #include "sfntly/table/bitmap/bitmap_glyph.h" +#include "sfntly/table/bitmap/simple_bitmap_glyph.h" +#include "sfntly/table/bitmap/composite_bitmap_glyph.h" namespace sfntly { /****************************************************************************** @@ -23,6 +25,17 @@ namespace sfntly { BitmapGlyph::~BitmapGlyph() { } +CALLER_ATTACH BitmapGlyph* BitmapGlyph::CreateGlyph(ReadableFontData* data, + int32_t format) { + BitmapGlyphPtr glyph; + BitmapGlyphBuilderPtr builder; + builder.Attach(Builder::CreateGlyphBuilder(data, format)); + if (builder) { + glyph.Attach(down_cast<BitmapGlyph*>(builder->Build())); + } + return glyph; +} + BitmapGlyph::BitmapGlyph(ReadableFontData* data, int32_t format) : SubTable(data), format_(format) { } @@ -33,12 +46,34 @@ BitmapGlyph::BitmapGlyph(ReadableFontData* data, int32_t format) BitmapGlyph::Builder::~Builder() { } -BitmapGlyph::Builder::Builder(WritableFontData* data) - : SubTable::Builder(data) { +CALLER_ATTACH BitmapGlyph::Builder* +BitmapGlyph::Builder::CreateGlyphBuilder(ReadableFontData* data, + int32_t format) { + BitmapGlyphBuilderPtr builder; + switch (format) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + builder = new SimpleBitmapGlyph::Builder(data, format); + break; + case 8: + case 9: + builder = new CompositeBitmapGlyph::Builder(data, format); + break; + } + return builder.Detach(); +} + +BitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format) + : SubTable::Builder(data), format_(format) { } -BitmapGlyph::Builder::Builder(ReadableFontData* data) - : SubTable::Builder(data) { +BitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format) + : SubTable::Builder(data), format_(format) { } CALLER_ATTACH @@ -48,19 +83,19 @@ FontDataTable* BitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) { } void BitmapGlyph::Builder::SubDataSet() { + // NOP } int32_t BitmapGlyph::Builder::SubDataSizeToSerialize() { - return 0; + return InternalReadData()->Length(); } bool BitmapGlyph::Builder::SubReadyToSerialize() { - return false; + return true; } int32_t BitmapGlyph::Builder::SubSerialize(WritableFontData* new_data) { - UNREFERENCED_PARAMETER(new_data); - return 0; + return InternalReadData()->CopyTo(new_data); } } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/bitmap_glyph.h b/cpp/src/sfntly/table/bitmap/bitmap_glyph.h index 47afbe1..2dd4c3a 100644 --- a/cpp/src/sfntly/table/bitmap/bitmap_glyph.h +++ b/cpp/src/sfntly/table/bitmap/bitmap_glyph.h @@ -17,6 +17,9 @@ #ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_ #define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_ +#include <vector> +#include <map> + #include "sfntly/table/subtable.h" namespace sfntly { @@ -73,18 +76,29 @@ class BitmapGlyph : public SubTable { public: virtual ~Builder(); - protected: - Builder(WritableFontData* data); - Builder(ReadableFontData* data); - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); virtual void SubDataSet(); virtual int32_t SubDataSizeToSerialize(); virtual bool SubReadyToSerialize(); virtual int32_t SubSerialize(WritableFontData* new_data); + + int32_t format() { return format_; } + + static CALLER_ATTACH Builder* CreateGlyphBuilder(ReadableFontData* data, + int32_t format); + + protected: + Builder(WritableFontData* data, int32_t format); + Builder(ReadableFontData* data, int32_t format); + + private: + int32_t format_; }; virtual ~BitmapGlyph(); + + static CALLER_ATTACH BitmapGlyph* CreateGlyph(ReadableFontData* data, + int32_t format); int32_t format() { return format_; } // UNIMPLEMENTED: toString() @@ -96,6 +110,9 @@ class BitmapGlyph : public SubTable { int32_t format_; }; typedef Ptr<BitmapGlyph> BitmapGlyphPtr; +typedef Ptr<BitmapGlyph::Builder> BitmapGlyphBuilderPtr; +typedef std::map<int32_t, BitmapGlyphBuilderPtr> BitmapGlyphBuilderMap; +typedef std::vector<BitmapGlyphBuilderMap> BitmapGlyphBuilderList; } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.cc b/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.cc new file mode 100644 index 0000000..ab9953b --- /dev/null +++ b/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.cc @@ -0,0 +1,68 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/bitmap_glyph_info.h" + +namespace sfntly { + +BitmapGlyphInfo::BitmapGlyphInfo(int32_t glyph_id, + int32_t block_offset, + int32_t start_offset, + int32_t length, + int32_t format) + : glyph_id_(glyph_id), + relative_(true), + block_offset_(block_offset), + start_offset_(start_offset), + length_(length), + format_(format) { +} + +BitmapGlyphInfo::BitmapGlyphInfo(int32_t glyph_id, + int32_t start_offset, + int32_t length, + int32_t format) + : glyph_id_(glyph_id), + relative_(false), + block_offset_(0), + start_offset_(start_offset), + length_(length), + format_(format) { +} + +bool BitmapGlyphInfo::operator==(const BitmapGlyphInfo& rhs) const { + return (format_ == rhs.format_ && + glyph_id_ == rhs.glyph_id_ && + length_ == rhs.length_ && + offset() == rhs.offset()); +} + +bool BitmapGlyphInfo::operator==(BitmapGlyphInfo* rhs) { + if (rhs == NULL) { + return this == NULL; + } + return (format_ == rhs->format() && + glyph_id_ == rhs->glyph_id() && + length_ == rhs->length() && + offset() == rhs->offset()); +} + +bool StartOffsetComparator::operator()(BitmapGlyphInfo* lhs, + BitmapGlyphInfo* rhs) { + return lhs->start_offset() > rhs->start_offset(); +} + +} // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.h b/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.h new file mode 100644 index 0000000..9921d0d --- /dev/null +++ b/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.h @@ -0,0 +1,85 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_ + +#include <vector> +#include <map> + +#include "sfntly/table/subtable.h" + +namespace sfntly { + +// An immutable class holding bitmap glyph information. +class BitmapGlyphInfo : public RefCounted<BitmapGlyphInfo> { + public: + // Constructor for a relative located glyph. The glyph's position in the EBDT + // table is a combination of it's block offset and it's own start offset. + // @param glyphId the glyph id + // @param blockOffset the offset of the block to which the glyph belongs + // @param startOffset the offset of the glyph within the block + // @param length the byte length + // @param format the glyph image format + BitmapGlyphInfo(int32_t glyph_id, + int32_t block_offset, + int32_t start_offset, + int32_t length, + int32_t format); + + // Constructor for an absolute located glyph. The glyph's position in the EBDT + // table is only given by it's own start offset. + // @param glyphId the glyph id + // @param startOffset the offset of the glyph within the block + // @param length the byte length + // @param format the glyph image format + BitmapGlyphInfo(int32_t glyph_id, + int32_t start_offset, + int32_t length, + int32_t format); + + int32_t glyph_id() const { return glyph_id_; } + bool relative() const { return relative_; } + int32_t block_offset() const { return block_offset_; } + int32_t offset() const { return block_offset() + start_offset(); } + int32_t start_offset() const { return start_offset_; } + int32_t length() const { return length_; } + int32_t format() const { return format_; } + + // UNIMPLEMENTED: hashCode() + bool operator==(const BitmapGlyphInfo& rhs) const; + bool operator==(BitmapGlyphInfo* rhs); + + private: + int32_t glyph_id_; + bool relative_; + int32_t block_offset_; + int32_t start_offset_; + int32_t length_; + int32_t format_; +}; +typedef Ptr<BitmapGlyphInfo> BitmapGlyphInfoPtr; +typedef std::map<int32_t, BitmapGlyphInfoPtr> BitmapGlyphInfoMap; +typedef std::vector<BitmapGlyphInfoMap> BitmapLocaList; + +class StartOffsetComparator { + public: + bool operator()(BitmapGlyphInfo* lhs, BitmapGlyphInfo* rhs); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_ diff --git a/cpp/src/sfntly/table/bitmap/bitmap_size_table.cc b/cpp/src/sfntly/table/bitmap/bitmap_size_table.cc index 00488ea..93b8625 100644 --- a/cpp/src/sfntly/table/bitmap/bitmap_size_table.cc +++ b/cpp/src/sfntly/table/bitmap/bitmap_size_table.cc @@ -16,16 +16,19 @@ #include "sfntly/table/bitmap/bitmap_size_table.h" +#include <stdlib.h> + #include "sfntly/table/bitmap/eblc_table.h" +#include "sfntly/table/bitmap/index_sub_table_format1.h" +#include "sfntly/table/bitmap/index_sub_table_format2.h" +#include "sfntly/table/bitmap/index_sub_table_format3.h" +#include "sfntly/table/bitmap/index_sub_table_format4.h" +#include "sfntly/table/bitmap/index_sub_table_format5.h" namespace sfntly { - -BitmapSizeTable::BitmapSizeTable(ReadableFontData* data, - ReadableFontData* master_data) - : SubTable(data) { - master_data_ = master_data; -} - +/****************************************************************************** + * BitmapSizeTable class + ******************************************************************************/ BitmapSizeTable::~BitmapSizeTable() { } @@ -40,8 +43,7 @@ int32_t BitmapSizeTable::IndexTableSize() { } int32_t BitmapSizeTable::NumberOfIndexSubTables() { - return data_->ReadULongAsInt( - EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables); + return NumberOfIndexSubTables(data_, 0); } int32_t BitmapSizeTable::ColorRef() { @@ -96,6 +98,14 @@ int32_t BitmapSizeTable::GlyphLength(int32_t glyph_id) { return subtable->GlyphLength(glyph_id); } +CALLER_ATTACH BitmapGlyphInfo* BitmapSizeTable::GlyphInfo(int32_t glyph_id) { + IndexSubTable* sub_table = SearchIndexSubTables(glyph_id); + if (sub_table == NULL) { + return NULL; + } + return sub_table->GlyphInfo(glyph_id); +} + int32_t BitmapSizeTable::GlyphFormat(int32_t glyph_id) { IndexSubTable* subtable = SearchIndexSubTables(glyph_id); if (subtable == NULL) { @@ -104,7 +114,41 @@ int32_t BitmapSizeTable::GlyphFormat(int32_t glyph_id) { return subtable->image_format(); } +BitmapSizeTable::BitmapSizeTable(ReadableFontData* data, + ReadableFontData* master_data) + : SubTable(data, master_data) { +} + +// static +int32_t BitmapSizeTable::NumberOfIndexSubTables(ReadableFontData* data, + int32_t table_offset) { + return data->ReadULongAsInt(table_offset + + EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables); +} + IndexSubTable* BitmapSizeTable::SearchIndexSubTables(int32_t glyph_id) { + // would be faster to binary search but too many size tables don't have + // sorted subtables +#if (SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH) + return BinarySearchIndexSubTables(glyph_id); +#else + return LinearSearchIndexSubTables(glyph_id); +#endif +} + +IndexSubTable* BitmapSizeTable::LinearSearchIndexSubTables(int32_t glyph_id) { + IndexSubTableList* subtable_list = GetIndexSubTableList(); + for (IndexSubTableList::iterator b = subtable_list->begin(), + e = subtable_list->end(); b != e; b++) { + if ((*b)->first_glyph_index() <= glyph_id && + (*b)->last_glyph_index() >= glyph_id) { + return *b; + } + } + return NULL; +} + +IndexSubTable* BitmapSizeTable::BinarySearchIndexSubTables(int32_t glyph_id) { IndexSubTableList* subtable_list = GetIndexSubTableList(); int32_t index = 0; int32_t bottom = 0; @@ -128,21 +172,389 @@ IndexSubTable* BitmapSizeTable::SearchIndexSubTables(int32_t glyph_id) { CALLER_ATTACH IndexSubTable* BitmapSizeTable::CreateIndexSubTable(int32_t index) { - return IndexSubTable::CreateIndexSubTable(master_data_, + return IndexSubTable::CreateIndexSubTable(master_read_data(), IndexSubTableArrayOffset(), index); } IndexSubTableList* BitmapSizeTable::GetIndexSubTableList() { - AutoLock lock(atomic_subtables_lock_); - if (atomic_subtables.empty()) { + AutoLock lock(index_subtables_lock_); + if (index_subtables_.empty()) { for (int32_t i = 0; i < NumberOfIndexSubTables(); ++i) { IndexSubTablePtr table; table.Attach(CreateIndexSubTable(i)); - atomic_subtables.push_back(table); + index_subtables_.push_back(table); + } + } + return &index_subtables_; +} + +/****************************************************************************** + * BitmapSizeTable::Builder class + ******************************************************************************/ +BitmapSizeTable::Builder::~Builder() { +} + +CALLER_ATTACH +FontDataTable* BitmapSizeTable::Builder::SubBuildTable(ReadableFontData* data) { + BitmapSizeTablePtr output = new BitmapSizeTable(data, master_read_data()); + return output.Detach(); +} + +void BitmapSizeTable::Builder::SubDataSet() { + Revert(); +} + +int32_t BitmapSizeTable::Builder::SubDataSizeToSerialize() { + IndexSubTableBuilderList* builders = IndexSubTableBuilders(); + if (builders->empty()) { + return 0; + } + int32_t size = EblcTable::Offset::kBitmapSizeTableLength; + bool variable = false; + for (IndexSubTableBuilderList::iterator b = builders->begin(), + e = builders->end(); b != e; b++) { + size += EblcTable::Offset::kIndexSubTableEntryLength; + int32_t sub_table_size = (*b)->SubDataSizeToSerialize(); + variable = (sub_table_size > 0) ? variable : true; + size += abs(sub_table_size); + } + return size; +} + +bool BitmapSizeTable::Builder::SubReadyToSerialize() { + if (IndexSubTableBuilders()->empty()) { + return false; + } + return true; +} + +int32_t BitmapSizeTable::Builder::SubSerialize(WritableFontData* new_data) { + SetNumberOfIndexSubTables(IndexSubTableBuilders()->size()); + int32_t size = InternalReadData()->CopyTo(new_data); + return size; +} + +CALLER_ATTACH BitmapSizeTable::Builder* +BitmapSizeTable::Builder::CreateBuilder(WritableFontData* data, + ReadableFontData* master_data) { + BitmapSizeTableBuilderPtr output = + new BitmapSizeTable::Builder(data, master_data); + return output.Detach(); +} + +CALLER_ATTACH BitmapSizeTable::Builder* +BitmapSizeTable::Builder::CreateBuilder(ReadableFontData* data, + ReadableFontData* master_data) { + BitmapSizeTableBuilderPtr output = + new BitmapSizeTable::Builder(data, master_data); + return output.Detach(); +} + +int32_t BitmapSizeTable::Builder::IndexSubTableArrayOffset() { + return InternalReadData()->ReadULongAsInt( + EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset); +} + +void BitmapSizeTable::Builder::SetIndexSubTableArrayOffset(int32_t offset) { + InternalWriteData()->WriteULong( + EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset, offset); +} + +int32_t BitmapSizeTable::Builder::IndexTableSize() { + return InternalReadData()->ReadULongAsInt( + EblcTable::Offset::kBitmapSizeTable_indexTableSize); +} + +void BitmapSizeTable::Builder::SetIndexTableSize(int32_t size) { + InternalWriteData()->WriteULong( + EblcTable::Offset::kBitmapSizeTable_indexTableSize, size); +} + +int32_t BitmapSizeTable::Builder::NumberOfIndexSubTables() { + return GetIndexSubTableBuilders()->size(); +} + +int32_t BitmapSizeTable::Builder::ColorRef() { + return InternalReadData()->ReadULongAsInt( + EblcTable::Offset::kBitmapSizeTable_colorRef); +} + +int32_t BitmapSizeTable::Builder::StartGlyphIndex() { + return InternalReadData()->ReadUShort( + EblcTable::Offset::kBitmapSizeTable_startGlyphIndex); +} + +int32_t BitmapSizeTable::Builder::EndGlyphIndex() { + return InternalReadData()->ReadUShort( + EblcTable::Offset::kBitmapSizeTable_endGlyphIndex); +} + +int32_t BitmapSizeTable::Builder::PpemX() { + return InternalReadData()->ReadByte( + EblcTable::Offset::kBitmapSizeTable_ppemX); +} + +int32_t BitmapSizeTable::Builder::PpemY() { + return InternalReadData()->ReadByte( + EblcTable::Offset::kBitmapSizeTable_ppemY); +} + +int32_t BitmapSizeTable::Builder::BitDepth() { + return InternalReadData()->ReadByte( + EblcTable::Offset::kBitmapSizeTable_bitDepth); +} + +int32_t BitmapSizeTable::Builder::FlagsAsInt() { + return InternalReadData()->ReadChar( + EblcTable::Offset::kBitmapSizeTable_flags); +} + +IndexSubTable::Builder* BitmapSizeTable::Builder::GetIndexSubTable( + int32_t index) { + IndexSubTableBuilderList* sub_table_list = GetIndexSubTableBuilders(); + return sub_table_list->at(index); +} + +int32_t BitmapSizeTable::Builder::GlyphOffset(int32_t glyph_id) { + IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id); + if (subtable == NULL) { + return -1; + } + return subtable->GlyphOffset(glyph_id); +} + +int32_t BitmapSizeTable::Builder::GlyphLength(int32_t glyph_id) { + IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id); + if (subtable == NULL) { + return -1; + } + return subtable->GlyphLength(glyph_id); +} + +int32_t BitmapSizeTable::Builder::GlyphFormat(int32_t glyph_id) { + IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id); + if (subtable == NULL) { + return -1; + } + return subtable->image_format(); +} + +IndexSubTableBuilderList* BitmapSizeTable::Builder::IndexSubTableBuilders() { + return GetIndexSubTableBuilders(); +} + +CALLER_ATTACH BitmapSizeTable::Builder::BitmapGlyphInfoIterator* +BitmapSizeTable::Builder::GetIterator() { + Ptr<BitmapSizeTable::Builder::BitmapGlyphInfoIterator> output = + new BitmapSizeTable::Builder::BitmapGlyphInfoIterator(this); + return output.Detach(); +} + +void BitmapSizeTable::Builder::GenerateLocaMap(BitmapGlyphInfoMap* output) { + assert(output); + Ptr<BitmapSizeTable::Builder::BitmapGlyphInfoIterator> it; + it.Attach(GetIterator()); + while (it->HasNext()) { + BitmapGlyphInfoPtr info; + info.Attach(it->Next()); + (*output)[info->glyph_id()] = info; + } +} + +void BitmapSizeTable::Builder::Revert() { + index_sub_tables_.clear(); + set_model_changed(false); +} + +BitmapSizeTable::Builder::Builder(WritableFontData* data, + ReadableFontData* master_data) + : SubTable::Builder(data, master_data) { +} + +BitmapSizeTable::Builder::Builder(ReadableFontData* data, + ReadableFontData* master_data) + : SubTable::Builder(data, master_data) { +} + +void BitmapSizeTable::Builder::SetNumberOfIndexSubTables(int32_t count) { + InternalWriteData()->WriteULong( + EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables, count); +} + +IndexSubTable::Builder* BitmapSizeTable::Builder::SearchIndexSubTables( + int32_t glyph_id) { + IndexSubTableBuilderList* subtable_list = GetIndexSubTableBuilders(); + int32_t index = 0; + int32_t bottom = 0; + int32_t top = subtable_list->size(); + while (top != bottom) { + index = (top + bottom) / 2; + IndexSubTable::Builder* subtable = subtable_list->at(index); + if (glyph_id < subtable->first_glyph_index()) { + // Location beow current location + top = index; + } else { + if (glyph_id <= subtable->last_glyph_index()) { + return subtable; + } else { + bottom = index + 1; + } + } + } + return NULL; +} + +IndexSubTableBuilderList* BitmapSizeTable::Builder::GetIndexSubTableBuilders() { + if (index_sub_tables_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &index_sub_tables_; +} + +void BitmapSizeTable::Builder::Initialize(ReadableFontData* data) { + index_sub_tables_.clear(); + if (data) { + int32_t number_of_index_subtables = + BitmapSizeTable::NumberOfIndexSubTables(data, 0); + for (int32_t i = 0; i < number_of_index_subtables; ++i) { + index_sub_tables_[index_sub_tables_.size()].Attach( + CreateIndexSubTableBuilder(i)); + } + } +} + +CALLER_ATTACH IndexSubTable::Builder* +BitmapSizeTable::Builder::CreateIndexSubTableBuilder(int32_t index) { + return IndexSubTable::Builder::CreateBuilder(master_read_data(), + IndexSubTableArrayOffset(), + index); +} + +/****************************************************************************** + * BitmapSizeTable::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +BitmapSizeTable::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + BitmapSizeTable::Builder* container) + : RefIterator<BitmapGlyphInfo, BitmapSizeTable::Builder>(container) { + sub_table_iter_ = container->IndexSubTableBuilders()->begin(); + sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator()); +} + +bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext() { + if (sub_table_glyph_info_iter_ && HasNext(sub_table_glyph_info_iter_)) { + return true; + } + while (++sub_table_iter_ != container()->IndexSubTableBuilders()->end()) { + sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator()); + if (HasNext(sub_table_glyph_info_iter_)) { + return true; + } + } + return false; +} + +CALLER_ATTACH +BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next() { + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + return Next(sub_table_glyph_info_iter_); +} + +bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext( + BitmapGlyphInfoIter* iterator_base) { + if (iterator_base) { + switch (iterator_base->container_base()->index_format()) { + case 1: { + IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->HasNext(); + } + + case 2: { + IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->HasNext(); + } + + case 3: { + IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->HasNext(); + } + + case 4: { + IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->HasNext(); + } + + case 5: { + IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->HasNext(); + } + + default: + break; + } + } + return false; +} + +CALLER_ATTACH +BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next( + BitmapGlyphInfoIter* iterator_base) { + if (iterator_base) { + switch (iterator_base->container_base()->index_format()) { + case 1: { + IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->Next(); + } + + case 2: { + IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->Next(); + } + + case 3: { + IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->Next(); + } + + case 4: { + IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->Next(); + } + + case 5: { + IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it = + down_cast<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*>( + iterator_base); + return it->Next(); + } + + default: + break; } } - return &atomic_subtables; + return NULL; } } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/bitmap_size_table.h b/cpp/src/sfntly/table/bitmap/bitmap_size_table.h index ee58bca..2bc91da 100644 --- a/cpp/src/sfntly/table/bitmap/bitmap_size_table.h +++ b/cpp/src/sfntly/table/bitmap/bitmap_size_table.h @@ -17,28 +17,120 @@ #ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_ #define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_ -#include <vector> - #include "sfntly/port/lock.h" +#include "sfntly/table/bitmap/bitmap_glyph_info.h" #include "sfntly/table/bitmap/index_sub_table.h" namespace sfntly { +// Binary search would be faster but many fonts have index subtables that +// aren't sorted. +// Note: preprocessor define is used to avoid const expression warnings in C++ +// code. +#define SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH 0 class BitmapSizeTable : public SubTable, public RefCounted<BitmapSizeTable> { public: - // Note: C++ port take two ReadableFontData. The first is sliced data, and - // the second is unsliced data. The second one is used to correctly - // construct index sub tables since Java version calculate the offset - // based on unsliced data. - BitmapSizeTable(ReadableFontData* data, - ReadableFontData* master_data); + class Builder : public SubTable::Builder, + public RefCounted<Builder> { + public: + class BitmapGlyphInfoIterator : + public RefIterator<BitmapGlyphInfo, Builder> { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + bool HasNext(BitmapGlyphInfoIter* iterator_base); + CALLER_ATTACH BitmapGlyphInfo* Next(BitmapGlyphInfoIter* iterator_base); + + IndexSubTableBuilderList::iterator sub_table_iter_; + BitmapGlyphInfoIterPtr sub_table_glyph_info_iter_; + }; + + virtual ~Builder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + ReadableFontData* master_data); + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + ReadableFontData* master_data); + // Gets the subtable array offset as set in the original table as read from + // the font file. This value cannot be explicitly set and will be generated + // during table building. + // @return the subtable array offset + int32_t IndexSubTableArrayOffset(); + + // Sets the subtable array offset. This is used only during the building + // process when the objects are being serialized. + // @param offset the offset to the index subtable array + void SetIndexSubTableArrayOffset(int32_t offset); + + // Gets the subtable array size as set in the original table as read from + // the font file. This value cannot be explicitly set and will be generated + // during table building. + // @return the subtable array size + int32_t IndexTableSize(); + + // Sets the subtable size. This is used only during the building process + // when the objects are being serialized. + // @param size the offset to the index subtable array + void SetIndexTableSize(int32_t size); + + int32_t NumberOfIndexSubTables(); + int32_t ColorRef(); + // TODO(stuartg): SBitLineMetrics hori(); + // TODO(stuartg): SBitLineMetrics vert(); + int32_t StartGlyphIndex(); + int32_t EndGlyphIndex(); + int32_t PpemX(); + int32_t PpemY(); + int32_t BitDepth(); + int32_t FlagsAsInt(); + + // Note: renamed from indexSubTable() + IndexSubTable::Builder* GetIndexSubTable(int32_t index); + int32_t GlyphOffset(int32_t glyph_id); + int32_t GlyphLength(int32_t glyph_id); + int32_t GlyphFormat(int32_t glyph_id); + IndexSubTableBuilderList* IndexSubTableBuilders(); + // Note: renamed from iterator(), type is the derived type. + CALLER_ATTACH BitmapGlyphInfoIterator* GetIterator(); + void GenerateLocaMap(BitmapGlyphInfoMap* output); + + protected: + void Revert(); + + private: + Builder(WritableFontData* data, ReadableFontData* master_data); + Builder(ReadableFontData* data, ReadableFontData* master_data); + + void SetNumberOfIndexSubTables(int32_t count); + IndexSubTable::Builder* SearchIndexSubTables(int32_t glyph_id); + IndexSubTableBuilderList* GetIndexSubTableBuilders(); + void Initialize(ReadableFontData* data); + CALLER_ATTACH IndexSubTable::Builder* CreateIndexSubTableBuilder( + int32_t index); + + IndexSubTableBuilderList index_sub_tables_; + }; + virtual ~BitmapSizeTable(); int32_t IndexSubTableArrayOffset(); int32_t IndexTableSize(); int32_t NumberOfIndexSubTables(); int32_t ColorRef(); + // TODO(stuartg): SBitLineMetrics hori(); + // TODO(stuartg): SBitLineMetrics vert(); int32_t StartGlyphIndex(); int32_t EndGlyphIndex(); int32_t PpemX(); @@ -48,22 +140,31 @@ class BitmapSizeTable : public SubTable, // Note: renamed from indexSubTable() IndexSubTable* GetIndexSubTable(int32_t index); - int32_t GlyphOffset(int32_t glyph_id); int32_t GlyphLength(int32_t glyph_id); + CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id); int32_t GlyphFormat(int32_t glyph_id); + protected: + BitmapSizeTable(ReadableFontData* data, + ReadableFontData* master_data); + private: + static int32_t NumberOfIndexSubTables(ReadableFontData* data, + int32_t table_offset); IndexSubTable* SearchIndexSubTables(int32_t glyph_id); + IndexSubTable* LinearSearchIndexSubTables(int32_t glyph_id); + IndexSubTable* BinarySearchIndexSubTables(int32_t glyph_id); CALLER_ATTACH IndexSubTable* CreateIndexSubTable(int32_t index); IndexSubTableList* GetIndexSubTableList(); - ReadableFontDataPtr master_data_; - Lock atomic_subtables_lock_; - IndexSubTableList atomic_subtables; + Lock index_subtables_lock_; + IndexSubTableList index_subtables_; }; typedef Ptr<BitmapSizeTable> BitmapSizeTablePtr; typedef std::vector<BitmapSizeTablePtr> BitmapSizeTableList; +typedef Ptr<BitmapSizeTable::Builder> BitmapSizeTableBuilderPtr; +typedef std::vector<BitmapSizeTableBuilderPtr> BitmapSizeTableBuilderList; } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.cc b/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.cc index bd680e4..ae7dc5a 100644 --- a/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.cc +++ b/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.cc @@ -86,4 +86,24 @@ CompositeBitmapGlyph::Component::Component(int32_t glyph_code, : glyph_code_(glyph_code), x_offset_(x_offset), y_offset_(y_offset) { } +/****************************************************************************** + * CompositeBitmapGlyph::Builder class + ******************************************************************************/ +CompositeBitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format) + : BitmapGlyph::Builder(data, format) { +} + +CompositeBitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format) + : BitmapGlyph::Builder(data, format) { +} + +CompositeBitmapGlyph::Builder::~Builder() { +} + +CALLER_ATTACH FontDataTable* +CompositeBitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) { + Ptr<CompositeBitmapGlyph> glyph = new CompositeBitmapGlyph(data, format()); + return glyph.Detach(); +} + } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.h b/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.h index 0521213..897db7e 100644 --- a/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.h +++ b/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.h @@ -47,6 +47,16 @@ class CompositeBitmapGlyph : public BitmapGlyph, friend class CompositeBitmapGlyph; }; + class Builder : public BitmapGlyph::Builder, + public RefCounted<Builder> { + public: + Builder(WritableFontData* data, int32_t format); + Builder(ReadableFontData* data, int32_t format); + virtual ~Builder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + }; + CompositeBitmapGlyph(ReadableFontData* data, int32_t format); virtual ~CompositeBitmapGlyph(); int32_t NumComponents(); diff --git a/cpp/src/sfntly/table/bitmap/ebdt_table.cc b/cpp/src/sfntly/table/bitmap/ebdt_table.cc index a131f5a..75a5080 100644 --- a/cpp/src/sfntly/table/bitmap/ebdt_table.cc +++ b/cpp/src/sfntly/table/bitmap/ebdt_table.cc @@ -16,6 +16,8 @@ #include "sfntly/table/bitmap/ebdt_table.h" +#include <stdlib.h> + #include "sfntly/table/bitmap/composite_bitmap_glyph.h" #include "sfntly/table/bitmap/simple_bitmap_glyph.h" @@ -32,28 +34,9 @@ int32_t EbdtTable::Version() { CALLER_ATTACH BitmapGlyph* EbdtTable::Glyph(int32_t offset, int32_t length, int32_t format) { - ReadableFontDataPtr new_data; - new_data.Attach(down_cast<ReadableFontData*>(data_->Slice(offset, length))); - BitmapGlyphPtr glyph; - switch (format) { - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - glyph = new SimpleBitmapGlyph(new_data, format); - break; - case 8: - case 9: - glyph = new CompositeBitmapGlyph(new_data, format); - break; - default: - assert(false); - break; - } - return glyph.Detach(); + ReadableFontDataPtr glyph_data; + glyph_data.Attach(down_cast<ReadableFontData*>(data_->Slice(offset, length))); + return BitmapGlyph::CreateGlyph(glyph_data, format); } EbdtTable::EbdtTable(Header* header, ReadableFontData* data) @@ -81,20 +64,113 @@ CALLER_ATTACH FontDataTable* } void EbdtTable::Builder::SubDataSet() { - // NOP + Revert(); } int32_t EbdtTable::Builder::SubDataSizeToSerialize() { - return 0; + if (glyph_builders_.empty()) { + return 0; + } + bool fixed = true; + int32_t size = Offset::kHeaderLength; + for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(), + builder_end = glyph_builders_.end(); + builder_map != builder_end; + builder_map++) { + for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(), + glyph_entry_end = builder_map->end(); + glyph_entry != glyph_entry_end; + glyph_entry++) { + int32_t glyph_size = glyph_entry->second->SubDataSizeToSerialize(); + size += abs(glyph_size); + fixed = (glyph_size <= 0) ? false : fixed; + } + } + return (fixed ? 1 : -1) * size; } bool EbdtTable::Builder::SubReadyToSerialize() { - return false; + if (glyph_builders_.empty()) { + return false; + } + return true; } int32_t EbdtTable::Builder::SubSerialize(WritableFontData* new_data) { - UNREFERENCED_PARAMETER(new_data); - return 0; + int32_t size = 0; + size += new_data->WriteFixed(Offset::kVersion, kVersion); + for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(), + builder_end = glyph_builders_.end(); + builder_map != builder_end; + builder_map++) { + for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(), + glyph_entry_end = builder_map->end(); + glyph_entry != glyph_entry_end; + glyph_entry++) { + WritableFontDataPtr slice; + slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size))); + size += glyph_entry->second->SubSerialize(slice); + } + } + return size; +} + +void EbdtTable::Builder::SetLoca(BitmapLocaList* loca_list) { + assert(loca_list); + Revert(); + std::copy(loca_list->begin(), loca_list->end(), glyph_loca_.begin()); +} + +void EbdtTable::Builder::GenerateLocaList(BitmapLocaList* output) { + assert(output); + output->clear(); + + if (glyph_builders_.empty()) { + if (glyph_loca_.empty()) { + return; + } + } + + output->resize(glyph_builders_.size()); + int start_offset = Offset::kHeaderLength; + for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(), + builder_end = glyph_builders_.end(); + builder_map != builder_end; + builder_map++) { + BitmapGlyphInfoMap new_loca_map; + int32_t glyph_offset = 0; + for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(), + glyph_end = builder_map->end(); + glyph_entry != glyph_end; + glyph_entry++) { + BitmapGlyphBuilderPtr builder = glyph_entry->second; + int32_t size = builder->SubDataSizeToSerialize(); + BitmapGlyphInfoPtr info = new BitmapGlyphInfo(glyph_entry->first, + start_offset + glyph_offset, size, builder->format()); + new_loca_map[glyph_entry->first] = info; + glyph_offset += size; + } + start_offset += glyph_offset; + output->push_back(new_loca_map); + } +} + +BitmapGlyphBuilderList* EbdtTable::Builder::GlyphBuilders() { + return GetGlyphBuilders(); +} + +void EbdtTable::Builder::SetGlyphBuilders( + BitmapGlyphBuilderList* glyph_builders) { + glyph_builders_.clear(); + std::copy(glyph_builders->begin(), glyph_builders->end(), + glyph_builders_.begin()); + set_model_changed(); +} + +void EbdtTable::Builder::Revert() { + glyph_loca_.clear(); + glyph_builders_.clear(); + set_model_changed(false); } CALLER_ATTACH @@ -105,5 +181,57 @@ EbdtTable::Builder* EbdtTable::Builder::CreateBuilder(Header* header, return builder.Detach(); } +CALLER_ATTACH +EbdtTable::Builder* EbdtTable::Builder::CreateBuilder(Header* header, + ReadableFontData* data) { + Ptr<EbdtTable::Builder> builder; + builder = new Builder(header, data); + return builder.Detach(); +} + +BitmapGlyphBuilderList* EbdtTable::Builder::GetGlyphBuilders() { + if (glyph_builders_.empty()) { + if (glyph_loca_.empty()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalStateException( + "Loca values not set - unable to parse glyph data."); +#endif + return NULL; + } + Initialize(InternalReadData(), &glyph_loca_, &glyph_builders_); + set_model_changed(); + } + return &glyph_builders_; +} + +void EbdtTable::Builder::Initialize(ReadableFontData* data, + BitmapLocaList* loca_list, + BitmapGlyphBuilderList* output) { + assert(loca_list); + assert(output); + + output->clear(); + output->resize(loca_list->size()); + if (data) { + for (BitmapLocaList::iterator loca_map = loca_list->begin(), + loca_end = loca_list->end(); + loca_map != loca_end; loca_map++) { + BitmapGlyphBuilderMap glyph_builder_map; + for (BitmapGlyphInfoMap::iterator entry = loca_map->begin(), + entry_end = loca_map->end(); + entry != entry_end; entry++) { + BitmapGlyphInfoPtr info = entry->second; + ReadableFontDataPtr slice; + slice.Attach(down_cast<ReadableFontData*>(data->Slice( + info->start_offset(), info->length()))); + BitmapGlyphBuilderPtr glyph_builder; + glyph_builder.Attach(BitmapGlyph::Builder::CreateGlyphBuilder( + slice, info->format())); + glyph_builder_map[entry->first] = glyph_builder; + } + output->push_back(glyph_builder_map); + } + } +} } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/ebdt_table.h b/cpp/src/sfntly/table/bitmap/ebdt_table.h index 998541e..723c3f9 100644 --- a/cpp/src/sfntly/table/bitmap/ebdt_table.h +++ b/cpp/src/sfntly/table/bitmap/ebdt_table.h @@ -18,6 +18,7 @@ #define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_ #include "sfntly/table/bitmap/bitmap_glyph.h" +#include "sfntly/table/bitmap/bitmap_glyph_info.h" #include "sfntly/table/subtable_container_table.h" namespace sfntly { @@ -40,8 +41,48 @@ class EbdtTable : public SubTableContainerTable, virtual void SubDataSet(); virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + void SetLoca(BitmapLocaList* loca_list); + void GenerateLocaList(BitmapLocaList* output); +
+ // Gets the List of glyph builders for the glyph table builder. These may be
+ // manipulated in any way by the caller and the changes will be reflected in
+ // the final glyph table produced.
+ // If there is no current data for the glyph builder or the glyph builders
+ // have not been previously set then this will return an empty glyph builder
+ // List. If there is current data (i.e. data read from an existing font) and
+ // the loca list has not been set or is null, empty, or invalid, then an
+ // empty glyph builder List will be returned.
+ // @return the list of glyph builders + BitmapGlyphBuilderList* GlyphBuilders(); + + // Replace the internal glyph builders with the one provided. The provided
+ // list and all contained objects belong to this builder.
+ // This call is only required if the entire set of glyphs in the glyph
+ // table builder are being replaced. If the glyph builder list provided from
+ // the {@link EbdtTable.Builder#glyphBuilders()} is being used and modified
+ // then those changes will already be reflected in the glyph table builder.
+ // @param glyphBuilders the new glyph builders + void SetGlyphBuilders(BitmapGlyphBuilderList* glyph_builders); + + void Revert(); + + // Create a new builder using the header information and data provided. + // @param header the header information + // @param data the data holding the table static CALLER_ATTACH Builder* CreateBuilder(Header* header, WritableFontData* data); + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + ReadableFontData* data); + + private: + BitmapGlyphBuilderList* GetGlyphBuilders(); + static void Initialize(ReadableFontData* data, + BitmapLocaList* loca_list, + BitmapGlyphBuilderList* output); + + static const int32_t kVersion = 0x00020000; // TODO(stuartg): const/enum + BitmapLocaList glyph_loca_; + BitmapGlyphBuilderList glyph_builders_; }; virtual ~EbdtTable(); @@ -51,14 +92,14 @@ class EbdtTable : public SubTableContainerTable, int32_t format); protected: - EbdtTable(Header* header, ReadableFontData* data); - - private: struct Offset { enum { kVersion = 0, + kHeaderLength = DataSize::kFixed, }; }; + + EbdtTable(Header* header, ReadableFontData* data); }; typedef Ptr<EbdtTable> EbdtTablePtr; diff --git a/cpp/src/sfntly/table/bitmap/eblc_table.cc b/cpp/src/sfntly/table/bitmap/eblc_table.cc index decbadf..bb36db0 100644 --- a/cpp/src/sfntly/table/bitmap/eblc_table.cc +++ b/cpp/src/sfntly/table/bitmap/eblc_table.cc @@ -16,6 +16,10 @@ #include "sfntly/table/bitmap/eblc_table.h" +#include <stdlib.h> + +#include "sfntly/math/font_math.h" + namespace sfntly { /****************************************************************************** * EblcTable class @@ -67,8 +71,12 @@ void EblcTable::CreateBitmapSizeTable(ReadableFontData* data, data->Slice(Offset::kBitmapSizeTableArrayStart + i * Offset::kBitmapSizeTableLength, Offset::kBitmapSizeTableLength))); - BitmapSizeTablePtr new_table = new BitmapSizeTable(new_data, data); - output->push_back(new_table); + BitmapSizeTableBuilderPtr size_builder; + size_builder.Attach( + BitmapSizeTable::Builder::CreateBuilder(new_data, data)); + BitmapSizeTablePtr size; + size.Attach(down_cast<BitmapSizeTable*>(size_builder->Build())); + output->push_back(size); } } @@ -87,20 +95,163 @@ EblcTable::Builder::~Builder() { } int32_t EblcTable::Builder::SubSerialize(WritableFontData* new_data) { - UNREFERENCED_PARAMETER(new_data); - return 0; + // header + int32_t size = new_data->WriteFixed(0, kVersion); + size += new_data->WriteULong(size, size_table_builders_.size()); + + // calculate the offsets + // offset to the start of the size table array + int32_t size_table_start_offset = size; + // walking offset in the size table array + int32_t size_table_offset = size_table_start_offset; + // offset to the start of the whole index subtable block + int32_t sub_table_block_start_offset = size_table_offset + + size_table_builders_.size() * Offset::kBitmapSizeTableLength; + // walking offset in the index subtable + // points to the start of the current subtable block + int32_t current_sub_table_block_start_offset = sub_table_block_start_offset; + +#if defined (SFNTLY_DEBUG_BITMAP) + int32_t size_index = 0; +#endif + for (BitmapSizeTableBuilderList::iterator + size_builder = size_table_builders_.begin(), + size_builder_end = size_table_builders_.end(); + size_builder != size_builder_end; size_builder++) { + (*size_builder)->SetIndexSubTableArrayOffset( + current_sub_table_block_start_offset); + IndexSubTableBuilderList* index_sub_table_builder_list = + (*size_builder)->IndexSubTableBuilders(); + + // walking offset within the current subTable array + int32_t index_sub_table_array_offset = current_sub_table_block_start_offset; + // walking offset within the subTable entries + int32_t index_sub_table_offset = index_sub_table_array_offset + + index_sub_table_builder_list->size() * Offset::kIndexSubHeaderLength; + +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "size %d: sizeTable=%x, current subTable Block=%x, ", + size_index, size_table_offset); + fprintf(stderr, "index subTableStart=%x\n", index_sub_table_offset); + size_index++; + int32_t sub_table_index = 0; +#endif + for (IndexSubTableBuilderList::iterator + index_sub_table_builder = index_sub_table_builder_list->begin(), + index_sub_table_builder_end = index_sub_table_builder_list->end(); + index_sub_table_builder != index_sub_table_builder_end; + index_sub_table_builder++) { +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "\tsubTableIndex %d: format=%x, ", sub_table_index, + (*index_sub_table_builder)->index_format()); + fprintf(stderr, "indexSubTableArrayOffset=%x, indexSubTableOffset=%x\n", + index_sub_table_array_offset, index_sub_table_offset); + sub_table_index++; +#endif + // array entry + index_sub_table_array_offset += new_data->WriteUShort( + index_sub_table_array_offset, + (*index_sub_table_builder)->first_glyph_index()); + index_sub_table_array_offset += new_data->WriteUShort( + index_sub_table_array_offset, + (*index_sub_table_builder)->last_glyph_index()); + index_sub_table_array_offset += new_data->WriteULong( + index_sub_table_array_offset, + index_sub_table_offset - current_sub_table_block_start_offset); + + // index sub table + WritableFontDataPtr slice_index_sub_table; + slice_index_sub_table.Attach(down_cast<WritableFontData*>( + new_data->Slice(index_sub_table_offset))); + int32_t current_sub_table_size = + (*index_sub_table_builder)->SubSerialize(slice_index_sub_table); + int32_t padding = FontMath::PaddingRequired(current_sub_table_size, + DataSize::kULONG); +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "\t\tsubTableSize = %x, padding = %x\n", + current_sub_table_size, padding); +#endif + index_sub_table_offset += current_sub_table_size; + index_sub_table_offset += + new_data->WritePadding(index_sub_table_offset, padding); + } + + // serialize size table + (*size_builder)->SetIndexTableSize( + index_sub_table_offset - current_sub_table_block_start_offset); + WritableFontDataPtr slice_size_table; + slice_size_table.Attach(down_cast<WritableFontData*>( + new_data->Slice(size_table_offset))); + size_table_offset += (*size_builder)->SubSerialize(slice_size_table); + + current_sub_table_block_start_offset = index_sub_table_offset; + } + return size + current_sub_table_block_start_offset; } bool EblcTable::Builder::SubReadyToSerialize() { - return false; + if (size_table_builders_.empty()) { + return false; + } + for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(), + e = size_table_builders_.end(); + b != e; b++) { + if (!(*b)->SubReadyToSerialize()) { + return false; + } + } + return true; } int32_t EblcTable::Builder::SubDataSizeToSerialize() { - return 0; + if (size_table_builders_.empty()) { + return 0; + } + int32_t size = Offset::kHeaderLength; + bool variable = false; + for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(), + e = size_table_builders_.end(); + b != e; b++) { + int32_t size_builder_size = (*b)->SubDataSizeToSerialize(); + variable = size_builder_size > 0 ? variable : true; + size += abs(size_builder_size); + } + return -size; + // TODO(stuartg): need to fix to get size calculated accurately + // return variable ? -size : size; } void EblcTable::Builder::SubDataSet() { - // NOP + Revert(); +} + +BitmapSizeTableBuilderList* EblcTable::Builder::BitmapSizeBuilders() { + return GetSizeList(); +} + +void EblcTable::Builder::Revert() { + size_table_builders_.clear(); + set_model_changed(false); +} + +void EblcTable::Builder::GenerateLocaList(BitmapLocaList* output) { + assert(output); + BitmapSizeTableBuilderList* size_builder_list = GetSizeList(); + output->clear(); + output->resize(size_builder_list->size()); +#if defined (SFNTLY_DEBUG_BITMAP) + int32_t size_index = 0; +#endif + for (BitmapSizeTableBuilderList::iterator b = size_builder_list->begin(), + e = size_builder_list->end(); + b != e; b++) { +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "size table = %d\n", size_index++); +#endif + BitmapGlyphInfoMap loca_map; + (*b)->GenerateLocaMap(&loca_map); + output->push_back(loca_map); + } } CALLER_ATTACH @@ -116,4 +267,38 @@ CALLER_ATTACH EblcTable::Builder* return new_builder.Detach(); } +// static +CALLER_ATTACH EblcTable::Builder* + EblcTable::Builder::CreateBuilder(Header* header, ReadableFontData* data) { + Ptr<EblcTable::Builder> new_builder = new EblcTable::Builder(header, data); + return new_builder.Detach(); +} + +BitmapSizeTableBuilderList* EblcTable::Builder::GetSizeList() { + if (size_table_builders_.empty()) { + Initialize(InternalReadData(), &size_table_builders_); + set_model_changed(); + } + return &size_table_builders_; +} + +void EblcTable::Builder::Initialize(ReadableFontData* data, + BitmapSizeTableBuilderList* output) { + assert(output); + if (data) { + int32_t num_sizes = data->ReadULongAsInt(Offset::kNumSizes); + for (int32_t i = 0; i < num_sizes; ++i) { + ReadableFontDataPtr new_data; + new_data.Attach(down_cast<ReadableFontData*>( + data->Slice(Offset::kBitmapSizeTableArrayStart + + i * Offset::kBitmapSizeTableLength, + Offset::kBitmapSizeTableLength))); + BitmapSizeTableBuilderPtr size_builder; + size_builder.Attach(BitmapSizeTable::Builder::CreateBuilder( + new_data, data)); + output->push_back(size_builder); + } + } +} + } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/eblc_table.h b/cpp/src/sfntly/table/bitmap/eblc_table.h index 84831ef..f8f052d 100644 --- a/cpp/src/sfntly/table/bitmap/eblc_table.h +++ b/cpp/src/sfntly/table/bitmap/eblc_table.h @@ -32,9 +32,10 @@ class EblcTable : public SubTableContainerTable, // header kVersion = 0, kNumSizes = 4, + kHeaderLength = kNumSizes + DataSize::kULONG, // bitmapSizeTable - kBitmapSizeTableArrayStart = 8, + kBitmapSizeTableArrayStart = kHeaderLength, kBitmapSizeTableLength = 48, kBitmapSizeTable_indexSubTableArrayOffset = 0, kBitmapSizeTable_indexTableSize = 4, @@ -95,6 +96,9 @@ class EblcTable : public SubTableContainerTable, kIndexSubTable4_numGlyphs = kIndexSubHeaderLength, kIndexSubTable4_glyphArray = kIndexSubTable4_numGlyphs + DataSize::kULONG, + kIndexSubTable4_codeOffsetPairLength = 2 * DataSize::kUSHORT, + kIndexSubTable4_codeOffsetPair_glyphCode = 0, + kIndexSubTable4_codeOffsetPair_offset = DataSize::kUSHORT, // kIndexSubTable5 kIndexSubTable5_imageSize = kIndexSubHeaderLength, @@ -127,8 +131,31 @@ class EblcTable : public SubTableContainerTable, virtual void SubDataSet(); virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + BitmapSizeTableBuilderList* BitmapSizeBuilders(); + void Revert(); + + // Generates the loca list for the EBDT table. The list is intended to be + // used by the EBDT to allow it to parse the glyph data and generate glyph + // objects. After returning from this method the list belongs to the caller. + // The list entries are in the same order as the size table builders are at + // the time of this call. + // @return the list of loca maps with one for each size table builder + void GenerateLocaList(BitmapLocaList* output); + + // Create a new builder using the header information and data provided. + // @param header the header information + // @param data the data holding the table static CALLER_ATTACH Builder* CreateBuilder(Header* header, WritableFontData* data); + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + ReadableFontData* data); + + private: + BitmapSizeTableBuilderList* GetSizeList(); + void Initialize(ReadableFontData* data, BitmapSizeTableBuilderList* output); + + static const int32_t kVersion = 0x00020000; + BitmapSizeTableBuilderList size_table_builders_; }; int32_t Version(); @@ -137,11 +164,14 @@ class EblcTable : public SubTableContainerTable, BitmapSizeTable* GetBitmapSizeTable(int32_t index); + static const int32_t NOTDEF = -1; + protected: EblcTable(Header* header, ReadableFontData* data); private: BitmapSizeTableList* GetBitmapSizeTableList(); + static void CreateBitmapSizeTable(ReadableFontData* data, int32_t num_sizes, BitmapSizeTableList* output); diff --git a/cpp/src/sfntly/table/bitmap/ebsc_table.cc b/cpp/src/sfntly/table/bitmap/ebsc_table.cc new file mode 100644 index 0000000..458c2d4 --- /dev/null +++ b/cpp/src/sfntly/table/bitmap/ebsc_table.cc @@ -0,0 +1,107 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/ebsc_table.h" + +namespace sfntly { +/****************************************************************************** + * EbscTable class + ******************************************************************************/ +EbscTable::~EbscTable() { +} + +int32_t EbscTable::Version() { + return data_->ReadFixed(Offset::kVersion); +} + +int32_t EbscTable::NumSizes() { + return data_->ReadULongAsInt(Offset::kNumSizes); +} + +EbscTable::EbscTable(Header* header, ReadableFontData* data) + : Table(header, data) { +} + +/****************************************************************************** + * EbscTable::BitmapScaleTable class + ******************************************************************************/ +EbscTable::BitmapScaleTable::~BitmapScaleTable() { +} + +EbscTable::BitmapScaleTable::BitmapScaleTable(ReadableFontData* data) + : SubTable(data) { +} + +int32_t EbscTable::BitmapScaleTable::PpemX() { + return data_->ReadByte(Offset::kBitmapScaleTable_ppemX); +} + +int32_t EbscTable::BitmapScaleTable::PpemY() { + return data_->ReadByte(Offset::kBitmapScaleTable_ppemY); +} + +int32_t EbscTable::BitmapScaleTable::SubstitutePpemX() { + return data_->ReadByte(Offset::kBitmapScaleTable_substitutePpemX); +} + +int32_t EbscTable::BitmapScaleTable::SubstitutePpemY() { + return data_->ReadByte(Offset::kBitmapScaleTable_substitutePpemY); +} + +/****************************************************************************** + * EbscTable::Builder class + ******************************************************************************/ +EbscTable::Builder::~Builder() { +} + +CALLER_ATTACH EbscTable::Builder* EbscTable::Builder::CreateBuilder( + Header* header, WritableFontData* data) { + EbscTableBuilderPtr builder = new EbscTable::Builder(header, data); + return builder.Detach(); +} + +EbscTable::Builder::Builder(Header* header, WritableFontData* data) + : Table::Builder(header, data) { +} + +EbscTable::Builder::Builder(Header* header, ReadableFontData* data) + : Table::Builder(header, data) { +} + +CALLER_ATTACH +FontDataTable* EbscTable::Builder::SubBuildTable(ReadableFontData* data) { + EbscTablePtr output = new EbscTable(header(), data); + return output.Detach(); +} + +void EbscTable::Builder::SubDataSet() { + // NOP +} + +int32_t EbscTable::Builder::SubDataSizeToSerialize() { + return 0; +} + +bool EbscTable::Builder::SubReadyToSerialize() { + return false; +} + +int32_t EbscTable::Builder::SubSerialize(WritableFontData* new_data) { + UNREFERENCED_PARAMETER(new_data); + return 0; +} + +} // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/ebsc_table.h b/cpp/src/sfntly/table/bitmap/ebsc_table.h new file mode 100644 index 0000000..43088fd --- /dev/null +++ b/cpp/src/sfntly/table/bitmap/ebsc_table.h @@ -0,0 +1,102 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_ + +#include "sfntly/table/bitmap/eblc_table.h" + +namespace sfntly { + +class EbscTable : public Table, + public RefCounted<EbscTable> { + public: + struct Offset { + enum { + // header + kVersion = 0, + kNumSizes = DataSize::kFixed, + kHeaderLength = kNumSizes + DataSize::kULONG, + kBitmapScaleTableStart = kHeaderLength, + + // bitmapScaleTable + kBitmapScaleTable_hori = 0, + kBitmapScaleTable_vert = EblcTable::Offset::kSbitLineMetricsLength, + kBitmapScaleTable_ppemX = kBitmapScaleTable_vert + + EblcTable::Offset::kSbitLineMetricsLength, + kBitmapScaleTable_ppemY = kBitmapScaleTable_ppemX + DataSize::kBYTE, + kBitmapScaleTable_substitutePpemX = kBitmapScaleTable_ppemY + + DataSize::kBYTE, + kBitmapScaleTable_substitutePpemY = kBitmapScaleTable_substitutePpemX + + DataSize::kBYTE, + kBitmapScaleTableLength = kBitmapScaleTable_substitutePpemY + + DataSize::kBYTE, + }; + }; + + class BitmapScaleTable : public SubTable, + public RefCounted<BitmapScaleTable> { + public: + virtual ~BitmapScaleTable(); + int32_t PpemX(); + int32_t PpemY(); + int32_t SubstitutePpemX(); + int32_t SubstitutePpemY(); + + protected: + // Note: caller to do data->Slice(offset, Offset::kBitmapScaleTableLength) + explicit BitmapScaleTable(ReadableFontData* data); + }; + + // TODO(stuartg): currently the builder is minimally functional + // -just builds from initial data + // - need to make fully working + class Builder : public Table::Builder, + public RefCounted<Builder> { + public: + virtual ~Builder(); + + static CALLER_ATTACH Builder* CreateBuilder(Header* header, + WritableFontData* data); + + protected: + Builder(Header* header, WritableFontData* data); + Builder(Header* header, ReadableFontData* data); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + }; + + virtual ~EbscTable(); + + int32_t Version(); + int32_t NumSizes(); + // Note: renamed from bitmapScaleTable + CALLER_ATTACH BitmapScaleTable* GetBitmapScaleTable(int32_t index); + + private: + EbscTable(Header* header, ReadableFontData* data); + friend class Builder; +}; +typedef Ptr<EbscTable> EbscTablePtr; +typedef Ptr<EbscTable::Builder> EbscTableBuilderPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_ diff --git a/cpp/src/sfntly/table/bitmap/glyph_metrics.cc b/cpp/src/sfntly/table/bitmap/glyph_metrics.cc new file mode 100644 index 0000000..e91eb99 --- /dev/null +++ b/cpp/src/sfntly/table/bitmap/glyph_metrics.cc @@ -0,0 +1,39 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/glyph_metrics.h" + +namespace sfntly { + +GlyphMetrics::~GlyphMetrics() { +} + +GlyphMetrics::GlyphMetrics(ReadableFontData* data) + : SubTable(data) { +} + +GlyphMetrics::Builder::~Builder() { +} + +GlyphMetrics::Builder::Builder(WritableFontData* data) + : SubTable::Builder(data) { +} + +GlyphMetrics::Builder::Builder(ReadableFontData* data) + : SubTable::Builder(data) { +} + +} // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/glyph_metrics.h b/cpp/src/sfntly/table/bitmap/glyph_metrics.h new file mode 100644 index 0000000..5f16aaa --- /dev/null +++ b/cpp/src/sfntly/table/bitmap/glyph_metrics.h @@ -0,0 +1,43 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_ + +#include "sfntly/table/subtable.h" + +namespace sfntly { + +class GlyphMetrics : public SubTable { + public: + virtual ~GlyphMetrics(); + + protected: + class Builder : public SubTable::Builder { + public: + virtual ~Builder(); + + protected: + explicit Builder(WritableFontData* data); + explicit Builder(ReadableFontData* data); + }; + + explicit GlyphMetrics(ReadableFontData* data); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_ diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table.cc b/cpp/src/sfntly/table/bitmap/index_sub_table.cc index 329179d..66d2d83 100644 --- a/cpp/src/sfntly/table/bitmap/index_sub_table.cc +++ b/cpp/src/sfntly/table/bitmap/index_sub_table.cc @@ -24,30 +24,31 @@ #include "sfntly/table/bitmap/index_sub_table_format5.h" namespace sfntly { - -bool IndexSubTable::CheckGlyphRange(int32_t glyph_id) { - if (glyph_id < first_glyph_index() || glyph_id > last_glyph_index()) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException("Glyph ID is outside of the allowed range"); -#endif - return false; +/****************************************************************************** + * IndexSubTable class + ******************************************************************************/ +CALLER_ATTACH BitmapGlyphInfo* IndexSubTable::GlyphInfo(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return NULL; } - return true; + if (GlyphStartOffset(glyph_id) == -1) { + return NULL; + } + BitmapGlyphInfoPtr output = new BitmapGlyphInfo(glyph_id, + image_data_offset(), + GlyphStartOffset(glyph_id), + GlyphLength(glyph_id), + image_format()); + return output.Detach(); } -template <typename IndexSubTableType> -static IndexSubTableType* CreateTable(ReadableFontData* data, - int32_t index_sub_table_offset, - int32_t first_glyph_index, - int32_t last_glyph_index) { - ReadableFontDataPtr new_data; - new_data.Attach(down_cast<ReadableFontData*>( - data->Slice(index_sub_table_offset, - IndexSubTableType::GetDataLength(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index)))); - return new IndexSubTableType(new_data, first_glyph_index, last_glyph_index); +int32_t IndexSubTable::GlyphOffset(int32_t glyph_id) { + int32_t glyph_start_offset = GlyphStartOffset(glyph_id); + if (glyph_start_offset == -1) { + return -1; + } + return image_data_offset() + glyph_start_offset; } // static @@ -55,10 +56,65 @@ CALLER_ATTACH IndexSubTable* IndexSubTable::CreateIndexSubTable(ReadableFontData* data, int32_t offset_to_index_sub_table_array, int32_t array_index) { + IndexSubTableBuilderPtr builder; + builder.Attach(IndexSubTable::Builder::CreateBuilder( + data, offset_to_index_sub_table_array, array_index)); + return down_cast<IndexSubTable*>(builder->Build()); +} + +IndexSubTable::IndexSubTable(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : SubTable(data), + first_glyph_index_(first_glyph_index), + last_glyph_index_(last_glyph_index) { + index_format_ = + data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat); + image_format_ = + data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat); + image_data_offset_ = + data_->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset); +} + +int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id) { + return CheckGlyphRange(glyph_id, first_glyph_index(), last_glyph_index()); +} + +// static +int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id, + int32_t first_glyph_id, + int32_t last_glyph_id) { + if (glyph_id < first_glyph_id || glyph_id > last_glyph_id) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundException("Glyph ID is outside of the allowed range."); +#endif + return -1; + } + return glyph_id - first_glyph_id; +} + +/****************************************************************************** + * IndexSubTable::Builder class + ******************************************************************************/ +IndexSubTable::Builder::~Builder() { +} + +void IndexSubTable::Builder::Revert() { + set_model_changed(false); + Initialize(InternalReadData()); +} + +int32_t IndexSubTable::Builder::GlyphOffset(int32_t glyph_id) { + return image_data_offset() + GlyphStartOffset(glyph_id); +} + +// static +CALLER_ATTACH IndexSubTable::Builder* +IndexSubTable::Builder::CreateBuilder(ReadableFontData* data, + int32_t offset_to_index_sub_table_array, int32_t array_index) { int32_t index_sub_table_entry_offset = offset_to_index_sub_table_array + array_index * EblcTable::Offset::kIndexSubTableEntryLength; - int32_t first_glyph_index = data->ReadUShort(index_sub_table_entry_offset + EblcTable::Offset::kIndexSubTableEntry_firstGlyphIndex); @@ -68,49 +124,25 @@ CALLER_ATTACH IndexSubTable* int32_t additional_offset_to_index_subtable = data->ReadULongAsInt( index_sub_table_entry_offset + EblcTable::Offset::kIndexSubTableEntry_additionalOffsetToIndexSubTable); - int32_t index_sub_table_offset = offset_to_index_sub_table_array + additional_offset_to_index_subtable; - int32_t index_format = data->ReadUShort(index_sub_table_offset); - IndexSubTablePtr new_table; - ReadableFontDataPtr new_data; switch (index_format) { case 1: - new_table = CreateTable<IndexSubTableFormat1>(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index); - break; - + return IndexSubTableFormat1::Builder::CreateBuilder( + data, index_sub_table_offset, first_glyph_index, last_glyph_index); case 2: - new_table = CreateTable<IndexSubTableFormat2>(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index); - break; - + return IndexSubTableFormat2::Builder::CreateBuilder( + data, index_sub_table_offset, first_glyph_index, last_glyph_index); case 3: - new_table = CreateTable<IndexSubTableFormat3>(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index); - break; - + return IndexSubTableFormat3::Builder::CreateBuilder( + data, index_sub_table_offset, first_glyph_index, last_glyph_index); case 4: - new_table = CreateTable<IndexSubTableFormat4>(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index); - break; - + return IndexSubTableFormat4::Builder::CreateBuilder( + data, index_sub_table_offset, first_glyph_index, last_glyph_index); case 5: - new_table = CreateTable<IndexSubTableFormat5>(data, - index_sub_table_offset, - first_glyph_index, - last_glyph_index); - break; - + return IndexSubTableFormat5::Builder::CreateBuilder( + data, index_sub_table_offset, first_glyph_index, last_glyph_index); default: // Unknown format and unable to process. #if !defined (SFNTLY_NO_EXCEPTION) @@ -118,20 +150,82 @@ CALLER_ATTACH IndexSubTable* #endif break; } + return NULL; +} - return new_table.Detach(); +CALLER_ATTACH +FontDataTable* IndexSubTable::Builder::SubBuildTable(ReadableFontData* data) { + UNREFERENCED_PARAMETER(data); + return NULL; } -IndexSubTable::IndexSubTable(ReadableFontData* data, - int32_t first, - int32_t last) - : SubTable(data), first_glyph_index_(first), last_glyph_index_(last) { +void IndexSubTable::Builder::SubDataSet() { +} + +int32_t IndexSubTable::Builder::SubDataSizeToSerialize() { + return 0; +} + +bool IndexSubTable::Builder::SubReadyToSerialize() { + return false; +} + +int32_t IndexSubTable::Builder::SubSerialize(WritableFontData* new_data) { + UNREFERENCED_PARAMETER(new_data); + return 0; +} + +IndexSubTable::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : SubTable::Builder(data), + first_glyph_index_(first_glyph_index), + last_glyph_index_(last_glyph_index) { + Initialize(data); +} + +IndexSubTable::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : SubTable::Builder(data), + first_glyph_index_(first_glyph_index), + last_glyph_index_(last_glyph_index) { + Initialize(data); +} + +IndexSubTable::Builder::Builder(int32_t index_format, + int32_t image_format, + int32_t image_data_offset) + : index_format_(index_format), + image_format_(image_format), + image_data_offset_(image_data_offset) { +} + +int32_t IndexSubTable::Builder::CheckGlyphRange(int32_t glyph_id) { + return IndexSubTable::CheckGlyphRange(glyph_id, + first_glyph_index(), + last_glyph_index()); +} + +int32_t IndexSubTable::Builder::SerializeIndexSubHeader( + WritableFontData* data) { + int32_t size = + data->WriteUShort(EblcTable::Offset::kIndexSubHeader_indexFormat, + index_format()); + size += data->WriteUShort(EblcTable::Offset::kIndexSubHeader_imageFormat, + image_format()); + size += data->WriteULong(EblcTable::Offset::kIndexSubHeader_imageDataOffset, + image_data_offset()); + return size; +} + +void IndexSubTable::Builder::Initialize(ReadableFontData* data) { index_format_ = - data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat); + data->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat); image_format_ = - data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat); + data->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat); image_data_offset_ = - data_->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset); + data->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset); } } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table.h b/cpp/src/sfntly/table/bitmap/index_sub_table.h index 253f165..c2be7d1 100644 --- a/cpp/src/sfntly/table/bitmap/index_sub_table.h +++ b/cpp/src/sfntly/table/bitmap/index_sub_table.h @@ -19,18 +19,106 @@ #include <vector> +#include "sfntly/port/java_iterator.h" #include "sfntly/table/subtable.h" +#include "sfntly/table/bitmap/bitmap_glyph_info.h" namespace sfntly { class IndexSubTable : public SubTable { public: + class Builder : public SubTable::Builder { + public: + virtual ~Builder(); + + void Revert(); + + int32_t index_format() { return index_format_; } + int32_t first_glyph_index() { return first_glyph_index_; } + void set_first_glyph_index(int32_t v) { first_glyph_index_ = v; } + int32_t last_glyph_index() { return last_glyph_index_; } + void set_last_glyph_index(int32_t v) { last_glyph_index_ = v; } + int32_t image_format() { return image_format_; } + void set_image_format(int32_t v) { image_format_ = v; } + int32_t image_data_offset() { return image_data_offset_; } + void set_image_data_offset(int32_t v) { image_data_offset_ = v; } + + virtual int32_t NumGlyphs() = 0; + + // Gets the full offset of the glyph within the EBDT table. + // @param glyphId the glyph id + // @return the glyph offset + virtual int32_t GlyphOffset(int32_t glyph_id); + + // Gets the offset of the glyph relative to the block for this index + // subtable. + // @param glyphId the glyph id + // @return the glyph offset + virtual int32_t GlyphStartOffset(int32_t glyph_id) = 0; + + // Gets the length of the glyph within the EBDT table. + // @param glyphId the glyph id + // @return the glyph offset + virtual int32_t GlyphLength(int32_t glyph_id) = 0; + + // Note: renamed from java iterator() + CALLER_ATTACH virtual Iterator<BitmapGlyphInfo, IndexSubTable::Builder>* + GetIterator() = 0; + + // Static instantiation function. + static CALLER_ATTACH Builder* + CreateBuilder(ReadableFontData* data, + int32_t offset_to_index_sub_table_array, + int32_t array_index); + + // The following methods will never be called but they need to be here to + // allow the BitmapSizeTable to see these methods through an abstract + // reference. + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + protected: + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(int32_t index_format, + int32_t image_format, + int32_t image_data_offset); + + // Checks that the glyph id is within the correct range. If it returns the + // offset of the glyph id from the start of the range. + // @param glyphId + // @return the offset of the glyphId from the start of the glyph range + // @throws IndexOutOfBoundsException if the glyph id is not within the + // correct range + int32_t CheckGlyphRange(int32_t glyph_id); + int32_t SerializeIndexSubHeader(WritableFontData* data); + + private: + void Initialize(ReadableFontData* data); + + int32_t first_glyph_index_; + int32_t last_glyph_index_; + int32_t index_format_; + int32_t image_format_; + int32_t image_data_offset_; + }; + + int32_t index_format() { return index_format_; } int32_t first_glyph_index() { return first_glyph_index_; } int32_t last_glyph_index() { return last_glyph_index_; } int32_t image_format() { return image_format_; } int32_t image_data_offset() { return image_data_offset_; } - virtual int32_t GlyphOffset(int32_t glyph_id) = 0; + CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id); + virtual int32_t GlyphOffset(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id) = 0; virtual int32_t GlyphLength(int32_t glyph_id) = 0; virtual int32_t NumGlyphs() = 0; @@ -44,10 +132,14 @@ class IndexSubTable : public SubTable { // Java to avoid heavy lifting in constructors. Callers to call // GetDataLength() static method of the derived class to get proper // length and slice ahead. - IndexSubTable(ReadableFontData* data, int32_t first, int32_t last); + IndexSubTable(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); - // Note: change return type to bool in C++ since we may not throw. - bool CheckGlyphRange(int32_t glyph_id); + int32_t CheckGlyphRange(int32_t glyph_id); + static int32_t CheckGlyphRange(int32_t glyph_id, + int32_t first_glyph_id, + int32_t last_glyph_id); private: int32_t first_glyph_index_; @@ -58,6 +150,10 @@ class IndexSubTable : public SubTable { }; typedef Ptr<IndexSubTable> IndexSubTablePtr; typedef std::vector<IndexSubTablePtr> IndexSubTableList; +typedef Ptr<IndexSubTable::Builder> IndexSubTableBuilderPtr; +typedef std::vector<IndexSubTableBuilderPtr> IndexSubTableBuilderList; +typedef Iterator<BitmapGlyphInfo, IndexSubTable::Builder> BitmapGlyphInfoIter; +typedef Ptr<BitmapGlyphInfoIter> BitmapGlyphInfoIterPtr; } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format1.cc b/cpp/src/sfntly/table/bitmap/index_sub_table_format1.cc index b98655a..809412d 100644 --- a/cpp/src/sfntly/table/bitmap/index_sub_table_format1.cc +++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format1.cc @@ -19,7 +19,9 @@ #include "sfntly/table/bitmap/eblc_table.h" namespace sfntly { - +/****************************************************************************** + * IndexSubTableFormat1 class + ******************************************************************************/ // static int32_t IndexSubTableFormat1::GetDataLength(ReadableFontData* data, int32_t offset, @@ -30,12 +32,6 @@ int32_t IndexSubTableFormat1::GetDataLength(ReadableFontData* data, return (last - first + 1 + 1) * DataSize::kULONG; } -IndexSubTableFormat1::IndexSubTableFormat1(ReadableFontData* data, - int32_t first, - int32_t last) - : IndexSubTable(data, first, last) { -} - IndexSubTableFormat1::~IndexSubTableFormat1() { } @@ -43,25 +39,242 @@ int32_t IndexSubTableFormat1::NumGlyphs() { return last_glyph_index() - first_glyph_index() + 1; } -int32_t IndexSubTableFormat1::GlyphOffset(int32_t glyph_id) { - if (CheckGlyphRange(glyph_id)) { - return Loca(glyph_id); +int32_t IndexSubTableFormat1::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; } - return -1; + return Loca(loca); } int32_t IndexSubTableFormat1::GlyphLength(int32_t glyph_id) { - if (CheckGlyphRange(glyph_id)) { - return Loca(glyph_id + 1) - Loca(glyph_id); + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; } - return -1; + return Loca(loca + 1) - Loca(loca); } -int32_t IndexSubTableFormat1::Loca(int32_t loca_index) { +IndexSubTableFormat1::IndexSubTableFormat1(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable(data, first_glyph_index, last_glyph_index) { +} + +int32_t IndexSubTableFormat1::Loca(int32_t loca) { return image_data_offset() + data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable1_offsetArray + - (loca_index - first_glyph_index()) * - DataSize::kULONG); + loca * DataSize::kULONG); +} + +/****************************************************************************** + * IndexSubTableFormat1::Builder class + ******************************************************************************/ +IndexSubTableFormat1::Builder::~Builder() { +} + +int32_t IndexSubTableFormat1::Builder::NumGlyphs() { + return GetOffsetArray()->size() - 1; +} + +int32_t IndexSubTableFormat1::Builder::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return 0; + } + IntegerList* offset_array = GetOffsetArray(); + return offset_array->at(loca + 1) - offset_array->at(loca); +} + +int32_t IndexSubTableFormat1::Builder::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + return GetOffsetArray()->at(loca); +} + +CALLER_ATTACH +BitmapGlyphInfoIter* IndexSubTableFormat1::Builder::GetIterator() { + Ptr<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator> it = + new IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator(this); + return it.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat1::Builder* +IndexSubTableFormat1::Builder::CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + ReadableFontDataPtr new_data; + new_data.Attach(down_cast<ReadableFontData*>( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat1BuilderPtr output = + new IndexSubTableFormat1::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + + +// static +CALLER_ATTACH IndexSubTableFormat1::Builder* +IndexSubTableFormat1::Builder::CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + WritableFontDataPtr new_data; + new_data.Attach(down_cast<WritableFontData*>( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat1BuilderPtr output = + new IndexSubTableFormat1::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +CALLER_ATTACH FontDataTable* IndexSubTableFormat1::Builder::SubBuildTable( + ReadableFontData* data) { + IndexSubTableFormat1Ptr output = new IndexSubTableFormat1( + data, first_glyph_index(), last_glyph_index()); + return output.Detach(); +} + +void IndexSubTableFormat1::Builder::SubDataSet() { + Revert(); +} + +int32_t IndexSubTableFormat1::Builder::SubDataSizeToSerialize() { + if (offset_array_.empty()) { + return 0; + } + return EblcTable::Offset::kIndexSubHeaderLength + + offset_array_.size() * DataSize::kULONG; +} + +bool IndexSubTableFormat1::Builder::SubReadyToSerialize() { + if (!offset_array_.empty()) { + return true; + } + return false; +} + +int32_t IndexSubTableFormat1::Builder::SubSerialize( + WritableFontData* new_data) { + int32_t size = SerializeIndexSubHeader(new_data); + if (!model_changed()) { + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( + EblcTable::Offset::kIndexSubTable1_offsetArray))); + target.Attach(down_cast<WritableFontData*>(new_data->Slice( + EblcTable::Offset::kIndexSubTable1_offsetArray))); + size += source->CopyTo(target); + return size; + } + for (IntegerList::iterator b = GetOffsetArray()->begin(), + e = GetOffsetArray()->end(); b != e; b++) { + size += new_data->WriteLong(size, *b); + } + return size; +} + +void IndexSubTableFormat1::Builder::SetOffsetArray( + const IntegerList& offset_array) { + offset_array_.clear(); + offset_array_ = offset_array; + set_model_changed(); +} + +void IndexSubTableFormat1::Builder::Revert() { + offset_array_.clear(); + IndexSubTable::Builder::Revert(); +} + +IndexSubTableFormat1::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IndexSubTableFormat1::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IntegerList* IndexSubTableFormat1::Builder::GetOffsetArray() { + if (offset_array_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &offset_array_; +} + +void IndexSubTableFormat1::Builder::Initialize(ReadableFontData* data) { + offset_array_.clear(); + if (data) { + int32_t num_offsets = (last_glyph_index() - first_glyph_index() + 1) + 1; + for (int32_t i = 0; i < num_offsets; ++i) { + offset_array_.push_back(data->ReadULongAsInt( + EblcTable::Offset::kIndexSubTable1_offsetArray + + i * DataSize::kULONG)); + } + } +} + +// static +int32_t IndexSubTableFormat1::Builder::DataLength( + ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + UNREFERENCED_PARAMETER(data); + UNREFERENCED_PARAMETER(index_sub_table_offset); + return EblcTable::Offset::kIndexSubHeaderLength + + (last_glyph_index - first_glyph_index + 1 + 1) * DataSize::kULONG; +} + +/****************************************************************************** + * IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + IndexSubTableFormat1::Builder* container) + : RefIterator<BitmapGlyphInfo, IndexSubTableFormat1::Builder, + IndexSubTable::Builder>(container) { + glyph_id_ = container->first_glyph_index(); +} + +bool IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::HasNext() { + if (glyph_id_ <= container()->last_glyph_index()) { + return true; + } + return false; +} + +CALLER_ATTACH BitmapGlyphInfo* +IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::Next() { + BitmapGlyphInfoPtr output; + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + output = new BitmapGlyphInfo(glyph_id_, + container()->image_data_offset(), + container()->GlyphStartOffset(glyph_id_), + container()->GlyphLength(glyph_id_), + container()->image_format()); + glyph_id_++; + return output.Detach(); } } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format1.h b/cpp/src/sfntly/table/bitmap/index_sub_table_format1.h index 3329bc9..c36bf18 100644 --- a/cpp/src/sfntly/table/bitmap/index_sub_table_format1.h +++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format1.h @@ -17,32 +17,96 @@ #ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_ #define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_ +#include "sfntly/port/java_iterator.h" #include "sfntly/table/bitmap/index_sub_table.h" namespace sfntly { - +// Format 1 Index Subtable Entry. class IndexSubTableFormat1 : public IndexSubTable, public RefCounted<IndexSubTableFormat1> { public: - static int32_t GetDataLength(ReadableFontData* data, - int32_t offset, - int32_t first, - int32_t last); + class Builder : public IndexSubTable::Builder, + public RefCounted<Builder> { + public: + class BitmapGlyphInfoIterator + : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + int32_t glyph_id_; + }; + + virtual ~Builder(); + virtual int32_t NumGlyphs(); + virtual int32_t GlyphLength(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + CALLER_ATTACH virtual BitmapGlyphInfoIter* GetIterator(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + void SetOffsetArray(const IntegerList& offset_array); + CALLER_ATTACH BitmapGlyphInfoIter* Iterator(); + + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + protected: + void Revert(); + + private: + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + IntegerList* GetOffsetArray(); + void Initialize(ReadableFontData* data); + + static int32_t DataLength(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + IntegerList offset_array_; + }; - // Note: the constructor does not implement offset/length form provided in - // Java to avoid heavy lifting in constructors. Callers to call - // GetDataLength() static method of the derived class to get proper - // length and slice ahead. - IndexSubTableFormat1(ReadableFontData* data, int32_t first, int32_t last); virtual ~IndexSubTableFormat1(); virtual int32_t NumGlyphs(); - virtual int32_t GlyphOffset(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id); virtual int32_t GlyphLength(int32_t glyph_id); + static int32_t GetDataLength(ReadableFontData* data, + int32_t offset, + int32_t first, + int32_t last); + private: + IndexSubTableFormat1(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); int32_t Loca(int32_t loca_index); + + friend class Builder; }; +typedef Ptr<IndexSubTableFormat1> IndexSubTableFormat1Ptr; +typedef Ptr<IndexSubTableFormat1::Builder> IndexSubTableFormat1BuilderPtr; } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format2.cc b/cpp/src/sfntly/table/bitmap/index_sub_table_format2.cc index 82deef3..e54481b 100644 --- a/cpp/src/sfntly/table/bitmap/index_sub_table_format2.cc +++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format2.cc @@ -19,17 +19,29 @@ #include "sfntly/table/bitmap/eblc_table.h" namespace sfntly { +/****************************************************************************** + * IndexSubTableFormat2 class + ******************************************************************************/ +IndexSubTableFormat2::~IndexSubTableFormat2() { +} -// static -int32_t IndexSubTableFormat2::GetDataLength(ReadableFontData* data, - int32_t offset, - int32_t first, - int32_t last) { - UNREFERENCED_PARAMETER(data); - UNREFERENCED_PARAMETER(offset); - UNREFERENCED_PARAMETER(first); - UNREFERENCED_PARAMETER(last); - return EblcTable::Offset::kIndexSubTable2Length; +int32_t IndexSubTableFormat2::NumGlyphs() { + return last_glyph_index() - first_glyph_index() + 1; +} + +int32_t IndexSubTableFormat2::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + return loca * image_size_; +} + +int32_t IndexSubTableFormat2::GlyphLength(int32_t glyph_id) { + if (CheckGlyphRange(glyph_id) == -1) { + return 0; + } + return image_size_; } IndexSubTableFormat2::IndexSubTableFormat2(ReadableFontData* data, @@ -40,25 +52,183 @@ IndexSubTableFormat2::IndexSubTableFormat2(ReadableFontData* data, data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable2_imageSize); } -IndexSubTableFormat2::~IndexSubTableFormat2() { +/****************************************************************************** + * IndexSubTableFormat2::Builder class + ******************************************************************************/ +IndexSubTableFormat2::Builder::~Builder() { } -int32_t IndexSubTableFormat2::NumGlyphs() { +int32_t IndexSubTableFormat2::Builder::NumGlyphs() { return last_glyph_index() - first_glyph_index() + 1; } -int32_t IndexSubTableFormat2::GlyphOffset(int32_t glyph_id) { - if (CheckGlyphRange(glyph_id)) { - return image_data_offset() + (glyph_id - first_glyph_index()) * image_size_; +int32_t IndexSubTableFormat2::Builder::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; } - return -1; + return loca * ImageSize(); } -int32_t IndexSubTableFormat2::GlyphLength(int32_t glyph_id) { - if (CheckGlyphRange(glyph_id)) { - return image_size_; +int32_t IndexSubTableFormat2::Builder::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return 0; + } + return ImageSize(); +} + +CALLER_ATTACH +BitmapGlyphInfoIter* IndexSubTableFormat2::Builder::GetIterator() { + Ptr<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator> it = + new IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator(this); + return it.Detach(); +} + +int32_t IndexSubTableFormat2::Builder::ImageSize() { + return InternalReadData()->ReadULongAsInt( + EblcTable::Offset::kIndexSubTable2_imageSize); +} + +void IndexSubTableFormat2::Builder::SetImageSize(int32_t image_size) { + InternalWriteData()->WriteULong(EblcTable::Offset::kIndexSubTable2_imageSize, + image_size); +} + +CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat2::Builder::BigMetrics() { + WritableFontDataPtr data; + data.Attach(down_cast<WritableFontData*>(InternalWriteData()->Slice( + EblcTable::Offset::kIndexSubTable2_bigGlyphMetrics, + BigGlyphMetrics::Offset::kMetricsLength))); + BigGlyphMetricsPtr output = new BigGlyphMetrics(data); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat2::Builder* +IndexSubTableFormat2::Builder::CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + ReadableFontDataPtr new_data; + new_data.Attach(down_cast<ReadableFontData*>( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat2BuilderPtr output = + new IndexSubTableFormat2::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat2::Builder* +IndexSubTableFormat2::Builder::CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + WritableFontDataPtr new_data; + new_data.Attach(down_cast<WritableFontData*>( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat2BuilderPtr output = + new IndexSubTableFormat2::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +CALLER_ATTACH FontDataTable* IndexSubTableFormat2::Builder::SubBuildTable( + ReadableFontData* data) { + IndexSubTableFormat2Ptr output = new IndexSubTableFormat2( + data, first_glyph_index(), last_glyph_index()); + return output.Detach(); +} + +void IndexSubTableFormat2::Builder::SubDataSet() { +} + +int32_t IndexSubTableFormat2::Builder::SubDataSizeToSerialize() { + return EblcTable::Offset::kIndexSubTable2Length; +} + +bool IndexSubTableFormat2::Builder::SubReadyToSerialize() { + return true; +} + +int32_t IndexSubTableFormat2::Builder::SubSerialize( + WritableFontData* new_data) { + int32_t size = SerializeIndexSubHeader(new_data); + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice(size))); + target.Attach(down_cast<WritableFontData*>(new_data->Slice(size))); + size += source->CopyTo(target); + return size; +} + +IndexSubTableFormat2::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IndexSubTableFormat2::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +// static +int32_t IndexSubTableFormat2::Builder::DataLength( + ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + UNREFERENCED_PARAMETER(data); + UNREFERENCED_PARAMETER(index_sub_table_offset); + UNREFERENCED_PARAMETER(first_glyph_index); + UNREFERENCED_PARAMETER(last_glyph_index); + return EblcTable::Offset::kIndexSubTable2Length; +} + +/****************************************************************************** + * IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + IndexSubTableFormat2::Builder* container) + : RefIterator<BitmapGlyphInfo, IndexSubTableFormat2::Builder, + IndexSubTable::Builder>(container) { + glyph_id_ = container->first_glyph_index(); +} + +bool IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::HasNext() { + if (glyph_id_ <= container()->last_glyph_index()) { + return true; + } + return false; +} + +CALLER_ATTACH BitmapGlyphInfo* +IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::Next() { + BitmapGlyphInfoPtr output; + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; } - return -1; + output = new BitmapGlyphInfo(glyph_id_, + container()->image_data_offset(), + container()->GlyphStartOffset(glyph_id_), + container()->GlyphLength(glyph_id_), + container()->image_format()); + glyph_id_++; + return output.Detach(); } } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format2.h b/cpp/src/sfntly/table/bitmap/index_sub_table_format2.h index b325ccd..7b13d60 100644 --- a/cpp/src/sfntly/table/bitmap/index_sub_table_format2.h +++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format2.h @@ -18,33 +18,81 @@ #define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT2_H_ #include "sfntly/table/bitmap/index_sub_table.h" +#include "sfntly/table/bitmap/big_glyph_metrics.h" namespace sfntly { - +// Format 2 Index Subtable Entry. class IndexSubTableFormat2 : public IndexSubTable, public RefCounted<IndexSubTableFormat2> { public: - static int32_t GetDataLength(ReadableFontData* data, - int32_t offset, - int32_t first, - int32_t last); - - // Note: the constructor does not implement offset/length form provided in - // Java to avoid heavy lifting in constructors. Callers to call - // GetDataLength() static method of the derived class to get proper - // length and slice ahead. - IndexSubTableFormat2(ReadableFontData* data, int32_t first, int32_t last); + class Builder : public IndexSubTable::Builder, + public RefCounted<Builder> { + public: + class BitmapGlyphInfoIterator + : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + int32_t glyph_id_; + }; + + virtual ~Builder(); + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + CALLER_ATTACH virtual BitmapGlyphInfoIter* GetIterator(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + int32_t ImageSize(); + void SetImageSize(int32_t image_size); + CALLER_ATTACH BigGlyphMetrics* BigMetrics(); + + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + private: + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + + static int32_t DataLength(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + }; + virtual ~IndexSubTableFormat2(); virtual int32_t NumGlyphs(); - virtual int32_t GlyphOffset(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id); virtual int32_t GlyphLength(int32_t glyph_id); private: - int32_t Loca(int32_t loca_index); + IndexSubTableFormat2(ReadableFontData* data, int32_t first, int32_t last); int32_t image_size_; + friend class Builder; }; +typedef Ptr<IndexSubTableFormat2> IndexSubTableFormat2Ptr; +typedef Ptr<IndexSubTableFormat2::Builder> IndexSubTableFormat2BuilderPtr; } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format3.cc b/cpp/src/sfntly/table/bitmap/index_sub_table_format3.cc index 4fa529e..75ff14c 100644 --- a/cpp/src/sfntly/table/bitmap/index_sub_table_format3.cc +++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format3.cc @@ -19,6 +19,31 @@ #include "sfntly/table/bitmap/eblc_table.h" namespace sfntly { +/****************************************************************************** + * IndexSubTableFormat3 class + ******************************************************************************/ +IndexSubTableFormat3::~IndexSubTableFormat3() { +} + +int32_t IndexSubTableFormat3::NumGlyphs() { + return last_glyph_index() - first_glyph_index() + 1; +} + +int32_t IndexSubTableFormat3::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca != -1) { + return Loca(loca); + } + return -1; +} + +int32_t IndexSubTableFormat3::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca != -1) { + return Loca(glyph_id + 1) - Loca(glyph_id); + } + return 0; +} // static int32_t IndexSubTableFormat3::GetDataLength(ReadableFontData* data, @@ -31,37 +56,225 @@ int32_t IndexSubTableFormat3::GetDataLength(ReadableFontData* data, } IndexSubTableFormat3::IndexSubTableFormat3(ReadableFontData* data, - int32_t first, - int32_t last) - : IndexSubTable(data, first, last) { + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable(data, first_glyph_index, last_glyph_index) { } -IndexSubTableFormat3::~IndexSubTableFormat3() { +int32_t IndexSubTableFormat3::Loca(int32_t loca) { + int32_t read_offset = + data_->ReadUShort(EblcTable::Offset::kIndexSubTable3_offsetArray + + loca * DataSize::kUSHORT); + return read_offset; } -int32_t IndexSubTableFormat3::NumGlyphs() { - return last_glyph_index() - first_glyph_index() + 1; +/****************************************************************************** + * IndexSubTableFormat3::Builder class + ******************************************************************************/ +IndexSubTableFormat3::Builder::~Builder() { +} + +int32_t IndexSubTableFormat3::Builder::NumGlyphs() { + return GetOffsetArray()->size() - 1; } -int32_t IndexSubTableFormat3::GlyphOffset(int32_t glyph_id) { - if (CheckGlyphRange(glyph_id)) { - return Loca(glyph_id); +int32_t IndexSubTableFormat3::Builder::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; } - return -1; + return GetOffsetArray()->at(loca); } -int32_t IndexSubTableFormat3::GlyphLength(int32_t glyph_id) { - if (CheckGlyphRange(glyph_id)) { - return Loca(glyph_id + 1) - Loca(glyph_id); +int32_t IndexSubTableFormat3::Builder::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return 0; } - return -1; + IntegerList* offset_array = GetOffsetArray(); + return offset_array->at(loca + 1) - offset_array->at(loca); } -int32_t IndexSubTableFormat3::Loca(int32_t loca_index) { - int32_t read_offset = - data_->ReadUShort(EblcTable::Offset::kIndexSubTable3_offsetArray + - (loca_index - first_glyph_index()) * DataSize::kUSHORT); - return image_data_offset() + read_offset; +CALLER_ATTACH +BitmapGlyphInfoIter* IndexSubTableFormat3::Builder::GetIterator() { + Ptr<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator> it = + new IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator(this); + return it.Detach(); +} + +void IndexSubTableFormat3::Builder::Revert() { + offset_array_.clear(); + IndexSubTable::Builder::Revert(); +} + +void IndexSubTableFormat3::Builder::SetOffsetArray( + const IntegerList& offset_array) { + offset_array_.clear(); + offset_array_ = offset_array; + set_model_changed(); +} + +// static +CALLER_ATTACH IndexSubTableFormat3::Builder* +IndexSubTableFormat3::Builder::CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + ReadableFontDataPtr new_data; + new_data.Attach(down_cast<ReadableFontData*>( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat3BuilderPtr output = + new IndexSubTableFormat3::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat3::Builder* +IndexSubTableFormat3::Builder::CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + WritableFontDataPtr new_data; + new_data.Attach(down_cast<WritableFontData*>( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat3BuilderPtr output = + new IndexSubTableFormat3::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +CALLER_ATTACH FontDataTable* IndexSubTableFormat3::Builder::SubBuildTable( + ReadableFontData* data) { + IndexSubTableFormat3Ptr output = new IndexSubTableFormat3( + data, first_glyph_index(), last_glyph_index()); + return output.Detach(); +} + +void IndexSubTableFormat3::Builder::SubDataSet() { + Revert(); +} + +int32_t IndexSubTableFormat3::Builder::SubDataSizeToSerialize() { + if (offset_array_.empty()) { + return 0; + } + return EblcTable::Offset::kIndexSubHeaderLength + + offset_array_.size() * DataSize::kULONG; +} + +bool IndexSubTableFormat3::Builder::SubReadyToSerialize() { + if (!offset_array_.empty()) { + return true; + } + return false; +} + +int32_t IndexSubTableFormat3::Builder::SubSerialize( + WritableFontData* new_data) { + int32_t size = SerializeIndexSubHeader(new_data); + if (!model_changed()) { + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( + EblcTable::Offset::kIndexSubTable3_offsetArray))); + target.Attach(down_cast<WritableFontData*>(new_data->Slice( + EblcTable::Offset::kIndexSubTable3_offsetArray))); + size += source->CopyTo(target); + return size; + } + for (IntegerList::iterator b = GetOffsetArray()->begin(), + e = GetOffsetArray()->end(); b != e; b++) { + size += new_data->WriteUShort(size, *b); + } + return size; +} + +IndexSubTableFormat3::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IndexSubTableFormat3::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IntegerList* IndexSubTableFormat3::Builder::GetOffsetArray() { + if (offset_array_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &offset_array_; +} + +void IndexSubTableFormat3::Builder::Initialize(ReadableFontData* data) { + offset_array_.clear(); + if (data) { + int32_t num_offsets = (last_glyph_index() - first_glyph_index() + 1) + 1; + for (int32_t i = 0; i < num_offsets; ++i) { + offset_array_.push_back(data->ReadULongAsInt( + EblcTable::Offset::kIndexSubTable3_offsetArray + + i * DataSize::kULONG)); + } + } +} + +// static +int32_t IndexSubTableFormat3::Builder::DataLength( + ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + UNREFERENCED_PARAMETER(data); + UNREFERENCED_PARAMETER(index_sub_table_offset); + return EblcTable::Offset::kIndexSubHeaderLength + + (last_glyph_index - first_glyph_index + 1 + 1) * DataSize::kUSHORT; +} + +/****************************************************************************** + * IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + IndexSubTableFormat3::Builder* container) + : RefIterator<BitmapGlyphInfo, IndexSubTableFormat3::Builder, + IndexSubTable::Builder>(container) { + glyph_id_ = container->first_glyph_index(); +} + +bool IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::HasNext() { + if (glyph_id_ <= container()->last_glyph_index()) { + return true; + } + return false; +} + +CALLER_ATTACH BitmapGlyphInfo* +IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::Next() { + BitmapGlyphInfoPtr output; + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + output = new BitmapGlyphInfo(glyph_id_, + container()->image_data_offset(), + container()->GlyphStartOffset(glyph_id_), + container()->GlyphLength(glyph_id_), + container()->image_format()); + glyph_id_++; + return output.Detach(); } } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format3.h b/cpp/src/sfntly/table/bitmap/index_sub_table_format3.h index 1e45f23..2c4004c 100644 --- a/cpp/src/sfntly/table/bitmap/index_sub_table_format3.h +++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format3.h @@ -20,29 +20,91 @@ #include "sfntly/table/bitmap/index_sub_table.h" namespace sfntly { - +// Format 3 Index Subtable Entry. class IndexSubTableFormat3 : public IndexSubTable, public RefCounted<IndexSubTableFormat3> { public: - static int32_t GetDataLength(ReadableFontData* data, - int32_t offset, - int32_t first, - int32_t last); + class Builder : public IndexSubTable::Builder, + public RefCounted<Builder> { + public: + class BitmapGlyphInfoIterator + : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + int32_t glyph_id_; + }; + + virtual ~Builder(); + virtual int32_t NumGlyphs(); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + virtual int32_t GlyphLength(int32_t glyph_id); + CALLER_ATTACH virtual BitmapGlyphInfoIter* GetIterator(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + void SetOffsetArray(const IntegerList& offset_array); + + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + protected: + void Revert(); + + private: + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + IntegerList* GetOffsetArray(); + void Initialize(ReadableFontData* data); + + static int32_t DataLength(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + IntegerList offset_array_; + }; - // Note: the constructor does not implement offset/length form provided in - // Java to avoid heavy lifting in constructors. Callers to call - // GetDataLength() static method of the derived class to get proper - // length and slice ahead. - IndexSubTableFormat3(ReadableFontData* data, int32_t first, int32_t last); virtual ~IndexSubTableFormat3(); virtual int32_t NumGlyphs(); - virtual int32_t GlyphOffset(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id); virtual int32_t GlyphLength(int32_t glyph_id); + static int32_t GetDataLength(ReadableFontData* data, + int32_t offset, + int32_t first, + int32_t last); + private: + IndexSubTableFormat3(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); int32_t Loca(int32_t loca_index); + + friend class Builder; }; +typedef Ptr<IndexSubTableFormat3> IndexSubTableFormat3Ptr; +typedef Ptr<IndexSubTableFormat3::Builder> IndexSubTableFormat3BuilderPtr; } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format4.cc b/cpp/src/sfntly/table/bitmap/index_sub_table_format4.cc index 9ef681c..efa5f28 100644 --- a/cpp/src/sfntly/table/bitmap/index_sub_table_format4.cc +++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format4.cc @@ -19,18 +19,49 @@ #include "sfntly/table/bitmap/eblc_table.h" namespace sfntly { +/****************************************************************************** + * IndexSubTableFormat4 class + ******************************************************************************/ +IndexSubTableFormat4::~IndexSubTableFormat4() { +} -// static -int32_t IndexSubTableFormat4::GetDataLength(ReadableFontData* data, - int32_t offset, - int32_t first, - int32_t last) { - UNREFERENCED_PARAMETER(first); - UNREFERENCED_PARAMETER(last); - assert(data); - return data->ReadULongAsInt(offset + - EblcTable::Offset::kIndexSubTable4_numGlyphs) * - EblcTable::Offset::kCodeOffsetPairLength; +int32_t IndexSubTableFormat4::NumGlyphs() { + return IndexSubTableFormat4::NumGlyphs(data_, 0); +} + +int32_t IndexSubTableFormat4::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + int32_t pair_index = FindCodeOffsetPair(glyph_id); + if (pair_index < 0) { + return -1; + } + return data_->ReadUShort(EblcTable::Offset::kIndexSubTable4_glyphArray + + pair_index * + EblcTable::Offset::kCodeOffsetPairLength + + EblcTable::Offset::kCodeOffsetPair_offset); +} + +int32_t IndexSubTableFormat4::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + + int32_t pair_index = FindCodeOffsetPair(glyph_id); + if (pair_index < 0) { + return -1; + } + return data_->ReadUShort( + EblcTable::Offset::kIndexSubTable4_glyphArray + + (pair_index + 1) * EblcTable::Offset::kCodeOffsetPairLength + + EblcTable::Offset::kCodeOffsetPair_offset) - + data_->ReadUShort( + EblcTable::Offset::kIndexSubTable4_glyphArray + + (pair_index) * EblcTable::Offset::kCodeOffsetPairLength + + EblcTable::Offset::kCodeOffsetPair_offset); } IndexSubTableFormat4::IndexSubTableFormat4(ReadableFontData* data, @@ -39,50 +70,293 @@ IndexSubTableFormat4::IndexSubTableFormat4(ReadableFontData* data, : IndexSubTable(data, first, last) { } -IndexSubTableFormat4::~IndexSubTableFormat4() { +int32_t IndexSubTableFormat4::FindCodeOffsetPair(int32_t glyph_id) { + return data_->SearchUShort(EblcTable::Offset::kIndexSubTable4_glyphArray, + EblcTable::Offset::kCodeOffsetPairLength, + NumGlyphs(), + glyph_id); } -int32_t IndexSubTableFormat4::NumGlyphs() { - return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable4_numGlyphs); +int32_t IndexSubTableFormat4::NumGlyphs(ReadableFontData* data, + int32_t table_offset) { + int32_t num_glyphs = data->ReadULongAsInt(table_offset + + EblcTable::Offset::kIndexSubTable4_numGlyphs); + return num_glyphs; +} + +/****************************************************************************** + * IndexSubTableFormat4::CodeOffsetPair related class + ******************************************************************************/ +IndexSubTableFormat4::CodeOffsetPair::CodeOffsetPair(int32_t glyph_code, + int32_t offset) + : glyph_code_(glyph_code), offset_(offset) { +} + +IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder( + int32_t glyph_code, int32_t offset) + : CodeOffsetPair(glyph_code, offset) { +} + +bool IndexSubTableFormat4::CodeOffsetPairGlyphCodeComparator::operator()( + const CodeOffsetPair& lhs, const CodeOffsetPair& rhs) { + return lhs.glyph_code() < rhs.glyph_code(); +} + +/****************************************************************************** + * IndexSubTableFormat4::Builder class + ******************************************************************************/ +IndexSubTableFormat4::Builder::~Builder() { +} + +int32_t IndexSubTableFormat4::Builder::NumGlyphs() { + return GetOffsetArray()->size() - 1; +} + +int32_t IndexSubTableFormat4::Builder::GlyphLength(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return 0; + } + int32_t pair_index = FindCodeOffsetPair(glyph_id); + if (pair_index == -1) { + return 0; + } + return GetOffsetArray()->at(pair_index + 1).offset() - + GetOffsetArray()->at(pair_index).offset(); +} + +int32_t IndexSubTableFormat4::Builder::GlyphStartOffset(int32_t glyph_id) { + int32_t loca = CheckGlyphRange(glyph_id); + if (loca == -1) { + return -1; + } + int32_t pair_index = FindCodeOffsetPair(glyph_id); + if (pair_index == -1) { + return -1; + } + return GetOffsetArray()->at(pair_index).offset(); +} + +CALLER_ATTACH +BitmapGlyphInfoIter* IndexSubTableFormat4::Builder::GetIterator() { + Ptr<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator> it = + new IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator(this); + return it.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat4::Builder* +IndexSubTableFormat4::Builder::CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + ReadableFontDataPtr new_data; + new_data.Attach(down_cast<ReadableFontData*>( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat4BuilderPtr output = + new IndexSubTableFormat4::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat4::Builder* +IndexSubTableFormat4::Builder::CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + WritableFontDataPtr new_data; + new_data.Attach(down_cast<WritableFontData*>( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat4BuilderPtr output = + new IndexSubTableFormat4::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +CALLER_ATTACH FontDataTable* IndexSubTableFormat4::Builder::SubBuildTable( + ReadableFontData* data) { + IndexSubTableFormat4Ptr output = new IndexSubTableFormat4( + data, first_glyph_index(), last_glyph_index()); + return output.Detach(); +} + +void IndexSubTableFormat4::Builder::SubDataSet() { + Revert(); +} + +int32_t IndexSubTableFormat4::Builder::SubDataSizeToSerialize() { + if (offset_pair_array_.empty()) { + return 0; + } + return EblcTable::Offset::kIndexSubHeaderLength + DataSize::kULONG + + GetOffsetArray()->size() * + EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset; +} + +bool IndexSubTableFormat4::Builder::SubReadyToSerialize() { + if (!offset_pair_array_.empty()) { + return true; + } + return false; +} + +int32_t IndexSubTableFormat4::Builder::SubSerialize( + WritableFontData* new_data) { + int32_t size = SerializeIndexSubHeader(new_data); + if (!model_changed()) { + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( + EblcTable::Offset::kIndexSubTable4_glyphArray))); + target.Attach(down_cast<WritableFontData*>(new_data->Slice( + EblcTable::Offset::kIndexSubTable4_glyphArray))); + size += source->CopyTo(target); + return size; + } + + size += new_data->WriteLong(size, offset_pair_array_.size() - 1); + for (std::vector<CodeOffsetPairBuilder>::iterator + b = GetOffsetArray()->begin(), e = GetOffsetArray()->end(); + b != e; b++) { + size += new_data->WriteUShort(size, b->glyph_code()); + size += new_data->WriteUShort(size, b->offset()); + } + return size; +} + +void IndexSubTableFormat4::Builder::Revert() { + offset_pair_array_.clear(); + IndexSubTable::Builder::Revert(); +} + +void IndexSubTableFormat4::Builder::SetOffsetArray( + const std::vector<CodeOffsetPairBuilder>& pair_array) { + offset_pair_array_.clear(); + offset_pair_array_ = pair_array; + set_model_changed(); +} + +IndexSubTableFormat4::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { } -int32_t IndexSubTableFormat4::GlyphOffset(int32_t glyph_id) { - if (CheckGlyphRange(glyph_id)) { - int32_t pair_index = FindCodeOffsetPair(glyph_id); - if (pair_index < 0) { - return -1; +IndexSubTableFormat4::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +std::vector<IndexSubTableFormat4::CodeOffsetPairBuilder>* +IndexSubTableFormat4::Builder::GetOffsetArray() { + if (offset_pair_array_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &offset_pair_array_; +} + +void IndexSubTableFormat4::Builder::Initialize(ReadableFontData* data) { + offset_pair_array_.clear(); + if (data) { + int32_t num_pairs = IndexSubTableFormat4::NumGlyphs(data, 0) + 1; + int32_t offset = EblcTable::Offset::kIndexSubTable4_glyphArray; + for (int32_t i = 0; i < num_pairs; ++i) { + int32_t glyph_code = data->ReadUShort(offset + + EblcTable::Offset::kIndexSubTable4_codeOffsetPair_glyphCode); + int32_t glyph_offset = data->ReadUShort(offset + + EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset); + CodeOffsetPairBuilder pair_builder(glyph_code, glyph_offset); + offset_pair_array_.push_back(pair_builder); } - return data_->ReadUShort(
- EblcTable::Offset::kIndexSubTable4_glyphArray +
- pair_index * EblcTable::Offset::kCodeOffsetPairLength + - EblcTable::Offset::kCodeOffsetPair_offset); } - return -1; } -int32_t IndexSubTableFormat4::GlyphLength(int32_t glyph_id) { - if (CheckGlyphRange(glyph_id)) { - int32_t pair_index = FindCodeOffsetPair(glyph_id); - if (pair_index < 0) { - return -1; +int32_t IndexSubTableFormat4::Builder::FindCodeOffsetPair(int32_t glyph_id) { + std::vector<CodeOffsetPairBuilder>* pair_list = GetOffsetArray(); + int32_t location = 0; + int32_t bottom = 0; + int32_t top = pair_list->size(); + while (top != bottom) { + location = (top + bottom) / 2; + CodeOffsetPairBuilder* pair = &(pair_list->at(location)); + if (glyph_id < pair->glyph_code()) { + // location is below current location + top = location; + } else if (glyph_id > pair->glyph_code()) { + // location is above current location + bottom = location + 1; + } else { + return location; } - return data_->ReadUShort(
- EblcTable::Offset::kIndexSubTable4_glyphArray +
- (pair_index + 1) * EblcTable::Offset::kCodeOffsetPairLength +
- EblcTable::Offset::kCodeOffsetPair_offset) -
- data_->ReadUShort(
- EblcTable::Offset::kIndexSubTable4_glyphArray +
- (pair_index) * EblcTable::Offset::kCodeOffsetPairLength + - EblcTable::Offset::kCodeOffsetPair_offset); } return -1; } -int32_t IndexSubTableFormat4::FindCodeOffsetPair(int32_t glyph_id) { - return data_->SearchUShort(EblcTable::Offset::kIndexSubTable4_glyphArray, - EblcTable::Offset::kCodeOffsetPairLength, - NumGlyphs(), - glyph_id); +// static +int32_t IndexSubTableFormat4::Builder::DataLength( + ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t num_glyphs = IndexSubTableFormat4::NumGlyphs(data, + index_sub_table_offset); + UNREFERENCED_PARAMETER(first_glyph_index); + UNREFERENCED_PARAMETER(last_glyph_index); + return EblcTable::Offset::kIndexSubTable4_glyphArray + + num_glyphs * EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset; +} + + +/****************************************************************************** + * IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + IndexSubTableFormat4::Builder* container) + : RefIterator<BitmapGlyphInfo, IndexSubTableFormat4::Builder, + IndexSubTable::Builder>(container), + code_offset_pair_index_(0) { +} + +bool IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::HasNext() { + if (code_offset_pair_index_ < + (int32_t)(container()->GetOffsetArray()->size() - 1)) { + return true; + } + return false; +} + +CALLER_ATTACH BitmapGlyphInfo* +IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::Next() { + BitmapGlyphInfoPtr output; + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; + } + std::vector<CodeOffsetPairBuilder>* offset_array = + container()->GetOffsetArray(); + int32_t offset = offset_array->at(code_offset_pair_index_).offset(); + int32_t next_offset = offset_array->at(code_offset_pair_index_ + 1).offset(); + int32_t glyph_code = offset_array->at(code_offset_pair_index_).glyph_code(); + output = new BitmapGlyphInfo(glyph_code, + container()->image_data_offset(), + offset, + next_offset - offset, + container()->image_format()); + code_offset_pair_index_++; + return output.Detach(); } } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format4.h b/cpp/src/sfntly/table/bitmap/index_sub_table_format4.h index 821acca..258998d 100644 --- a/cpp/src/sfntly/table/bitmap/index_sub_table_format4.h +++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format4.h @@ -24,25 +24,112 @@ namespace sfntly { class IndexSubTableFormat4 : public IndexSubTable, public RefCounted<IndexSubTableFormat4> { public: - static int32_t GetDataLength(ReadableFontData* data, - int32_t offset, - int32_t first, - int32_t last); - - // Note: the constructor does not implement offset/length form provided in - // Java to avoid heavy lifting in constructors. Callers to call - // GetDataLength() static method of the derived class to get proper - // length and slice ahead. - IndexSubTableFormat4(ReadableFontData* data, int32_t first, int32_t last); + class CodeOffsetPair { + public: + int32_t glyph_code() const { return glyph_code_; } + int32_t offset() const { return offset_; } + + protected: + CodeOffsetPair(int32_t glyph_code, int32_t offset); + + // TODO(arthurhsu): C++ style guide prohibits protected members. + int32_t glyph_code_; + int32_t offset_; + }; + + class Builder; + class CodeOffsetPairBuilder : public CodeOffsetPair { + public: + void set_glyph_code(int32_t v) { glyph_code_ = v; } + void set_offset(int32_t v) { offset_ = v; } + + private: + CodeOffsetPairBuilder(int32_t glyph_code, int32_t offset); + + friend class Builder; + }; + + class CodeOffsetPairGlyphCodeComparator { + public: + bool operator()(const CodeOffsetPair& lhs, const CodeOffsetPair& rhs); + }; + + class Builder : public IndexSubTable::Builder, + public RefCounted<Builder> { + public: + class BitmapGlyphInfoIterator + : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + int32_t code_offset_pair_index_; + }; + + virtual ~Builder(); + virtual int32_t NumGlyphs(); + virtual int32_t GlyphLength(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + CALLER_ATTACH virtual BitmapGlyphInfoIter* GetIterator(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + void Revert(); + void SetOffsetArray(const std::vector<CodeOffsetPairBuilder>& pair_array); + + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + private: + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + std::vector<CodeOffsetPairBuilder>* GetOffsetArray(); + void Initialize(ReadableFontData* data); + int32_t FindCodeOffsetPair(int32_t glyph_id); + + static int32_t DataLength(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + std::vector<CodeOffsetPairBuilder> offset_pair_array_; + }; + virtual ~IndexSubTableFormat4(); virtual int32_t NumGlyphs(); - virtual int32_t GlyphOffset(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id); virtual int32_t GlyphLength(int32_t glyph_id); private: + IndexSubTableFormat4(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + int32_t FindCodeOffsetPair(int32_t glyph_id); + static int32_t NumGlyphs(ReadableFontData* data, int32_t table_offset); + + friend class Builder; }; +typedef Ptr<IndexSubTableFormat4> IndexSubTableFormat4Ptr; +typedef Ptr<IndexSubTableFormat4::Builder> IndexSubTableFormat4BuilderPtr; } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format5.cc b/cpp/src/sfntly/table/bitmap/index_sub_table_format5.cc index a2aed5c..7ba78ec 100644 --- a/cpp/src/sfntly/table/bitmap/index_sub_table_format5.cc +++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format5.cc @@ -16,50 +16,324 @@ #include "sfntly/table/bitmap/index_sub_table_format5.h" +#include <algorithm> + #include "sfntly/table/bitmap/eblc_table.h" namespace sfntly { +/****************************************************************************** + * IndexSubTableFormat5 class + ******************************************************************************/ +IndexSubTableFormat5::~IndexSubTableFormat5() { +} -// static -int32_t IndexSubTableFormat5::GetDataLength(ReadableFontData* data, - int32_t offset, - int32_t first, - int32_t last) { - UNREFERENCED_PARAMETER(first); - UNREFERENCED_PARAMETER(last); - assert(data); - return data->ReadULongAsInt(offset + - EblcTable::Offset::kIndexSubTable5_numGlyphs) * - EblcTable::Offset::kCodeOffsetPairLength; +int32_t IndexSubTableFormat5::NumGlyphs() { + return NumGlyphs(data_, 0); +} + +int32_t IndexSubTableFormat5::GlyphStartOffset(int32_t glyph_id) { + int32_t check = CheckGlyphRange(glyph_id); + if (check == -1) { + return -1; + } + int32_t loca = ReadFontData()->SearchUShort( + EblcTable::Offset::kIndexSubTable5_glyphArray, + DataSize::kUSHORT, + NumGlyphs(), + glyph_id); + if (loca == -1) { + return loca; + } + return loca * ImageSize(); +} + +int32_t IndexSubTableFormat5::GlyphLength(int32_t glyph_id) { + int32_t check = CheckGlyphRange(glyph_id); + if (check == -1) { + return 0; + } + return image_size_; +} + +int32_t IndexSubTableFormat5::ImageSize() { + return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable5_imageSize); +} + +CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat5::BigMetrics() { + ReadableFontDataPtr data; + data.Attach(down_cast<ReadableFontData*>(data_->Slice( + EblcTable::Offset::kIndexSubTable5_bigMetrics, + BigGlyphMetrics::Offset::kMetricsLength))); + BigGlyphMetricsPtr output = new BigGlyphMetrics(data); + return output.Detach(); } IndexSubTableFormat5::IndexSubTableFormat5(ReadableFontData* data, - int32_t first, - int32_t last) - : IndexSubTable(data, first, last) { + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable(data, first_glyph_index, last_glyph_index) { + image_size_ = data_->ReadULongAsInt( + EblcTable::Offset::kIndexSubTable5_imageSize); } -IndexSubTableFormat5::~IndexSubTableFormat5() { +// static +int32_t IndexSubTableFormat5::NumGlyphs(ReadableFontData* data, + int32_t table_offset) { + UNREFERENCED_PARAMETER(table_offset); + int32_t num_glyphs = data->ReadULongAsInt( + EblcTable::Offset::kIndexSubTable5_numGlyphs); + return num_glyphs; } -int32_t IndexSubTableFormat5::NumGlyphs() { - return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable5_numGlyphs); +/****************************************************************************** + * IndexSubTableFormat5::Builder class + ******************************************************************************/ +IndexSubTableFormat5::Builder::~Builder() { } -int32_t IndexSubTableFormat5::GlyphOffset(int32_t glyph_id) { - if (CheckGlyphRange(glyph_id)) { - return data_->ReadUShort( - EblcTable::Offset::kIndexSubTable5_glyphArray + - glyph_id * DataSize::kUSHORT); +int32_t IndexSubTableFormat5::Builder::NumGlyphs() { + return GetGlyphArray()->size(); +} + +int32_t IndexSubTableFormat5::Builder::GlyphLength(int32_t glyph_id) { + UNREFERENCED_PARAMETER(glyph_id); + return ImageSize(); +} + +int32_t IndexSubTableFormat5::Builder::GlyphStartOffset(int32_t glyph_id) { + int32_t check = CheckGlyphRange(glyph_id); + if (check == -1) { + return -1; + } + IntegerList* glyph_array = GetGlyphArray(); + IntegerList::iterator it = std::find(glyph_array->begin(), + glyph_array->end(), + glyph_id); + if (it == glyph_array->end()) { + return -1; } - return -1; + return (it - glyph_array->begin()) * ImageSize(); } -int32_t IndexSubTableFormat5::GlyphLength(int32_t glyph_id) { - if (CheckGlyphRange(glyph_id)) { - return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable5_imageSize); +CALLER_ATTACH +BitmapGlyphInfoIter* IndexSubTableFormat5::Builder::GetIterator() { + Ptr<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator> it = + new IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator(this); + return it.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat5::Builder* +IndexSubTableFormat5::Builder::CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + ReadableFontDataPtr new_data; + new_data.Attach(down_cast<ReadableFontData*>( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat5BuilderPtr output = + new IndexSubTableFormat5::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat5::Builder* +IndexSubTableFormat5::Builder::CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t length = Builder::DataLength(data, + index_sub_table_offset, + first_glyph_index, + last_glyph_index); + WritableFontDataPtr new_data; + new_data.Attach(down_cast<WritableFontData*>( + data->Slice(index_sub_table_offset, length))); + IndexSubTableFormat5BuilderPtr output = + new IndexSubTableFormat5::Builder(new_data, + first_glyph_index, + last_glyph_index); + return output.Detach(); +} + +CALLER_ATTACH FontDataTable* IndexSubTableFormat5::Builder::SubBuildTable( + ReadableFontData* data) { + IndexSubTableFormat5Ptr output = new IndexSubTableFormat5( + data, first_glyph_index(), last_glyph_index()); + return output.Detach(); +} + +void IndexSubTableFormat5::Builder::SubDataSet() { + if (model_changed()) { + Initialize(InternalReadData()); + } +} + +int32_t IndexSubTableFormat5::Builder::SubDataSizeToSerialize() { + if (glyph_array_.empty()) { + return 0; + } + return EblcTable::Offset::kIndexSubHeaderLength + + glyph_array_.size() * DataSize::kUSHORT; +} + +bool IndexSubTableFormat5::Builder::SubReadyToSerialize() { + if (!glyph_array_.empty()) { + return true; + } + return false; +} + +int32_t IndexSubTableFormat5::Builder::SubSerialize( + WritableFontData* new_data) { + int32_t size = SerializeIndexSubHeader(new_data); + if (!model_changed()) { + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( + EblcTable::Offset::kIndexSubTable5_imageSize))); + target.Attach(down_cast<WritableFontData*>(new_data->Slice( + EblcTable::Offset::kIndexSubTable5_imageSize))); + size += source->CopyTo(target); + return size; + } else { + ReadableFontDataPtr source; + WritableFontDataPtr target; + source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( + EblcTable::Offset::kIndexSubTable5_imageSize, + EblcTable::Offset::kIndexSubTable5_numGlyphs))); + target.Attach(down_cast<WritableFontData*>(new_data->Slice( + EblcTable::Offset::kIndexSubTable5_imageSize, + EblcTable::Offset::kIndexSubTable5_numGlyphs))); + size += source->CopyTo(target); + } + + size += new_data->WriteLong(size, glyph_array_.size()); + for (IntegerList::iterator b = glyph_array_.begin(), e = glyph_array_.end(); + b != e; b++) { + size += new_data->WriteUShort(size, *b); + } + return size; +} + +int32_t IndexSubTableFormat5::Builder::ImageSize() { + return InternalReadData()->ReadULongAsInt( + EblcTable::Offset::kIndexSubTable5_imageSize); +} + +void IndexSubTableFormat5::Builder::SetImageSize(int32_t image_size) { + InternalWriteData()->WriteULong( + EblcTable::Offset::kIndexSubTable5_imageSize, image_size); +} + +CALLER_ATTACH +BigGlyphMetrics::Builder* IndexSubTableFormat5::Builder::BigMetrics() { + WritableFontDataPtr data; + data.Attach(down_cast<WritableFontData*>(InternalWriteData()->Slice( + EblcTable::Offset::kIndexSubTable5_bigMetrics, + BigGlyphMetrics::Offset::kMetricsLength))); + BigGlyphMetricsBuilderPtr output = new BigGlyphMetrics::Builder(data); + return output.Detach(); +} + +IntegerList* IndexSubTableFormat5::Builder::GlyphArray() { + return GetGlyphArray(); +} + +void IndexSubTableFormat5::Builder::SetGlyphArray(const IntegerList& v) { + glyph_array_.clear(); + glyph_array_ = v; + set_model_changed(); +} + +void IndexSubTableFormat5::Builder::Revert() { + glyph_array_.clear(); + IndexSubTable::Builder::Revert(); +} + +IndexSubTableFormat5::Builder::Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IndexSubTableFormat5::Builder::Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index) + : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { +} + +IntegerList* IndexSubTableFormat5::Builder::GetGlyphArray() { + if (glyph_array_.empty()) { + Initialize(InternalReadData()); + set_model_changed(); + } + return &glyph_array_; +} + +void IndexSubTableFormat5::Builder::Initialize(ReadableFontData* data) { + glyph_array_.clear(); + if (data) { + int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data, 0); + for (int32_t i = 0; i < num_glyphs; ++i) { + glyph_array_.push_back(data->ReadULongAsInt( + EblcTable::Offset::kIndexSubTable5_glyphArray + + i * DataSize::kUSHORT)); + } + } +} + +// static +int32_t IndexSubTableFormat5::Builder::DataLength( + ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index) { + int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data, + index_sub_table_offset); + UNREFERENCED_PARAMETER(first_glyph_index); + UNREFERENCED_PARAMETER(last_glyph_index); + return EblcTable::Offset::kIndexSubTable5_glyphArray + + num_glyphs * DataSize::kUSHORT; +} + +/****************************************************************************** + * IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator class + ******************************************************************************/ +IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( + IndexSubTableFormat5::Builder* container) + : RefIterator<BitmapGlyphInfo, IndexSubTableFormat5::Builder, + IndexSubTable::Builder>(container), + offset_index_(0) { +} + +bool IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::HasNext() { + if (offset_index_ < (int32_t)(container()->GetGlyphArray()->size())) { + return true; + } + return false; +} + +CALLER_ATTACH BitmapGlyphInfo* +IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::Next() { + BitmapGlyphInfoPtr output; + if (!HasNext()) { + // Note: In C++, we do not throw exception when there's no element. + return NULL; } - return -1; + output = new BitmapGlyphInfo(container()->GetGlyphArray()->at(offset_index_), + container()->image_data_offset(), + offset_index_ * container()->ImageSize(), + container()->ImageSize(), + container()->image_format()); + offset_index_++; + return output.Detach(); } } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format5.h b/cpp/src/sfntly/table/bitmap/index_sub_table_format5.h index 354834e..c480fd8 100644 --- a/cpp/src/sfntly/table/bitmap/index_sub_table_format5.h +++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format5.h @@ -17,6 +17,7 @@ #ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_ #define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_ +#include "sfntly/table/bitmap/big_glyph_metrics.h" #include "sfntly/table/bitmap/index_sub_table.h" namespace sfntly { @@ -24,22 +25,90 @@ namespace sfntly { class IndexSubTableFormat5 : public IndexSubTable, public RefCounted<IndexSubTableFormat5> { public: - static int32_t GetDataLength(ReadableFontData* data, - int32_t offset, - int32_t first, - int32_t last); - - // Note: the constructor does not implement offset/length form provided in - // Java to avoid heavy lifting in constructors. Callers to call - // GetDataLength() static method of the derived class to get proper - // length and slice ahead. - IndexSubTableFormat5(ReadableFontData* data, int32_t first, int32_t last); + class Builder : public IndexSubTable::Builder, + public RefCounted<Builder> { + public: + class BitmapGlyphInfoIterator + : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> { + public: + explicit BitmapGlyphInfoIterator(Builder* container); + virtual ~BitmapGlyphInfoIterator() {} + + virtual bool HasNext(); + CALLER_ATTACH virtual BitmapGlyphInfo* Next(); + + private: + int32_t offset_index_; + }; + virtual ~Builder(); + virtual int32_t NumGlyphs(); + virtual int32_t GlyphLength(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id); + CALLER_ATTACH virtual BitmapGlyphInfoIter* GetIterator(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + + int32_t ImageSize(); + void SetImageSize(int32_t image_size); + CALLER_ATTACH BigGlyphMetrics::Builder* BigMetrics(); + IntegerList* GlyphArray(); + void SetGlyphArray(const IntegerList& v); + + static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + protected: + void Revert(); + + private: + Builder(WritableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + Builder(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + + IntegerList* GetGlyphArray(); + void Initialize(ReadableFontData* data); + + static int32_t DataLength(ReadableFontData* data, + int32_t index_sub_table_offset, + int32_t first_glyph_index, + int32_t last_glyph_index); + + IntegerList glyph_array_; + }; virtual ~IndexSubTableFormat5(); virtual int32_t NumGlyphs(); - virtual int32_t GlyphOffset(int32_t glyph_id); + virtual int32_t GlyphStartOffset(int32_t glyph_id); virtual int32_t GlyphLength(int32_t glyph_id); + + int32_t ImageSize(); + CALLER_ATTACH BigGlyphMetrics* BigMetrics(); + + private: + IndexSubTableFormat5(ReadableFontData* data, + int32_t first_glyph_index, + int32_t last_glyph_index); + + static int32_t NumGlyphs(ReadableFontData* dta, int32_t table_offset); + + int32_t image_size_; + + friend class Builder; }; +typedef Ptr<IndexSubTableFormat5> IndexSubTableFormat5Ptr; +typedef Ptr<IndexSubTableFormat5::Builder> IndexSubTableFormat5BuilderPtr; } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.cc b/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.cc index 85364fd..87031a1 100644 --- a/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.cc +++ b/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.cc @@ -25,4 +25,21 @@ SimpleBitmapGlyph::SimpleBitmapGlyph(ReadableFontData* data, int32_t format) SimpleBitmapGlyph::~SimpleBitmapGlyph() { } +SimpleBitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format) + : BitmapGlyph::Builder(data, format) { +} + +SimpleBitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format) + : BitmapGlyph::Builder(data, format) { +} + +SimpleBitmapGlyph::Builder::~Builder() { +} + +CALLER_ATTACH FontDataTable* +SimpleBitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) { + Ptr<SimpleBitmapGlyph> glyph = new SimpleBitmapGlyph(data, format()); + return glyph.Detach(); +} + } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.h b/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.h index 48bca98..56ede10 100644 --- a/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.h +++ b/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.h @@ -24,9 +24,20 @@ namespace sfntly { class SimpleBitmapGlyph : public BitmapGlyph, public RefCounted<SimpleBitmapGlyph> { public: + class Builder : public BitmapGlyph::Builder, + public RefCounted<Builder> { + public: + Builder(WritableFontData* data, int32_t format); + Builder(ReadableFontData* data, int32_t format); + virtual ~Builder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + }; + SimpleBitmapGlyph(ReadableFontData* data, int32_t format); virtual ~SimpleBitmapGlyph(); }; +typedef Ptr<SimpleBitmapGlyph> SimpleBitmapGlyphPtr; } // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/small_glyph_metrics.cc b/cpp/src/sfntly/table/bitmap/small_glyph_metrics.cc new file mode 100644 index 0000000..0f3c1e9 --- /dev/null +++ b/cpp/src/sfntly/table/bitmap/small_glyph_metrics.cc @@ -0,0 +1,126 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/bitmap/small_glyph_metrics.h" + +namespace sfntly { +/****************************************************************************** + * SmallGlyphMetrics class + ******************************************************************************/ +SmallGlyphMetrics::SmallGlyphMetrics(ReadableFontData* data) + : GlyphMetrics(data) { +} + +SmallGlyphMetrics::~SmallGlyphMetrics() { +} + +int32_t SmallGlyphMetrics::Height() { + return data_->ReadByte(Offset::kHeight); +} + +int32_t SmallGlyphMetrics::Width() { + return data_->ReadByte(Offset::kWidth); +} + +int32_t SmallGlyphMetrics::BearingX() { + return data_->ReadByte(Offset::kBearingX); +} + +int32_t SmallGlyphMetrics::BearingY() { + return data_->ReadByte(Offset::kBearingY); +} + +int32_t SmallGlyphMetrics::Advance() { + return data_->ReadByte(Offset::kAdvance); +} + +/****************************************************************************** + * SmallGlyphMetrics::Builder class + ******************************************************************************/ +SmallGlyphMetrics::Builder::Builder(WritableFontData* data) + : GlyphMetrics::Builder(data) { +} + +SmallGlyphMetrics::Builder::Builder(ReadableFontData* data) + : GlyphMetrics::Builder(data) { +} + +SmallGlyphMetrics::Builder::~Builder() { +} + +int32_t SmallGlyphMetrics::Builder::Height() { + return InternalReadData()->ReadByte(Offset::kHeight); +} + +void SmallGlyphMetrics::Builder::SetHeight(byte_t height) { + InternalWriteData()->WriteByte(Offset::kHeight, height); +} + +int32_t SmallGlyphMetrics::Builder::Width() { + return InternalReadData()->ReadByte(Offset::kWidth); +} + +void SmallGlyphMetrics::Builder::SetWidth(byte_t width) { + InternalWriteData()->WriteByte(Offset::kWidth, width); +} + +int32_t SmallGlyphMetrics::Builder::BearingX() { + return InternalReadData()->ReadByte(Offset::kBearingX); +} + +void SmallGlyphMetrics::Builder::SetBearingX(byte_t bearing) { + InternalWriteData()->WriteByte(Offset::kBearingX, bearing); +} + +int32_t SmallGlyphMetrics::Builder::BearingY() { + return InternalReadData()->ReadByte(Offset::kBearingY); +} + +void SmallGlyphMetrics::Builder::SetBearingY(byte_t bearing) { + InternalWriteData()->WriteByte(Offset::kBearingY, bearing); +} + +int32_t SmallGlyphMetrics::Builder::Advance() { + return InternalReadData()->ReadByte(Offset::kAdvance); +} + +void SmallGlyphMetrics::Builder::SetAdvance(byte_t advance) { + InternalWriteData()->WriteByte(Offset::kAdvance, advance); +} + +CALLER_ATTACH FontDataTable* + SmallGlyphMetrics::Builder::SubBuildTable(ReadableFontData* data) { + SmallGlyphMetricsPtr output = new SmallGlyphMetrics(data); + return output.Detach(); +} + +void SmallGlyphMetrics::Builder::SubDataSet() { + // NOP. +} + +int32_t SmallGlyphMetrics::Builder::SubDataSizeToSerialize() { + return 0; +} + +bool SmallGlyphMetrics::Builder::SubReadyToSerialize() { + return false; +} + +int32_t SmallGlyphMetrics::Builder::SubSerialize(WritableFontData* new_data) { + return Data()->CopyTo(new_data); +} + +} // namespace sfntly diff --git a/cpp/src/sfntly/table/bitmap/small_glyph_metrics.h b/cpp/src/sfntly/table/bitmap/small_glyph_metrics.h new file mode 100644 index 0000000..ea13720 --- /dev/null +++ b/cpp/src/sfntly/table/bitmap/small_glyph_metrics.h @@ -0,0 +1,79 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_ + +#include "sfntly/port/refcount.h" +#include "sfntly/table/bitmap/glyph_metrics.h" + +namespace sfntly { + +class SmallGlyphMetrics : public GlyphMetrics, + public RefCounted<SmallGlyphMetrics> { + public: + struct Offset { + enum { + kMetricsLength = 5, + kHeight = 0, + kWidth = 1, + kBearingX = 2, + kBearingY = 3, + kAdvance = 4, + }; + }; + + class Builder : public GlyphMetrics::Builder, + public RefCounted<Builder> { + public: + // Constructor scope altered to public because C++ does not allow base + // class to instantiate derived class with protected constructors. + explicit Builder(WritableFontData* data); + explicit Builder(ReadableFontData* data); + virtual ~Builder(); + + int32_t Height(); + void SetHeight(byte_t height); + int32_t Width(); + void SetWidth(byte_t width); + int32_t BearingX(); + void SetBearingX(byte_t bearing); + int32_t BearingY(); + void SetBearingY(byte_t bearing); + int32_t Advance(); + void SetAdvance(byte_t advance); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + virtual void SubDataSet(); + virtual int32_t SubDataSizeToSerialize(); + virtual bool SubReadyToSerialize(); + virtual int32_t SubSerialize(WritableFontData* new_data); + }; + + explicit SmallGlyphMetrics(ReadableFontData* data); + virtual ~SmallGlyphMetrics(); + + int32_t Height(); + int32_t Width(); + int32_t BearingX(); + int32_t BearingY(); + int32_t Advance(); +}; +typedef Ptr<SmallGlyphMetrics> SmallGlyphMetricsPtr; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_ diff --git a/cpp/src/sfntly/table/byte_array_table_builder.cc b/cpp/src/sfntly/table/byte_array_table_builder.cc new file mode 100644 index 0000000..631a05f --- /dev/null +++ b/cpp/src/sfntly/table/byte_array_table_builder.cc @@ -0,0 +1,70 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/byte_array_table_builder.h" + +namespace sfntly { + +ByteArrayTableBuilder::~ByteArrayTableBuilder() {} + +int32_t ByteArrayTableBuilder::ByteValue(int32_t index) { + ReadableFontDataPtr data = InternalReadData(); + if (data == NULL) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("No font data for the table"); +#endif + return -1; + } + return data->ReadByte(index); +} + +void ByteArrayTableBuilder::SetByteValue(int32_t index, byte_t b) { + WritableFontDataPtr data = InternalWriteData(); + if (data == NULL) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("No font data for the table"); +#endif + return; + } + data->WriteByte(index, b); +} + +int32_t ByteArrayTableBuilder::ByteCount() { + ReadableFontDataPtr data = InternalReadData(); + if (data == NULL) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("No font data for the table"); +#endif + return 0; + } + return data->Length(); +} + +ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header, + WritableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header, + ReadableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header) + : TableBasedTableBuilder(header) { +} + +} // namespace sfntly diff --git a/cpp/src/sfntly/table/byte_array_table_builder.h b/cpp/src/sfntly/table/byte_array_table_builder.h new file mode 100644 index 0000000..42d27a8 --- /dev/null +++ b/cpp/src/sfntly/table/byte_array_table_builder.h @@ -0,0 +1,53 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ + +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +// An abstract builder base for byte array based tables. +class ByteArrayTableBuilder : public TableBasedTableBuilder { + public: + virtual ~ByteArrayTableBuilder(); + + // Get the byte value at the specified index. The index is relative to the + // start of the table. + // @param index index relative to the start of the table + // @return byte value at the given index + virtual int32_t ByteValue(int32_t index); + + // Set the byte value at the specified index. The index is relative to the + // start of the table. + // @param index index relative to the start of the table + // @param b byte value to set + virtual void SetByteValue(int32_t index, byte_t b); + + // Get the number of bytes set for this table. It may include padding bytes at + // the end. + virtual int32_t ByteCount(); + + protected: + ByteArrayTableBuilder(Header* header, WritableFontData* data); + ByteArrayTableBuilder(Header* header, ReadableFontData* data); + explicit ByteArrayTableBuilder(Header* header); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ diff --git a/cpp/src/sfntly/table/core/name_table.cc b/cpp/src/sfntly/table/core/name_table.cc index 9853130..5f6d5a5 100644 --- a/cpp/src/sfntly/table/core/name_table.cc +++ b/cpp/src/sfntly/table/core/name_table.cc @@ -227,27 +227,31 @@ bool NameTable::NameEntryFilterInPlace::Accept(int32_t platform_id, /****************************************************************************** * NameTable::NameEntryIterator class ******************************************************************************/ -NameTable::NameEntryIterator::NameEntryIterator(NameTable* table) { - Init(table, NULL); +NameTable::NameEntryIterator::NameEntryIterator(NameTable* table) + : RefIterator<NameEntry, NameTable>(table), + name_index_(0), + filter_(NULL) { } NameTable::NameEntryIterator::NameEntryIterator(NameTable* table, - NameEntryFilter* filter) { - Init(table, filter); + NameEntryFilter* filter) + : RefIterator<NameEntry, NameTable>(table), + name_index_(0), + filter_(filter) { } bool NameTable::NameEntryIterator::HasNext() { if (!filter_) { - if (name_index_ < table_->NameCount()) { + if (name_index_ < container()->NameCount()) { return true; } return false; } - for (; name_index_ < table_->NameCount(); ++name_index_) { - if (filter_->Accept(table_->PlatformId(name_index_), - table_->EncodingId(name_index_), - table_->LanguageId(name_index_), - table_->NameId(name_index_))) { + 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; } } @@ -257,21 +261,7 @@ bool NameTable::NameEntryIterator::HasNext() { CALLER_ATTACH NameTable::NameEntry* NameTable::NameEntryIterator::Next() { if (!HasNext()) return NULL; - return table_->GetNameEntry(name_index_++); -} - -void NameTable::NameEntryIterator::Remove() { -#if !defined (SFNTLY_NO_EXCEPTION) - throw UnsupportedOperationException( - "Cannot remove a name table from an existing font."); -#endif -} - -void NameTable::NameEntryIterator::Init(NameTable* table, - NameEntryFilter* filter) { - table_ = table; - filter_ = filter; - name_index_ = 0; + return container()->GetNameEntry(name_index_++); } /****************************************************************************** @@ -423,10 +413,11 @@ int32_t NameTable::Builder::SubSerialize(WritableFontData* new_data) { void NameTable::Builder::Initialize(ReadableFontData* data) { if (data) { NameTablePtr table = new NameTable(header(), data); - NameEntryIterator name_iter(table, NULL); - while (name_iter.HasNext()) { + Ptr<NameEntryIterator> name_iter; + name_iter.Attach(table->Iterator()); + while (name_iter->HasNext()) { NameEntryPtr name_entry; - name_entry.Attach(name_iter.Next()); + 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(); @@ -532,21 +523,25 @@ CALLER_ATTACH NameTable::NameEntry* NameTable::GetNameEntry(int32_t platform_id, int32_t name_id) { NameTable::NameEntryFilterInPlace filter(platform_id, encoding_id, language_id, name_id); - NameTable::NameEntryIterator* name_entry_iter = Iterator(&filter); + Ptr<NameTable::NameEntryIterator> name_entry_iter; + name_entry_iter.Attach(Iterator(&filter)); NameEntryPtr result; if (name_entry_iter->HasNext()) { result = name_entry_iter->Next(); } - delete name_entry_iter; return result; } -NameTable::NameEntryIterator* NameTable::Iterator() { - return new NameTable::NameEntryIterator(this); +CALLER_ATTACH NameTable::NameEntryIterator* NameTable::Iterator() { + Ptr<NameEntryIterator> output = new NameTable::NameEntryIterator(this); + return output.Detach(); } +CALLER_ATTACH NameTable::NameEntryIterator* NameTable::Iterator(NameEntryFilter* filter) { - return new NameTable::NameEntryIterator(this, filter); + Ptr<NameEntryIterator> output = + new NameTable::NameEntryIterator(this, filter); + return output.Detach(); } NameTable::NameTable(Header* header, ReadableFontData* data) diff --git a/cpp/src/sfntly/table/core/name_table.h b/cpp/src/sfntly/table/core/name_table.h index 0c657da..9c007a1 100644 --- a/cpp/src/sfntly/table/core/name_table.h +++ b/cpp/src/sfntly/table/core/name_table.h @@ -26,6 +26,7 @@ #include <map> #include <utility> +#include "sfntly/port/java_iterator.h" #include "sfntly/table/subtable_container_table.h" #if defined U_USING_ICU_NAMESPACE @@ -555,23 +556,17 @@ class NameTable : public SubTableContainerTable, public RefCounted<NameTable> { int32_t name_id_; }; - // Mimic Java's iterator to iterate through the entries within the name table. - class NameEntryIterator { + class NameEntryIterator : public RefIterator<NameEntry, NameTable> { public: // If filter is NULL, filter through all tables. explicit NameEntryIterator(NameTable* table); NameEntryIterator(NameTable* table, NameEntryFilter* filter); - // Make gcc -Wnon-virtual-dtor happy. virtual ~NameEntryIterator() {} virtual bool HasNext(); virtual CALLER_ATTACH NameEntry* Next(); - virtual void Remove(); private: - void Init(NameTable* table, NameEntryFilter* filter); - - NameTable* table_; // Use dumb pointer since it's a composition object. int32_t name_index_; NameEntryFilter* filter_; }; @@ -686,9 +681,8 @@ class NameTable : public SubTableContainerTable, public RefCounted<NameTable> { // virtual void names(std::set<NameEntryPtr>*); // Get the iterator to iterate through all name entries. - // Note: Caller delete the returned object. - virtual NameEntryIterator* Iterator(); - virtual NameEntryIterator* Iterator(NameEntryFilter* filter); + virtual CALLER_ATTACH NameEntryIterator* Iterator(); + virtual CALLER_ATTACH NameEntryIterator* Iterator(NameEntryFilter* filter); private: struct Offset { diff --git a/cpp/src/sfntly/table/font_data_table.cc b/cpp/src/sfntly/table/font_data_table.cc index 0197bbd..7953269 100644 --- a/cpp/src/sfntly/table/font_data_table.cc +++ b/cpp/src/sfntly/table/font_data_table.cc @@ -53,6 +53,9 @@ CALLER_ATTACH WritableFontData* FontDataTable::Builder::Data() { WritableFontDataPtr new_data; if (model_changed_) { if (!SubReadyToSerialize()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("Table not ready to build."); +#endif return NULL; } int32_t size = SubDataSizeToSerialize(); @@ -80,6 +83,9 @@ CALLER_ATTACH FontDataTable* FontDataTable::Builder::Build() { if (model_changed_) { // Let subclass serialize from model. if (!SubReadyToSerialize()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IOException("Table not ready to build."); +#endif return NULL; } int32_t size = SubDataSizeToSerialize(); @@ -113,9 +119,17 @@ WritableFontData* FontDataTable::Builder::InternalWriteData() { WritableFontDataPtr new_data; new_data.Attach(WritableFontData::CreateWritableFontData( r_data_ == NULL ? 0 : r_data_->Length())); - if (r_data_) { - r_data_->CopyTo(new_data); +#if !defined (SFNTLY_NO_EXCEPTION) + try { +#endif + if (r_data_) { + r_data_->CopyTo(new_data); + } +#if !defined (SFNTLY_NO_EXCEPTION) + } catch (IOException& e) { + // TODO(stuartg): fix when IOExceptions are cleaned up } +#endif InternalSetData(new_data, false); } return w_data_.p_; diff --git a/cpp/src/sfntly/table/generic_table_builder.cc b/cpp/src/sfntly/table/generic_table_builder.cc new file mode 100644 index 0000000..78e6797 --- /dev/null +++ b/cpp/src/sfntly/table/generic_table_builder.cc @@ -0,0 +1,49 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sfntly/table/generic_table_builder.h" + +namespace sfntly { + +GenericTableBuilder::~GenericTableBuilder() {} + +CALLER_ATTACH +FontDataTable* GenericTableBuilder::SubBuildTable(ReadableFontData* data) { + // Note: In C++ port, we use GenericTable, the ref-counted version of Table + UNREFERENCED_PARAMETER(data); + Ptr<GenericTable> table = new GenericTable(header(), InternalReadData()); + return table.Detach(); +} + +// static +CALLER_ATTACH GenericTableBuilder* + GenericTableBuilder::CreateBuilder(Header* header, WritableFontData* data) { + Ptr<GenericTableBuilder> builder = + new GenericTableBuilder(header, data); + return builder.Detach(); +} + +GenericTableBuilder::GenericTableBuilder(Header* header, + WritableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +GenericTableBuilder::GenericTableBuilder(Header* header, + ReadableFontData* data) + : TableBasedTableBuilder(header, data) { +} + +} // namespace sfntly diff --git a/cpp/src/sfntly/table/generic_table_builder.h b/cpp/src/sfntly/table/generic_table_builder.h new file mode 100644 index 0000000..a100ea0 --- /dev/null +++ b/cpp/src/sfntly/table/generic_table_builder.h @@ -0,0 +1,42 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_GENERIC_TABLE_BUILDER_H_ +#define SFNTLY_CPP_SRC_SFNTLY_TABLE_GENERIC_TABLE_BUILDER_H_ + +#include "sfntly/table/table_based_table_builder.h" + +namespace sfntly { + +// A table builder to do the minimal table building for an unknown table type. +class GenericTableBuilder : public TableBasedTableBuilder, + public RefCounted<GenericTableBuilder> { + public: + virtual ~GenericTableBuilder(); + + virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); + + static CALLER_ATTACH GenericTableBuilder* + CreateBuilder(Header* header, WritableFontData* data); + + private: + GenericTableBuilder(Header* header, WritableFontData* data); + GenericTableBuilder(Header* header, ReadableFontData* data); +}; + +} // namespace sfntly + +#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_ diff --git a/cpp/src/sfntly/table/header.h b/cpp/src/sfntly/table/header.h index 117da95..280e556 100644 --- a/cpp/src/sfntly/table/header.h +++ b/cpp/src/sfntly/table/header.h @@ -22,7 +22,7 @@ namespace sfntly { class Header : public RefCounted<Header> { - public: + public: // Make a partial header with only the basic info for an empty new table. explicit Header(int32_t tag); @@ -36,7 +36,10 @@ class Header : public RefCounted<Header> { // Get the table tag. int32_t tag() { return tag_; } - // Get the table offset. The offset is from the start of the font file. + // Get the table offset. The offset is from the start of the font file. This + // offset value is what was read from the font file during construction of the + // font. It may not be meaningful if the font was maninpulated through the + // builders. int32_t offset() { return offset_; } // Is the offset in the header valid. The offset will not be valid if the @@ -44,12 +47,15 @@ class Header : public RefCounted<Header> { // font file. bool offset_valid() { return offset_valid_; } - // Get the length of the table as recorded in the table record header. + // Get the length of the table as recorded in the table record header. During + // building the header length will reflect the length that was initially read + // from the font file. This may not be consistent with the current state of + // the data. int32_t length() { return length_; } // Is the length in the header valid. The length will not be valid if the // table was constructed during building and has no physical location in a - // font file. + // font file until the table is built from the builder. bool length_valid() { return length_valid_; } // Get the checksum for the table as recorded in the table record header. @@ -65,7 +71,7 @@ class Header : public RefCounted<Header> { // int hashCode() // string toString() - private: + private: int32_t tag_; int32_t offset_; bool offset_valid_; diff --git a/cpp/src/sfntly/table/subtable.cc b/cpp/src/sfntly/table/subtable.cc index d70b18c..b990c7c 100644 --- a/cpp/src/sfntly/table/subtable.cc +++ b/cpp/src/sfntly/table/subtable.cc @@ -22,6 +22,11 @@ namespace sfntly { ******************************************************************************/ SubTable::~SubTable() {} +SubTable::SubTable(ReadableFontData* data, ReadableFontData* master_data) + : FontDataTable(data), padding_(0) { + master_data_ = master_data; +} + SubTable::SubTable(ReadableFontData* data) : FontDataTable(data), padding_(0) { } @@ -29,7 +34,23 @@ SubTable::SubTable(ReadableFontData* data) /****************************************************************************** * SubTable::Builder class ******************************************************************************/ -SubTable::Builder::~Builder() {} +SubTable::Builder::Builder() { +} + +SubTable::Builder::~Builder() { +} + +SubTable::Builder::Builder(WritableFontData* data, + ReadableFontData* master_data) + : FontDataTable::Builder(data) { + master_data_ = master_data; +} + +SubTable::Builder::Builder(ReadableFontData* data, + ReadableFontData* master_data) + : FontDataTable::Builder(data) { + master_data_ = master_data; +} SubTable::Builder::Builder(WritableFontData* data) : FontDataTable::Builder(data) { diff --git a/cpp/src/sfntly/table/subtable.h b/cpp/src/sfntly/table/subtable.h index e5ec748..fbfb4b0 100644 --- a/cpp/src/sfntly/table/subtable.h +++ b/cpp/src/sfntly/table/subtable.h @@ -29,24 +29,43 @@ class SubTable : public FontDataTable { public: class Builder : public FontDataTable::Builder { public: + // Creates a new empty sub-table. + Builder(); virtual ~Builder(); protected: - Builder(WritableFontData* data); - Builder(ReadableFontData* data); + // @param data the data for the subtable being built + // @param master_data the data for the full table + Builder(WritableFontData* data, ReadableFontData* master_data); + Builder(ReadableFontData* data, ReadableFontData* master_data); + explicit Builder(WritableFontData* data); + explicit Builder(ReadableFontData* data); + + ReadableFontData* master_read_data() { return master_data_; } + + private: + ReadableFontDataPtr master_data_; }; virtual ~SubTable(); int32_t padding() { return padding_; } + // Sets the amount of padding that is part of the data being used by this + // subtable. void set_padding(int32_t padding) { padding_ = padding; } protected: + SubTable(ReadableFontData* data, ReadableFontData* master_data); + // Note: constructor refactored in C++ to avoid heavy lifting. // caller need to do data->Slice(offset, length) beforehand. explicit SubTable(ReadableFontData* data); + ReadableFontData* master_read_data() { return master_data_; } + private: + // The data for the whole table in which this subtable is contained. + ReadableFontDataPtr master_data_; int32_t padding_; }; diff --git a/cpp/src/sfntly/table/table.cc b/cpp/src/sfntly/table/table.cc index 6cfe1f8..f1ff63d 100644 --- a/cpp/src/sfntly/table/table.cc +++ b/cpp/src/sfntly/table/table.cc @@ -31,6 +31,7 @@ #include "sfntly/table/core/maximum_profile_table.h" #include "sfntly/table/core/name_table.h" #include "sfntly/table/core/os2_table.h" +#include "sfntly/table/generic_table_builder.h" #include "sfntly/table/table_based_table_builder.h" #include "sfntly/table/truetype/glyph_table.h" #include "sfntly/table/truetype/loca_table.h" diff --git a/cpp/src/sfntly/table/table_based_table_builder.cc b/cpp/src/sfntly/table/table_based_table_builder.cc index 6e6a46a..b505704 100644 --- a/cpp/src/sfntly/table/table_based_table_builder.cc +++ b/cpp/src/sfntly/table/table_based_table_builder.cc @@ -18,7 +18,6 @@ namespace sfntly { - /****************************************************************************** * TableBasedTableBuilder class ******************************************************************************/ @@ -67,27 +66,4 @@ Table* TableBasedTableBuilder::GetTable() { return table_; } -/****************************************************************************** - * GenericTableBuilder class - ******************************************************************************/ -GenericTableBuilder::GenericTableBuilder(Header* header, - WritableFontData* data) - : TableBasedTableBuilder(header, data) { -} - -CALLER_ATTACH FontDataTable* - GenericTableBuilder::SubBuildTable(ReadableFontData* data) { - // Note: In C++ port, we use GenericTable, the ref-counted version of Table - UNREFERENCED_PARAMETER(data); - FontDataTablePtr table = new GenericTable(this->header(), InternalReadData()); - return table.Detach(); -} - -CALLER_ATTACH GenericTableBuilder* - GenericTableBuilder::CreateBuilder(Header* header, WritableFontData* data) { - Ptr<GenericTableBuilder> builder = - new GenericTableBuilder(header, data); - return builder.Detach(); -} - } // namespace sfntly diff --git a/cpp/src/sfntly/table/table_based_table_builder.h b/cpp/src/sfntly/table/table_based_table_builder.h index 3868d46..d88eefd 100644 --- a/cpp/src/sfntly/table/table_based_table_builder.h +++ b/cpp/src/sfntly/table/table_based_table_builder.h @@ -34,7 +34,7 @@ class TableBasedTableBuilder : public Table::Builder { protected: TableBasedTableBuilder(Header* header, WritableFontData* data); TableBasedTableBuilder(Header* header, ReadableFontData* data); - TableBasedTableBuilder(Header* header); + explicit TableBasedTableBuilder(Header* header); // C++ port: renamed table() to GetTable() virtual Table* GetTable(); @@ -43,17 +43,6 @@ class TableBasedTableBuilder : public Table::Builder { TablePtr table_; }; -class GenericTableBuilder : public TableBasedTableBuilder, - public RefCounted<GenericTableBuilder> { - public: - GenericTableBuilder(Header* header, WritableFontData* data); - virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); - - static CALLER_ATTACH - GenericTableBuilder* CreateBuilder(Header* header, - WritableFontData* data); -}; - } // namespace sfntly #endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_BASED_TABLE_BUILDER_H_ diff --git a/cpp/src/sfntly/table/truetype/glyph_table.cc b/cpp/src/sfntly/table/truetype/glyph_table.cc index dc1163a..bec9c89 100644 --- a/cpp/src/sfntly/table/truetype/glyph_table.cc +++ b/cpp/src/sfntly/table/truetype/glyph_table.cc @@ -162,10 +162,6 @@ void GlyphTable::Builder::Initialize(ReadableFontData* data, const IntegerList& loca) { if (data != NULL) { if (loca_.empty()) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IllegalStateException( - "Loca values not set - unable to parse glyph data."); -#endif return; } int32_t loca_value; @@ -186,6 +182,13 @@ void GlyphTable::Builder::Initialize(ReadableFontData* data, GlyphTable::GlyphBuilderList* GlyphTable::Builder::GetGlyphBuilders() { if (glyph_builders_.empty()) { + if (InternalReadData() && !loca_.empty()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalStateException( + "Loca values not set - unable to parse glyph data."); +#endif + return NULL; + } Initialize(InternalReadData(), loca_); set_model_changed(); } diff --git a/cpp/src/sfntly/table/truetype/glyph_table.h b/cpp/src/sfntly/table/truetype/glyph_table.h index 3ba9cac..f8a7c33 100644 --- a/cpp/src/sfntly/table/truetype/glyph_table.h +++ b/cpp/src/sfntly/table/truetype/glyph_table.h @@ -53,8 +53,8 @@ class GlyphTable : public SubTableContainerTable, // Incoming table_builder is GlyphTable::Builder*. // Note: constructor refactored in C++ to avoid heavy lifting. // caller need to do data->Slice(offset, length) beforehand. - Builder(WritableFontData* data); - Builder(ReadableFontData* data); + explicit Builder(WritableFontData* data); + explicit Builder(ReadableFontData* data); static CALLER_ATTACH Builder* GetBuilder(GlyphTable::Builder* table_builder, @@ -128,7 +128,12 @@ class GlyphTable : public SubTableContainerTable, // invalid, then an empty glyph builder List will be returned. GlyphBuilderList* GlyphBuilders(); - // Replace the internal glyph builders with the one provided. + // Replace the internal glyph builders with the one provided. The provided + // list and all contained objects belong to this builder. + // This call is only required if the entire set of glyphs in the glyph + // table builder are being replaced. If the glyph builder list provided from + // the GlyphTable.Builder::GlyphBuilders() is being used and modified + // then those changes will already be reflected in the glyph table builder. void SetGlyphBuilders(GlyphBuilderList* glyph_builders); // Glyph builder factories @@ -173,8 +178,8 @@ class GlyphTable : public SubTableContainerTable, protected: // Note: constructor refactored in C++ to avoid heavy lifting. // caller need to do data->Slice(offset, length) beforehand. - SimpleGlyphBuilder(WritableFontData* data); - SimpleGlyphBuilder(ReadableFontData* data); + explicit SimpleGlyphBuilder(WritableFontData* data); + explicit SimpleGlyphBuilder(ReadableFontData* data); virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); @@ -244,8 +249,8 @@ class GlyphTable : public SubTableContainerTable, protected: // Note: constructor refactored in C++ to avoid heavy lifting. // caller need to do data->Slice(offset, length) beforehand. - CompositeGlyphBuilder(WritableFontData* data); - CompositeGlyphBuilder(ReadableFontData* data); + explicit CompositeGlyphBuilder(WritableFontData* data); + explicit CompositeGlyphBuilder(ReadableFontData* data); virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data); diff --git a/cpp/src/sfntly/table/truetype/loca_table.cc b/cpp/src/sfntly/table/truetype/loca_table.cc index 0a579ae..c692155 100644 --- a/cpp/src/sfntly/table/truetype/loca_table.cc +++ b/cpp/src/sfntly/table/truetype/loca_table.cc @@ -73,16 +73,15 @@ LocaTable::LocaTable(Header* header, * LocaTable::Iterator class ******************************************************************************/ LocaTable::LocaIterator::LocaIterator(LocaTable* table) - : index_(-1) { - table_ = table; + : PODIterator<int32_t, LocaTable>(table), index_(-1) { } bool LocaTable::LocaIterator::HasNext() { - return index_ <= table_->num_glyphs_; + return index_ <= container()->num_glyphs_; } int32_t LocaTable::LocaIterator::Next() { - return table_->Loca(index_++); + return container()->Loca(index_++); } /****************************************************************************** @@ -118,29 +117,22 @@ void LocaTable::Builder::SetLocaList(IntegerList* list) { loca_.clear(); if (list) { loca_ = *list; - num_glyphs_ = loca_.size(); set_model_changed(); } } int32_t LocaTable::Builder::GlyphOffset(int32_t glyph_id) { - if (glyph_id < 0 || glyph_id > (num_glyphs_ + 1)) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException("Glyph ID is out of bounds."); -#endif + if (CheckGlyphRange(glyph_id) == -1) { return 0; } - return Loca(glyph_id); + return GetLocaList()->at(glyph_id); } int32_t LocaTable::Builder::GlyphLength(int32_t glyph_id) { - if (glyph_id < 0 || glyph_id > (num_glyphs_ + 1)) { -#if !defined (SFNTLY_NO_EXCEPTION) - throw IndexOutOfBoundException("Glyph ID is out of bounds."); -#endif + if (CheckGlyphRange(glyph_id) == -1) { return 0; } - return Loca(glyph_id + 1) - Loca(glyph_id); + return GetLocaList()->at(glyph_id + 1) - GetLocaList()->at(glyph_id); } void LocaTable::Builder::SetNumGlyphs(int32_t num_glyphs) { @@ -148,10 +140,7 @@ void LocaTable::Builder::SetNumGlyphs(int32_t num_glyphs) { } int32_t LocaTable::Builder::NumGlyphs() { - if (!loca_.empty()) { - return loca_.size() - 1; - } - return num_glyphs_; + return LastGlyphIndex() - 1; } void LocaTable::Builder::Revert() { @@ -202,10 +191,12 @@ int32_t LocaTable::Builder::SubSerialize(WritableFontData* new_data) { size += new_data->WriteUShort(size, *l / 2); } } - return 0; + num_glyphs_ = loca_.size() - 1; + return size; } void LocaTable::Builder::Initialize(ReadableFontData* data) { + ClearLoca(false); if (data) { if (NumGlyphs() < 0) { #if !defined (SFNTLY_NO_EXCEPTION) @@ -215,13 +206,28 @@ void LocaTable::Builder::Initialize(ReadableFontData* data) { } LocaTablePtr table = new LocaTable(header(), data, format_version_, num_glyphs_); - LocaTable::LocaIterator loca_iter(table); - while (loca_iter.HasNext()) { - loca_.push_back(loca_iter.Next()); + Ptr<LocaTable::LocaIterator> loca_iter = + new LocaTable::LocaIterator(table); + while (loca_iter->HasNext()) { + loca_.push_back(loca_iter->Next()); } } } +int32_t LocaTable::Builder::CheckGlyphRange(int32_t glyph_id) { + if (glyph_id < 0 || glyph_id > LastGlyphIndex()) { +#if !defined (SFNTLY_NO_EXCEPTION) + throw IndexOutOfBoundsException("Glyph ID is outside of the allowed range"); +#endif + return -1; + } + return glyph_id; +} + +int32_t LocaTable::Builder::LastGlyphIndex() { + return !loca_.empty() ? loca_.size() - 2 : num_glyphs_ - 1; +} + IntegerList* LocaTable::Builder::GetLocaList() { if (loca_.empty()) { Initialize(InternalReadData()); @@ -230,4 +236,11 @@ IntegerList* LocaTable::Builder::GetLocaList() { return &loca_; } +void LocaTable::Builder::ClearLoca(bool nullify) { + // Note: in C++ port, nullify is not used at all. + UNREFERENCED_PARAMETER(nullify); + loca_.clear(); + set_model_changed(false); +} + } // namespace sfntly diff --git a/cpp/src/sfntly/table/truetype/loca_table.h b/cpp/src/sfntly/table/truetype/loca_table.h index 0ec13bd..67c5749 100644 --- a/cpp/src/sfntly/table/truetype/loca_table.h +++ b/cpp/src/sfntly/table/truetype/loca_table.h @@ -17,6 +17,7 @@ #ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_LOCA_TABLE_H_ #define SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_LOCA_TABLE_H_ +#include "sfntly/port/java_iterator.h" #include "sfntly/table/table.h" #include "sfntly/table/core/font_header_table.h" @@ -25,17 +26,16 @@ namespace sfntly { // A Loca table - 'loca'. class LocaTable : public Table, public RefCounted<LocaTable> { public: - // Note: different implementation than Java, caller to instantiate this class - // object directly from stack instead of calling LocaTable::iterator(). - class LocaIterator { + class LocaIterator : public PODIterator<int32_t, LocaTable> { public: explicit LocaIterator(LocaTable* table); - bool HasNext(); - int32_t Next(); + virtual ~LocaIterator() {} + + virtual bool HasNext(); + virtual int32_t Next(); private: int32_t index_; - LocaTable* table_; // use dumb pointer since it's a composition object }; class Builder : public Table::Builder, public RefCounted<Builder> { @@ -83,7 +83,8 @@ class LocaTable : public Table, public RefCounted<LocaTable> { // This method sets the number of glyphs that the builder will attempt to // parse location data for from the raw binary data. This method only needs // to be called (and <b>must</b> be) when the raw data for this builder has - // been changed. + // been changed. It does not by itself reset the data or clear any set loca + // list. void SetNumGlyphs(int32_t num_glyphs); // Get the number of glyphs that this builder has support for. @@ -119,11 +120,19 @@ class LocaTable : public Table, public RefCounted<LocaTable> { // @param data the data to initialize from void Initialize(ReadableFontData* data); + // Checks that the glyph id is within the correct range. + // @return glyph_id if correct, -1 otherwise. + int32_t CheckGlyphRange(int32_t glyph_id); + + int32_t LastGlyphIndex(); + // Internal method to get the loca list if already generated and if not to // initialize the state of the builder. // @return the loca list IntegerList* GetLocaList(); + void ClearLoca(bool nullify); + int32_t format_version_; // Note: IndexToLocFormat int32_t num_glyphs_; IntegerList loca_; diff --git a/cpp/src/test/font_parsing_test.cc b/cpp/src/test/font_parsing_test.cc index 60c5524..6fd5c3b 100644 --- a/cpp/src/test/font_parsing_test.cc +++ b/cpp/src/test/font_parsing_test.cc @@ -22,6 +22,7 @@ #include "sfntly/font_factory.h" #include "sfntly/table/core/font_header_table.h" #include "sfntly/table/table.h" +#include "sfntly/table/generic_table_builder.h" #include "sfntly/table/table_based_table_builder.h" #include "sfntly/tag.h" #include "sfntly/port/file_input_stream.h" |