diff options
author | arthurhsu@google.com <arthurhsu@google.com@672e30a5-4c29-85ac-ac6d-611c735e0a51> | 2011-11-28 18:20:03 +0000 |
---|---|---|
committer | arthurhsu@google.com <arthurhsu@google.com@672e30a5-4c29-85ac-ac6d-611c735e0a51> | 2011-11-28 18:20:03 +0000 |
commit | 53847b66af7e0c1af9928e4da2e978ed3b7c2a25 (patch) | |
tree | 831a0fcdfbfdfcd71d869d23f6d7579bcbdcc1d1 | |
parent | 5768f5055c95f4fdd9dad479ac1f56604a29aba2 (diff) | |
download | src-53847b66af7e0c1af9928e4da2e978ed3b7c2a25.tar.gz |
Finish bitmap subsetting support
git-svn-id: http://sfntly.googlecode.com/svn/trunk/cpp/src@107 672e30a5-4c29-85ac-ac6d-611c735e0a51
30 files changed, 694 insertions, 297 deletions
diff --git a/sfntly/data/writable_font_data.h b/sfntly/data/writable_font_data.h index f88a986..d2a049e 100644 --- a/sfntly/data/writable_font_data.h +++ b/sfntly/data/writable_font_data.h @@ -85,16 +85,16 @@ 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
+ // 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
+ // 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); diff --git a/sfntly/table/bitmap/big_glyph_metrics.cc b/sfntly/table/bitmap/big_glyph_metrics.cc index d2519cd..2a30829 100644 --- a/sfntly/table/bitmap/big_glyph_metrics.cc +++ b/sfntly/table/bitmap/big_glyph_metrics.cc @@ -137,6 +137,18 @@ void BigGlyphMetrics::Builder::SetVertAdvance(byte_t advance) { InternalWriteData()->WriteByte(Offset::kVertAdvance, advance); } +// Note: C++ port only +void BigGlyphMetrics::Builder::CopyFrom(BigGlyphMetrics::Builder* source) { + SetHeight(static_cast<byte_t>(source->Height())); + SetWidth(static_cast<byte_t>(source->Width())); + SetHoriBearingX(static_cast<byte_t>(source->HoriBearingX())); + SetHoriBearingY(static_cast<byte_t>(source->HoriBearingY())); + SetHoriAdvance(static_cast<byte_t>(source->HoriAdvance())); + SetVertBearingX(static_cast<byte_t>(source->VertBearingX())); + SetVertBearingY(static_cast<byte_t>(source->VertBearingY())); + SetVertAdvance(static_cast<byte_t>(source->VertAdvance())); +} + CALLER_ATTACH FontDataTable* BigGlyphMetrics::Builder::SubBuildTable(ReadableFontData* data) { BigGlyphMetricsPtr output = new BigGlyphMetrics(data); @@ -159,4 +171,13 @@ int32_t BigGlyphMetrics::Builder::SubSerialize(WritableFontData* new_data) { return Data()->CopyTo(new_data); } +// static +CALLER_ATTACH +BigGlyphMetrics::Builder* BigGlyphMetrics::Builder::CreateBuilder() { + WritableFontDataPtr data; + data.Attach(WritableFontData::CreateWritableFontData(Offset::kMetricsLength)); + BigGlyphMetricsBuilderPtr output = new BigGlyphMetrics::Builder(data); + return output.Detach(); +} + } // namespace sfntly diff --git a/sfntly/table/bitmap/big_glyph_metrics.h b/sfntly/table/bitmap/big_glyph_metrics.h index 55963b4..b62aada 100644 --- a/sfntly/table/bitmap/big_glyph_metrics.h +++ b/sfntly/table/bitmap/big_glyph_metrics.h @@ -46,6 +46,7 @@ class BigGlyphMetrics : public GlyphMetrics, // class to instantiate derived class with protected constructors. explicit Builder(WritableFontData* data); explicit Builder(ReadableFontData* data); + virtual ~Builder(); int32_t Height(); @@ -65,11 +66,17 @@ class BigGlyphMetrics : public GlyphMetrics, int32_t VertAdvance(); void SetVertAdvance(byte_t advance); + // Note: C++ port only + void CopyFrom(Builder* source); + 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 instantiation function. + static CALLER_ATTACH Builder* CreateBuilder(); }; explicit BigGlyphMetrics(ReadableFontData* data); diff --git a/sfntly/table/bitmap/bitmap_size_table.cc b/sfntly/table/bitmap/bitmap_size_table.cc index bde903a..6c7d731 100644 --- a/sfntly/table/bitmap/bitmap_size_table.cc +++ b/sfntly/table/bitmap/bitmap_size_table.cc @@ -16,8 +16,10 @@ #include "sfntly/table/bitmap/bitmap_size_table.h" +#include <stdio.h> #include <stdlib.h> +#include "sfntly/math/font_math.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" @@ -216,10 +218,18 @@ int32_t BitmapSizeTable::Builder::SubDataSizeToSerialize() { e = builders->end(); b != e; b++) { size += EblcTable::Offset::kIndexSubTableEntryLength; int32_t sub_table_size = (*b)->SubDataSizeToSerialize(); + int32_t padding = FontMath::PaddingRequired(abs(sub_table_size), + DataSize::kULONG); +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "subtable size=%d\n", sub_table_size); +#endif variable = (sub_table_size > 0) ? variable : true; - size += abs(sub_table_size); + size += abs(sub_table_size) + padding; } - return size; +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "bitmap table size=%d\n", variable ? -size : size); +#endif + return variable ? -size : size; } bool BitmapSizeTable::Builder::SubReadyToSerialize() { @@ -310,7 +320,7 @@ int32_t BitmapSizeTable::Builder::FlagsAsInt() { EblcTable::Offset::kBitmapSizeTable_flags); } -IndexSubTable::Builder* BitmapSizeTable::Builder::GetIndexSubTable( +IndexSubTable::Builder* BitmapSizeTable::Builder::IndexSubTableBuilder( int32_t index) { IndexSubTableBuilderList* sub_table_list = GetIndexSubTableBuilders(); return sub_table_list->at(index); diff --git a/sfntly/table/bitmap/bitmap_size_table.h b/sfntly/table/bitmap/bitmap_size_table.h index 4f4a961..6733e20 100644 --- a/sfntly/table/bitmap/bitmap_size_table.h +++ b/sfntly/table/bitmap/bitmap_size_table.h @@ -96,8 +96,7 @@ class BitmapSizeTable : public SubTable, int32_t BitDepth(); int32_t FlagsAsInt(); - // Note: renamed from indexSubTable() - IndexSubTable::Builder* GetIndexSubTable(int32_t index); + IndexSubTable::Builder* IndexSubTableBuilder(int32_t index); CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id); int32_t GlyphOffset(int32_t glyph_id); int32_t GlyphLength(int32_t glyph_id); diff --git a/sfntly/table/bitmap/ebdt_table.h b/sfntly/table/bitmap/ebdt_table.h index 79852c3..d138c14 100644 --- a/sfntly/table/bitmap/ebdt_table.h +++ b/sfntly/table/bitmap/ebdt_table.h @@ -26,6 +26,13 @@ namespace sfntly { class EbdtTable : public SubTableContainerTable, public RefCounted<EbdtTable> { public: + struct Offset { + enum { + kVersion = 0, + kHeaderLength = DataSize::kFixed, + }; + }; + class Builder : public SubTableContainerTable::Builder, public RefCounted<Builder> { public: @@ -90,15 +97,7 @@ class EbdtTable : public SubTableContainerTable, CALLER_ATTACH BitmapGlyph* Glyph(int32_t offset, int32_t length, int32_t format); - protected: - struct Offset { - enum { - kVersion = 0, - kHeaderLength = DataSize::kFixed, - }; - }; - EbdtTable(Header* header, ReadableFontData* data); }; typedef Ptr<EbdtTable> EbdtTablePtr; diff --git a/sfntly/table/bitmap/eblc_table.cc b/sfntly/table/bitmap/eblc_table.cc index 6691b04..0ad2764 100644 --- a/sfntly/table/bitmap/eblc_table.cc +++ b/sfntly/table/bitmap/eblc_table.cc @@ -16,6 +16,7 @@ #include "sfntly/table/bitmap/eblc_table.h" +#include <stdio.h> #include <stdlib.h> #include "sfntly/math/font_math.h" @@ -131,7 +132,8 @@ int32_t EblcTable::Builder::SubSerialize(WritableFontData* new_data) { #if defined (SFNTLY_DEBUG_BITMAP) fprintf(stderr, "size %d: sizeTable=%x, current subTable Block=%x, ", - size_index, size_table_offset); + size_index, size_table_offset, + current_sub_table_block_start_offset); fprintf(stderr, "index subTableStart=%x\n", index_sub_table_offset); size_index++; int32_t sub_table_index = 0; @@ -209,16 +211,24 @@ int32_t EblcTable::Builder::SubDataSizeToSerialize() { } int32_t size = Offset::kHeaderLength; bool variable = false; +#if defined (SFNTLY_DEBUG_BITMAP) + size_t size_index = 0; +#endif for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(), e = size_table_builders_.end(); b != e; b++) { int32_t size_builder_size = (*b)->SubDataSizeToSerialize(); +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "sizeIndex = %d, sizeBuilderSize=0x%x (%d)\n", + size_index++, size_builder_size, size_builder_size); +#endif 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; +#if defined (SFNTLY_DEBUG_BITMAP) + fprintf(stderr, "eblc size=%d\n", size); +#endif + return variable ? -size : size; } void EblcTable::Builder::SubDataSet() { diff --git a/sfntly/table/bitmap/eblc_table.h b/sfntly/table/bitmap/eblc_table.h index 3a9b4c4..b04338a 100644 --- a/sfntly/table/bitmap/eblc_table.h +++ b/sfntly/table/bitmap/eblc_table.h @@ -18,6 +18,7 @@ #define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_ #include "sfntly/port/lock.h" +#include "sfntly/table/bitmap/big_glyph_metrics.h" #include "sfntly/table/bitmap/bitmap_glyph.h" #include "sfntly/table/bitmap/bitmap_size_table.h" #include "sfntly/table/subtable_container_table.h" @@ -81,16 +82,21 @@ class EblcTable : public SubTableContainerTable, // indexSubTable1 kIndexSubTable1_offsetArray = kIndexSubHeaderLength, + kIndexSubTable1_builderDataSize = kIndexSubHeaderLength, // kIndexSubTable2 kIndexSubTable2Length = kIndexSubHeaderLength + DataSize::kULONG + BitmapGlyph::Offset::kBigGlyphMetricsLength, kIndexSubTable2_imageSize = kIndexSubHeaderLength, - kIndexSubTable2_bigGlyphMetrics = kIndexSubTable2_imageSize + 4, + kIndexSubTable2_bigGlyphMetrics = kIndexSubTable2_imageSize + + DataSize::kULONG, + kIndexSubTable2_builderDataSize = kIndexSubTable2_bigGlyphMetrics + + BigGlyphMetrics::Offset::kMetricsLength, // kIndexSubTable3 kIndexSubTable3_offsetArray = kIndexSubHeaderLength, + kIndexSubTable3_builderDataSize = kIndexSubTable3_offsetArray, // kIndexSubTable4 kIndexSubTable4_numGlyphs = kIndexSubHeaderLength, @@ -99,15 +105,17 @@ class EblcTable : public SubTableContainerTable, kIndexSubTable4_codeOffsetPairLength = 2 * DataSize::kUSHORT, kIndexSubTable4_codeOffsetPair_glyphCode = 0, kIndexSubTable4_codeOffsetPair_offset = DataSize::kUSHORT, + kIndexSubTable4_builderDataSize = kIndexSubTable4_glyphArray, // kIndexSubTable5 kIndexSubTable5_imageSize = kIndexSubHeaderLength, - kIndexSubTable5_bigMetrics = kIndexSubTable5_imageSize + - DataSize::kULONG, - kIndexSubTable5_numGlyphs = kIndexSubTable5_bigMetrics + + kIndexSubTable5_bigGlyphMetrics = kIndexSubTable5_imageSize + + DataSize::kULONG, + kIndexSubTable5_numGlyphs = kIndexSubTable5_bigGlyphMetrics + BitmapGlyph::Offset::kBigGlyphMetricsLength, kIndexSubTable5_glyphArray = kIndexSubTable5_numGlyphs + DataSize::kULONG, + kIndexSubTable5_builderDataSize = kIndexSubTable5_glyphArray, // codeOffsetPair kCodeOffsetPairLength = 2 * DataSize::kUSHORT, diff --git a/sfntly/table/bitmap/index_sub_table.cc b/sfntly/table/bitmap/index_sub_table.cc index 80c0ffe..d302aed 100644 --- a/sfntly/table/bitmap/index_sub_table.cc +++ b/sfntly/table/bitmap/index_sub_table.cc @@ -121,6 +121,28 @@ int32_t IndexSubTable::Builder::GlyphOffset(int32_t glyph_id) { // static CALLER_ATTACH IndexSubTable::Builder* +IndexSubTable::Builder::CreateBuilder(int32_t index_format) { + switch (index_format) { + case Format::FORMAT_1: + return IndexSubTableFormat1::Builder::CreateBuilder(); + case Format::FORMAT_2: + return IndexSubTableFormat2::Builder::CreateBuilder(); + case Format::FORMAT_3: + return IndexSubTableFormat3::Builder::CreateBuilder(); + case Format::FORMAT_4: + return IndexSubTableFormat4::Builder::CreateBuilder(); + case Format::FORMAT_5: + return IndexSubTableFormat5::Builder::CreateBuilder(); + default: +#if !defined (SFNTLY_NO_EXCEPTION) + throw IllegalArgumentException("Invalid index subtable format"); +#endif + return NULL; + } +} + +// 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 = @@ -171,6 +193,7 @@ FontDataTable* IndexSubTable::Builder::SubBuildTable(ReadableFontData* data) { } void IndexSubTable::Builder::SubDataSet() { + // NOP } int32_t IndexSubTable::Builder::SubDataSizeToSerialize() { @@ -186,6 +209,20 @@ int32_t IndexSubTable::Builder::SubSerialize(WritableFontData* new_data) { return 0; } +IndexSubTable::Builder::Builder(int32_t data_size, int32_t index_format) + : SubTable::Builder(data_size), index_format_(index_format) { +} + +IndexSubTable::Builder::Builder(int32_t index_format, + int32_t image_format, + int32_t image_data_offset, + int32_t data_size) + : SubTable::Builder(data_size), + index_format_(index_format), + image_format_(image_format), + image_data_offset_(image_data_offset) { +} + IndexSubTable::Builder::Builder(WritableFontData* data, int32_t first_glyph_index, int32_t last_glyph_index) @@ -204,14 +241,6 @@ IndexSubTable::Builder::Builder(ReadableFontData* data, 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(), diff --git a/sfntly/table/bitmap/index_sub_table.h b/sfntly/table/bitmap/index_sub_table.h index 0993e76..6d27129 100644 --- a/sfntly/table/bitmap/index_sub_table.h +++ b/sfntly/table/bitmap/index_sub_table.h @@ -27,6 +27,16 @@ namespace sfntly { class IndexSubTable : public SubTable { public: + struct Format { + enum { + FORMAT_1 = 1, + FORMAT_2 = 2, + FORMAT_3 = 3, + FORMAT_4 = 4, + FORMAT_5 = 5, + }; + }; + class Builder : public SubTable::Builder { public: virtual ~Builder(); @@ -71,6 +81,7 @@ class IndexSubTable : public SubTable { GetIterator() = 0; // Static instantiation function. + static CALLER_ATTACH Builder* CreateBuilder(int32_t index_format); static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, int32_t offset_to_index_sub_table_array, @@ -86,15 +97,17 @@ class IndexSubTable : public SubTable { virtual int32_t SubSerialize(WritableFontData* new_data); protected: + Builder(int32_t data_size, int32_t index_format); + Builder(int32_t index_format, + int32_t image_format, + int32_t image_data_offset, + int32_t data_size); 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. diff --git a/sfntly/table/bitmap/index_sub_table_format1.cc b/sfntly/table/bitmap/index_sub_table_format1.cc index 634fbb0..db73723 100644 --- a/sfntly/table/bitmap/index_sub_table_format1.cc +++ b/sfntly/table/bitmap/index_sub_table_format1.cc @@ -103,6 +103,13 @@ CALLER_ATTACH IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* // static CALLER_ATTACH IndexSubTableFormat1::Builder* +IndexSubTableFormat1::Builder::CreateBuilder() { + IndexSubTableFormat1BuilderPtr output = new IndexSubTableFormat1::Builder(); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat1::Builder* IndexSubTableFormat1::Builder::CreateBuilder(ReadableFontData* data, int32_t index_sub_table_offset, int32_t first_glyph_index, @@ -155,7 +162,7 @@ void IndexSubTableFormat1::Builder::SubDataSet() { int32_t IndexSubTableFormat1::Builder::SubDataSizeToSerialize() { if (offset_array_.empty()) { - return 0; + return InternalReadData()->Length(); } return EblcTable::Offset::kIndexSubHeaderLength + offset_array_.size() * DataSize::kULONG; @@ -172,6 +179,9 @@ int32_t IndexSubTableFormat1::Builder::SubSerialize( WritableFontData* new_data) { int32_t size = SerializeIndexSubHeader(new_data); if (!model_changed()) { + if (InternalReadData() == NULL) { + return size; + } ReadableFontDataPtr source; WritableFontDataPtr target; source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( @@ -179,11 +189,11 @@ int32_t IndexSubTableFormat1::Builder::SubSerialize( 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); + } else { + for (IntegerList::iterator b = GetOffsetArray()->begin(), + e = GetOffsetArray()->end(); b != e; b++) { + size += new_data->WriteLong(size, *b); + } } return size; } @@ -204,6 +214,11 @@ void IndexSubTableFormat1::Builder::Revert() { IndexSubTable::Builder::Revert(); } +IndexSubTableFormat1::Builder::Builder() + : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable1_builderDataSize, + IndexSubTable::Format::FORMAT_1) { +} + IndexSubTableFormat1::Builder::Builder(WritableFontData* data, int32_t first_glyph_index, int32_t last_glyph_index) diff --git a/sfntly/table/bitmap/index_sub_table_format1.h b/sfntly/table/bitmap/index_sub_table_format1.h index 1078831..33171c1 100644 --- a/sfntly/table/bitmap/index_sub_table_format1.h +++ b/sfntly/table/bitmap/index_sub_table_format1.h @@ -57,6 +57,7 @@ class IndexSubTableFormat1 : public IndexSubTable, void SetOffsetArray(const IntegerList& offset_array); CALLER_ATTACH BitmapGlyphInfoIter* Iterator(); + static CALLER_ATTACH Builder* CreateBuilder(); static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, int32_t index_sub_table_offset, int32_t first_glyph_index, @@ -70,6 +71,7 @@ class IndexSubTableFormat1 : public IndexSubTable, void Revert(); private: + Builder(); Builder(WritableFontData* data, int32_t first_glyph_index, int32_t last_glyph_index); diff --git a/sfntly/table/bitmap/index_sub_table_format2.cc b/sfntly/table/bitmap/index_sub_table_format2.cc index 58881f4..b3bffda 100644 --- a/sfntly/table/bitmap/index_sub_table_format2.cc +++ b/sfntly/table/bitmap/index_sub_table_format2.cc @@ -25,6 +25,19 @@ namespace sfntly { IndexSubTableFormat2::~IndexSubTableFormat2() { } +int32_t IndexSubTableFormat2::ImageSize() { + return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable2_imageSize); +} + +CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat2::BigMetrics() { + ReadableFontDataPtr slice; + slice.Attach(down_cast<ReadableFontData*>( + data_->Slice(EblcTable::Offset::kIndexSubTable2_bigGlyphMetrics, + BigGlyphMetrics::Offset::kMetricsLength))); + BigGlyphMetricsPtr output = new BigGlyphMetrics(slice); + return output.Detach(); +} + int32_t IndexSubTableFormat2::NumGlyphs() { return last_glyph_index() - first_glyph_index() + 1; } @@ -95,12 +108,21 @@ void IndexSubTableFormat2::Builder::SetImageSize(int32_t image_size) { 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); +BigGlyphMetrics::Builder* IndexSubTableFormat2::Builder::BigMetrics() { + if (metrics_ == NULL) { + WritableFontDataPtr data; + data.Attach(down_cast<WritableFontData*>(InternalWriteData()->Slice( + EblcTable::Offset::kIndexSubTable2_bigGlyphMetrics, + BigGlyphMetrics::Offset::kMetricsLength))); + metrics_ = new BigGlyphMetrics::Builder(data); + } + return metrics_; +} + +// static +CALLER_ATTACH IndexSubTableFormat2::Builder* +IndexSubTableFormat2::Builder::CreateBuilder() { + IndexSubTableFormat2BuilderPtr output = new IndexSubTableFormat2::Builder(); return output.Detach(); } @@ -152,6 +174,7 @@ CALLER_ATTACH FontDataTable* IndexSubTableFormat2::Builder::SubBuildTable( } void IndexSubTableFormat2::Builder::SubDataSet() { + Revert(); } int32_t IndexSubTableFormat2::Builder::SubDataSizeToSerialize() { @@ -165,14 +188,29 @@ bool IndexSubTableFormat2::Builder::SubReadyToSerialize() { 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); + if (metrics_ == NULL) { + 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); + } else { + WritableFontDataPtr slice; + size += new_data->WriteLong(EblcTable::Offset::kIndexSubTable2_imageSize, + ImageSize()); + slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size))); + size += metrics_->SubSerialize(slice); + } return size; } +IndexSubTableFormat2::Builder::Builder() + : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable3_builderDataSize, + IndexSubTable::Format::FORMAT_2) { + metrics_.Attach(BigGlyphMetrics::Builder::CreateBuilder()); +} + IndexSubTableFormat2::Builder::Builder(WritableFontData* data, int32_t first_glyph_index, int32_t last_glyph_index) diff --git a/sfntly/table/bitmap/index_sub_table_format2.h b/sfntly/table/bitmap/index_sub_table_format2.h index 52a9ae0..784e8a3 100644 --- a/sfntly/table/bitmap/index_sub_table_format2.h +++ b/sfntly/table/bitmap/index_sub_table_format2.h @@ -55,8 +55,9 @@ class IndexSubTableFormat2 : public IndexSubTable, int32_t ImageSize(); void SetImageSize(int32_t image_size); - CALLER_ATTACH BigGlyphMetrics* BigMetrics(); + BigGlyphMetrics::Builder* BigMetrics(); + static CALLER_ATTACH Builder* CreateBuilder(); static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, int32_t index_sub_table_offset, int32_t first_glyph_index, @@ -66,6 +67,7 @@ class IndexSubTableFormat2 : public IndexSubTable, int32_t first_glyph_index, int32_t last_glyph_index); private: + Builder(); Builder(WritableFontData* data, int32_t first_glyph_index, int32_t last_glyph_index); @@ -77,10 +79,15 @@ class IndexSubTableFormat2 : public IndexSubTable, int32_t index_sub_table_offset, int32_t first_glyph_index, int32_t last_glyph_index); + + BigGlyphMetricsBuilderPtr metrics_; }; virtual ~IndexSubTableFormat2(); + int32_t ImageSize(); + CALLER_ATTACH BigGlyphMetrics* BigMetrics(); + virtual int32_t NumGlyphs(); virtual int32_t GlyphStartOffset(int32_t glyph_id); virtual int32_t GlyphLength(int32_t glyph_id); diff --git a/sfntly/table/bitmap/index_sub_table_format3.cc b/sfntly/table/bitmap/index_sub_table_format3.cc index eedc500..b3e418f 100644 --- a/sfntly/table/bitmap/index_sub_table_format3.cc +++ b/sfntly/table/bitmap/index_sub_table_format3.cc @@ -116,6 +116,13 @@ void IndexSubTableFormat3::Builder::SetOffsetArray( // static CALLER_ATTACH IndexSubTableFormat3::Builder* +IndexSubTableFormat3::Builder::CreateBuilder() { + IndexSubTableFormat3BuilderPtr output = new IndexSubTableFormat3::Builder(); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat3::Builder* IndexSubTableFormat3::Builder::CreateBuilder(ReadableFontData* data, int32_t index_sub_table_offset, int32_t first_glyph_index, @@ -167,7 +174,7 @@ void IndexSubTableFormat3::Builder::SubDataSet() { int32_t IndexSubTableFormat3::Builder::SubDataSizeToSerialize() { if (offset_array_.empty()) { - return 0; + return InternalReadData()->Length(); } return EblcTable::Offset::kIndexSubHeaderLength + offset_array_.size() * DataSize::kULONG; @@ -184,6 +191,9 @@ int32_t IndexSubTableFormat3::Builder::SubSerialize( WritableFontData* new_data) { int32_t size = SerializeIndexSubHeader(new_data); if (!model_changed()) { + if (InternalReadData() == NULL) { + return size; + } ReadableFontDataPtr source; WritableFontDataPtr target; source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( @@ -191,15 +201,20 @@ int32_t IndexSubTableFormat3::Builder::SubSerialize( 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); + } else { + for (IntegerList::iterator b = GetOffsetArray()->begin(), + e = GetOffsetArray()->end(); b != e; b++) { + size += new_data->WriteUShort(size, *b); + } } return size; } +IndexSubTableFormat3::Builder::Builder() + : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable3_builderDataSize, + IndexSubTable::Format::FORMAT_3) { +} + IndexSubTableFormat3::Builder::Builder(WritableFontData* data, int32_t first_glyph_index, int32_t last_glyph_index) diff --git a/sfntly/table/bitmap/index_sub_table_format3.h b/sfntly/table/bitmap/index_sub_table_format3.h index e9f1fa2..d71f857 100644 --- a/sfntly/table/bitmap/index_sub_table_format3.h +++ b/sfntly/table/bitmap/index_sub_table_format3.h @@ -54,6 +54,7 @@ class IndexSubTableFormat3 : public IndexSubTable, void SetOffsetArray(const IntegerList& offset_array); + static CALLER_ATTACH Builder* CreateBuilder(); static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, int32_t index_sub_table_offset, int32_t first_glyph_index, @@ -67,6 +68,7 @@ class IndexSubTableFormat3 : public IndexSubTable, void Revert(); private: + Builder(); Builder(WritableFontData* data, int32_t first_glyph_index, int32_t last_glyph_index); diff --git a/sfntly/table/bitmap/index_sub_table_format4.cc b/sfntly/table/bitmap/index_sub_table_format4.cc index 898e288..23f3e47 100644 --- a/sfntly/table/bitmap/index_sub_table_format4.cc +++ b/sfntly/table/bitmap/index_sub_table_format4.cc @@ -150,6 +150,13 @@ CALLER_ATTACH IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* // static CALLER_ATTACH IndexSubTableFormat4::Builder* +IndexSubTableFormat4::Builder::CreateBuilder() { + IndexSubTableFormat4BuilderPtr output = new IndexSubTableFormat4::Builder(); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat4::Builder* IndexSubTableFormat4::Builder::CreateBuilder(ReadableFontData* data, int32_t index_sub_table_offset, int32_t first_glyph_index, @@ -201,11 +208,11 @@ void IndexSubTableFormat4::Builder::SubDataSet() { int32_t IndexSubTableFormat4::Builder::SubDataSizeToSerialize() { if (offset_pair_array_.empty()) { - return 0; + return InternalReadData()->Length(); } return EblcTable::Offset::kIndexSubHeaderLength + DataSize::kULONG + GetOffsetArray()->size() * - EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset; + EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength; } bool IndexSubTableFormat4::Builder::SubReadyToSerialize() { @@ -219,6 +226,9 @@ int32_t IndexSubTableFormat4::Builder::SubSerialize( WritableFontData* new_data) { int32_t size = SerializeIndexSubHeader(new_data); if (!model_changed()) { + if (InternalReadData() == NULL) { + return size; + } ReadableFontDataPtr source; WritableFontDataPtr target; source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( @@ -226,15 +236,14 @@ int32_t IndexSubTableFormat4::Builder::SubSerialize( 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()); + } else { + 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; } @@ -251,6 +260,11 @@ void IndexSubTableFormat4::Builder::SetOffsetArray( set_model_changed(); } +IndexSubTableFormat4::Builder::Builder() + : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable4_builderDataSize, + Format::FORMAT_4) { +} + IndexSubTableFormat4::Builder::Builder(WritableFontData* data, int32_t first_glyph_index, int32_t last_glyph_index) @@ -282,6 +296,7 @@ void IndexSubTableFormat4::Builder::Initialize(ReadableFontData* data) { EblcTable::Offset::kIndexSubTable4_codeOffsetPair_glyphCode); int32_t glyph_offset = data->ReadUShort(offset + EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset); + offset += EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength; CodeOffsetPairBuilder pair_builder(glyph_code, glyph_offset); offset_pair_array_.push_back(pair_builder); } diff --git a/sfntly/table/bitmap/index_sub_table_format4.h b/sfntly/table/bitmap/index_sub_table_format4.h index be96628..efd540f 100644 --- a/sfntly/table/bitmap/index_sub_table_format4.h +++ b/sfntly/table/bitmap/index_sub_table_format4.h @@ -37,16 +37,12 @@ class IndexSubTableFormat4 : public IndexSubTable, int32_t offset_; }; - class Builder; class CodeOffsetPairBuilder : public CodeOffsetPair { public: CodeOffsetPairBuilder(); CodeOffsetPairBuilder(int32_t glyph_code, int32_t offset); void set_glyph_code(int32_t v) { glyph_code_ = v; } void set_offset(int32_t v) { offset_ = v; } - - private: - friend class Builder; }; class CodeOffsetPairGlyphCodeComparator { @@ -85,6 +81,7 @@ class IndexSubTableFormat4 : public IndexSubTable, void Revert(); void SetOffsetArray(const std::vector<CodeOffsetPairBuilder>& pair_array); + static CALLER_ATTACH Builder* CreateBuilder(); static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, int32_t index_sub_table_offset, int32_t first_glyph_index, @@ -94,6 +91,7 @@ class IndexSubTableFormat4 : public IndexSubTable, int32_t first_glyph_index, int32_t last_glyph_index); private: + Builder(); Builder(WritableFontData* data, int32_t first_glyph_index, int32_t last_glyph_index); diff --git a/sfntly/table/bitmap/index_sub_table_format5.cc b/sfntly/table/bitmap/index_sub_table_format5.cc index 1ddce05..b4ab1b8 100644 --- a/sfntly/table/bitmap/index_sub_table_format5.cc +++ b/sfntly/table/bitmap/index_sub_table_format5.cc @@ -62,7 +62,7 @@ int32_t IndexSubTableFormat5::ImageSize() { CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat5::BigMetrics() { ReadableFontDataPtr data; data.Attach(down_cast<ReadableFontData*>(data_->Slice( - EblcTable::Offset::kIndexSubTable5_bigMetrics, + EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics, BigGlyphMetrics::Offset::kMetricsLength))); BigGlyphMetricsPtr output = new BigGlyphMetrics(data); return output.Detach(); @@ -123,6 +123,13 @@ CALLER_ATTACH IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* // static CALLER_ATTACH IndexSubTableFormat5::Builder* +IndexSubTableFormat5::Builder::CreateBuilder() { + IndexSubTableFormat5BuilderPtr output = new IndexSubTableFormat5::Builder(); + return output.Detach(); +} + +// static +CALLER_ATTACH IndexSubTableFormat5::Builder* IndexSubTableFormat5::Builder::CreateBuilder(ReadableFontData* data, int32_t index_sub_table_offset, int32_t first_glyph_index, @@ -169,16 +176,14 @@ CALLER_ATTACH FontDataTable* IndexSubTableFormat5::Builder::SubBuildTable( } void IndexSubTableFormat5::Builder::SubDataSet() { - if (model_changed()) { - Initialize(InternalReadData()); - } + Revert(); } int32_t IndexSubTableFormat5::Builder::SubDataSizeToSerialize() { if (glyph_array_.empty()) { - return 0; + return InternalReadData()->Length(); } - return EblcTable::Offset::kIndexSubHeaderLength + + return EblcTable::Offset::kIndexSubTable5_builderDataSize + glyph_array_.size() * DataSize::kUSHORT; } @@ -200,23 +205,17 @@ int32_t IndexSubTableFormat5::Builder::SubSerialize( 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); + size += new_data->WriteULong(EblcTable::Offset::kIndexSubTable5_imageSize, + ImageSize()); + WritableFontDataPtr slice; + slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size))); + size += BigMetrics()->SubSerialize(slice); + size += new_data->WriteULong(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; } @@ -231,14 +230,16 @@ void IndexSubTableFormat5::Builder::SetImageSize(int32_t image_size) { 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(); + if (metrics_ == NULL) { + WritableFontDataPtr data; + data.Attach(down_cast<WritableFontData*>(InternalWriteData()->Slice( + EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics, + BigGlyphMetrics::Offset::kMetricsLength))); + metrics_ = new BigGlyphMetrics::Builder(data); + set_model_changed(); + } + return metrics_; } IntegerList* IndexSubTableFormat5::Builder::GlyphArray() { @@ -256,6 +257,11 @@ void IndexSubTableFormat5::Builder::Revert() { IndexSubTable::Builder::Revert(); } +IndexSubTableFormat5::Builder::Builder() + : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable5_builderDataSize, + IndexSubTable::Format::FORMAT_5) { +} + IndexSubTableFormat5::Builder::Builder(WritableFontData* data, int32_t first_glyph_index, int32_t last_glyph_index) diff --git a/sfntly/table/bitmap/index_sub_table_format5.h b/sfntly/table/bitmap/index_sub_table_format5.h index 511f1fc..a39e88c 100644 --- a/sfntly/table/bitmap/index_sub_table_format5.h +++ b/sfntly/table/bitmap/index_sub_table_format5.h @@ -54,10 +54,11 @@ class IndexSubTableFormat5 : public IndexSubTable, int32_t ImageSize(); void SetImageSize(int32_t image_size); - CALLER_ATTACH BigGlyphMetrics::Builder* BigMetrics(); + BigGlyphMetrics::Builder* BigMetrics(); IntegerList* GlyphArray(); void SetGlyphArray(const IntegerList& v); + static CALLER_ATTACH Builder* CreateBuilder(); static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data, int32_t index_sub_table_offset, int32_t first_glyph_index, @@ -70,6 +71,7 @@ class IndexSubTableFormat5 : public IndexSubTable, void Revert(); private: + Builder(); Builder(WritableFontData* data, int32_t first_glyph_index, int32_t last_glyph_index); @@ -86,6 +88,7 @@ class IndexSubTableFormat5 : public IndexSubTable, int32_t last_glyph_index); IntegerList glyph_array_; + BigGlyphMetricsBuilderPtr metrics_; }; virtual ~IndexSubTableFormat5(); diff --git a/sfntly/table/font_data_table.cc b/sfntly/table/font_data_table.cc index 7953269..0e27f7a 100644 --- a/sfntly/table/font_data_table.cc +++ b/sfntly/table/font_data_table.cc @@ -141,6 +141,13 @@ FontDataTable::Builder::Builder() data_changed_(false) { } +FontDataTable::Builder::Builder(int32_t data_size) + : model_changed_(false), + contained_model_changed_(false), + data_changed_(false) { + w_data_.Attach(WritableFontData::CreateWritableFontData(data_size)); +} + FontDataTable::Builder::Builder(WritableFontData* data) : model_changed_(false), contained_model_changed_(false), diff --git a/sfntly/table/font_data_table.h b/sfntly/table/font_data_table.h index ce5433b..5e437e2 100644 --- a/sfntly/table/font_data_table.h +++ b/sfntly/table/font_data_table.h @@ -64,6 +64,14 @@ class FontDataTable : virtual public RefCount { protected: explicit Builder(); + + // Construct a FontDataTable.Builder with a WritableFontData backing store + // of size given. A positive size will create a fixed size backing store and + // a 0 or less size is an estimate for a growable backing store with the + // estimate being the absolute of the size. + // @param dataSize if positive then a fixed size; if 0 or less then an + // estimate for a growable size + Builder(int32_t data_size); Builder(WritableFontData* data); Builder(ReadableFontData* data); virtual ~Builder(); diff --git a/sfntly/table/subtable.cc b/sfntly/table/subtable.cc index b990c7c..e5b906f 100644 --- a/sfntly/table/subtable.cc +++ b/sfntly/table/subtable.cc @@ -34,10 +34,11 @@ SubTable::SubTable(ReadableFontData* data) /****************************************************************************** * SubTable::Builder class ******************************************************************************/ -SubTable::Builder::Builder() { +SubTable::Builder::~Builder() { } -SubTable::Builder::~Builder() { +SubTable::Builder::Builder(int32_t data_size) + : FontDataTable::Builder(data_size) { } SubTable::Builder::Builder(WritableFontData* data, diff --git a/sfntly/table/subtable.h b/sfntly/table/subtable.h index 902d281..fa6f4c6 100644 --- a/sfntly/table/subtable.h +++ b/sfntly/table/subtable.h @@ -29,13 +29,12 @@ class SubTable : public FontDataTable { public: class Builder : public FontDataTable::Builder { public: - // Creates a new empty sub-table. - Builder(); virtual ~Builder(); protected: // @param data the data for the subtable being built // @param master_data the data for the full table + Builder(int32_t data_size); Builder(WritableFontData* data, ReadableFontData* master_data); Builder(ReadableFontData* data, ReadableFontData* master_data); explicit Builder(WritableFontData* data); diff --git a/test/bitmap_table_test.cc b/test/bitmap_table_test.cc index d5d718d..df3ffc0 100644 --- a/test/bitmap_table_test.cc +++ b/test/bitmap_table_test.cc @@ -16,9 +16,13 @@ #include "gtest/gtest.h" #include "sfntly/font.h" +#include "sfntly/port/file_input_stream.h" +#include "sfntly/port/memory_input_stream.h" +#include "sfntly/port/memory_output_stream.h" #include "sfntly/table/bitmap/ebdt_table.h" #include "sfntly/table/bitmap/eblc_table.h" #include "sfntly/table/bitmap/index_sub_table_format3.h" +#include "sfntly/table/bitmap/index_sub_table_format4.h" #include "test/test_data.h" #include "test/test_font_utils.h" @@ -45,12 +49,8 @@ const int32_t STRIKE4_SUB1_GLYPH_OFFSET[] = { const int32_t NUM_STRIKE4_SUB1_GLYPH_OFFSET = 10; const int32_t STRIKE4_SUB1_GLYPH2_LENGTH = 0x58a2 - 0x589d; -bool TestReadingBitmapTable() { - FontFactoryPtr factory; - factory.Attach(FontFactory::GetInstance()); - FontArray font_array; - LoadFont(SAMPLE_BITMAP_FONT, factory, &font_array); - FontPtr font = font_array[0]; +bool CommonReadingTest(Font* raw_font) { + FontPtr font = raw_font; EblcTablePtr bitmap_loca = down_cast<EblcTable*>(font->GetTable(Tag::EBLC)); EbdtTablePtr bitmap_table = down_cast<EbdtTable*>(font->GetTable(Tag::EBDT)); @@ -64,7 +64,6 @@ bool TestReadingBitmapTable() { BitmapSizeTablePtr strike1 = bitmap_loca->GetBitmapSizeTable(0); EXPECT_FALSE(strike1 == NULL); EXPECT_EQ(strike1->IndexSubTableArrayOffset(), STRIKE1_ARRAY_OFFSET); - EXPECT_EQ(strike1->IndexTableSize(), STRIKE1_INDEX_TABLE_SIZE); EXPECT_EQ(strike1->NumberOfIndexSubTables(), STRIKE1_NUM_INDEX_TABLES); EXPECT_EQ(strike1->ColorRef(), STRIKE1_COLOR_REF); EXPECT_EQ(strike1->StartGlyphIndex(), STRIKE1_START_GLYPH_INDEX); @@ -82,7 +81,6 @@ bool TestReadingBitmapTable() { EXPECT_EQ(strike4->EndGlyphIndex(), STRIKE1_END_GLYPH_INDEX); IndexSubTablePtr sub1 = strike4->GetIndexSubTable(0); EXPECT_FALSE(sub1 == NULL); - EXPECT_EQ(sub1->index_format(), STRIKE4_SUB1_INDEX_FORMAT); EXPECT_EQ(sub1->image_format(), STRIKE4_SUB1_IMAGE_FORMAT); EXPECT_EQ(sub1->first_glyph_index(), STRIKE1_START_GLYPH_INDEX); EXPECT_EQ(sub1->last_glyph_index(), STRIKE1_END_GLYPH_INDEX); @@ -91,6 +89,24 @@ bool TestReadingBitmapTable() { for (int32_t i = 0; i < NUM_STRIKE4_SUB1_GLYPH_OFFSET; ++i) { EXPECT_EQ(sub1->GlyphOffset(i), STRIKE4_SUB1_GLYPH_OFFSET[i]); } + return true; +} + +bool TestReadingBitmapTable() { + FontFactoryPtr factory; + factory.Attach(FontFactory::GetInstance()); + FontArray font_array; + LoadFont(SAMPLE_BITMAP_FONT, factory, &font_array); + FontPtr font = font_array[0]; + EXPECT_TRUE(CommonReadingTest(font)); + + EblcTablePtr bitmap_loca = down_cast<EblcTable*>(font->GetTable(Tag::EBLC)); + BitmapSizeTablePtr strike1 = bitmap_loca->GetBitmapSizeTable(0); + BitmapSizeTablePtr strike4 = bitmap_loca->GetBitmapSizeTable(3); + IndexSubTablePtr sub1 = strike4->GetIndexSubTable(0); + + EXPECT_EQ(strike1->IndexTableSize(), STRIKE1_INDEX_TABLE_SIZE); + EXPECT_EQ(sub1->index_format(), STRIKE4_SUB1_INDEX_FORMAT); // Strike 4 Index Sub Table 1 is a Format 3 IndexSubTableFormat3Ptr sub3 = @@ -108,8 +124,86 @@ bool TestReadingBitmapTable() { return true; } +// Function in subset_impl.cc +extern +void SubsetEBLC(EblcTable::Builder* eblc, const BitmapLocaList& new_loca); + +bool TestIndexFormatConversion() { + FontFactoryPtr factory; + factory.Attach(FontFactory::GetInstance()); + FontBuilderArray builder_array; + BuilderForFontFile(SAMPLE_BITMAP_FONT, factory, &builder_array); + + FontBuilderPtr font_builder; + font_builder = builder_array[0]; + EblcTableBuilderPtr eblc_builder = + down_cast<EblcTable::Builder*>(font_builder->GetTableBuilder(Tag::EBLC)); + BitmapLocaList new_loca; + eblc_builder->GenerateLocaList(&new_loca); + SubsetEBLC(eblc_builder, new_loca); // Format 3 -> 4 + + FontPtr new_font; + new_font.Attach(font_builder->Build()); + + // Serialize and reload the serialized font. + MemoryOutputStream os; + factory->SerializeFont(new_font, &os); + +#if defined (SFNTLY_DEBUG_BITMAP) + SerializeToFile(&os, "anon-mod.ttf"); +#endif + + MemoryInputStream is; + is.Attach(os.Get(), os.Size()); + FontArray font_array; + factory->LoadFonts(&is, &font_array); + new_font = font_array[0]; + + EXPECT_TRUE(CommonReadingTest(new_font)); + + // Strike 4 Index Sub Table 1 is a Format 4 + EblcTablePtr bitmap_loca = + down_cast<EblcTable*>(new_font->GetTable(Tag::EBLC)); + BitmapSizeTablePtr strike4 = bitmap_loca->GetBitmapSizeTable(3); + IndexSubTableFormat4Ptr sub4 = + down_cast<IndexSubTableFormat4*>(strike4->GetIndexSubTable(0)); + EXPECT_FALSE(sub4 == NULL); + + // And this subtable shall have exactly the same offset as original table + // since no subsetting happens. + FontArray original_font_array; + LoadFont(SAMPLE_BITMAP_FONT, factory, &original_font_array); + FontPtr font = original_font_array[0]; + EXPECT_FALSE(font == NULL); + EblcTablePtr original_loca = down_cast<EblcTable*>(font->GetTable(Tag::EBLC)); + EXPECT_FALSE(original_loca == NULL); + BitmapSizeTablePtr original_strike4 = bitmap_loca->GetBitmapSizeTable(3); + EXPECT_FALSE(original_strike4 == NULL); + IndexSubTableFormat3Ptr sub3 = + down_cast<IndexSubTableFormat3*>(strike4->GetIndexSubTable(0)); + EXPECT_FALSE(sub3 == NULL); + EXPECT_EQ(strike4->StartGlyphIndex(), original_strike4->StartGlyphIndex()); + EXPECT_EQ(strike4->EndGlyphIndex(), original_strike4->EndGlyphIndex()); + for (int32_t i = strike4->StartGlyphIndex(); + i <= strike4->EndGlyphIndex(); ++i) { + BitmapGlyphInfoPtr info, original_info; + info.Attach(sub4->GlyphInfo(i)); + original_info.Attach(sub3->GlyphInfo(i)); + EXPECT_EQ(info->format(), original_info->format()); + EXPECT_EQ(info->glyph_id(), original_info->glyph_id()); + EXPECT_EQ(info->length(), original_info->length()); + EXPECT_EQ(info->offset(), original_info->offset()); + } + + return true; +} + } // namespace sfntly -TEST(BitmapTable, All) { +TEST(BitmapTable, Reading) { ASSERT_TRUE(sfntly::TestReadingBitmapTable()); } + +TEST(BitmapTable, IndexFormatConversion) { + ASSERT_TRUE(sfntly::TestIndexFormatConversion()); +} diff --git a/test/serialization_test.cc b/test/serialization_test.cc index 3df6d95..0f2f489 100755 --- a/test/serialization_test.cc +++ b/test/serialization_test.cc @@ -91,8 +91,61 @@ bool TestSerialization() { return true; } +bool TestSerializationBitmap() { + FontFactoryPtr factory1, factory2, factory3; + factory1.Attach(FontFactory::GetInstance()); + FontArray font_array; + LoadFont(SAMPLE_BITMAP_FONT, factory1, &font_array); + FontPtr original = font_array[0]; + + factory2.Attach(FontFactory::GetInstance()); + FontBuilderArray font_builder_array; + BuilderForFontFile(SAMPLE_BITMAP_FONT, factory2, &font_builder_array); + FontBuilderPtr font_builder = font_builder_array[0]; + + FontPtr intermediate; + intermediate.Attach(font_builder->Build()); + MemoryOutputStream os; + factory2->SerializeFont(intermediate, &os); + + factory3.Attach(FontFactory::GetInstance()); + FontArray new_font_array; + MemoryInputStream is; + is.Attach(os.Get(), os.Size()); + factory3->LoadFonts(&is, &new_font_array); + FontPtr serialized = new_font_array[0]; + + // Check number of tables + EXPECT_EQ(original->num_tables(), serialized->num_tables()); + + // Check if same set of tables + const TableMap* original_tables = original->GetTableMap(); + const TableMap* serialized_tables = serialized->GetTableMap(); + EXPECT_EQ(original_tables->size(), serialized_tables->size()); + TableMap::const_iterator not_found = serialized_tables->end(); + for (TableMap::const_iterator b = original_tables->begin(), + e = original_tables->end(); b != e; ++b) { + EXPECT_TRUE((serialized_tables->find(b->first) != not_found)); + } + + // Check checksum equivalence + for (size_t i = 0; i < SAMPLE_BITMAP_KNOWN_TAGS; ++i) { + TablePtr original_table = original->GetTable(BITMAP_KNOWN_TAGS[i]); + TablePtr serialized_table = serialized->GetTable(BITMAP_KNOWN_TAGS[i]); + EXPECT_EQ(original_table->CalculatedChecksum(), + serialized_table->CalculatedChecksum()); + EXPECT_EQ(original_table->DataLength(), serialized_table->DataLength()); + } + + return true; +} + } // namespace sfntly -TEST(Serialization, All) { +TEST(Serialization, Simple) { ASSERT_TRUE(sfntly::TestSerialization()); } + +TEST(Serialization, Bitmap) { + ASSERT_TRUE(sfntly::TestSerializationBitmap()); +} diff --git a/test/subsetter_impl.cc b/test/subsetter_impl.cc index 292e83f..f36fcd2 100644 --- a/test/subsetter_impl.cc +++ b/test/subsetter_impl.cc @@ -39,6 +39,14 @@ #include "sfntly/port/memory_input_stream.h" #include "sfntly/port/memory_output_stream.h" + +namespace { + +// The bitmap tables must be greater than 16KB to trigger bitmap subsetter. +static const int BITMAP_SIZE_THRESHOLD = 16384; + +} + namespace sfntly { void ConstructName(UChar* name_part, UnicodeString* name, int32_t name_id) { @@ -278,10 +286,16 @@ bool SetupGlyfBuilders(Font::Builder* builder, return true; } -bool HasOverlap(int32_t range1_begin, int32_t range1_end, - int32_t range2_begin, int32_t range2_end) { - return (range2_begin < range1_end && range2_begin > range1_begin) || - (range1_begin < range2_end && range1_begin > range2_begin); +bool HasOverlap(int32_t range_begin, int32_t range_end, + const IntegerSet& glyph_ids) { + if (range_begin == range_end) { + return glyph_ids.find(range_begin) != glyph_ids.end(); + } else if (range_end > range_begin) { + IntegerSet::const_iterator left = glyph_ids.lower_bound(range_begin); + IntegerSet::const_iterator right = glyph_ids.lower_bound(range_end); + return right != left; + } + return false; } // Initialize builder, returns false if glyph_id subset is not covered. @@ -296,13 +310,12 @@ bool ShallSubset(EbdtTable::Builder* ebdt, EblcTable::Builder* eblc, // Note: Do not call eblc_builder->GenerateLocaList(&loca_list) and then // ebdt_builder->SetLoca(loca_list). For fonts like SimSun, there are // >28K glyphs inside, where a typical usage will be <1K glyphs. Doing - // the calls inproperly will result in creation of >100K objects that - // will be destroyed immediately and result in significant slowness. + // the calls improperly will result in creation of >100K objects that + // will be destroyed immediately, inducing significant slowness. IntegerList removed_strikes; for (size_t i = 0; i < strikes->size(); i++) { if (!HasOverlap((*strikes)[i]->StartGlyphIndex(), - (*strikes)[i]->EndGlyphIndex(), - *(glyph_ids.begin()), *(glyph_ids.rbegin()))) { + (*strikes)[i]->EndGlyphIndex(), glyph_ids)) { removed_strikes.push_back(i); continue; } @@ -310,22 +323,27 @@ bool ShallSubset(EbdtTable::Builder* ebdt, EblcTable::Builder* eblc, IndexSubTableBuilderList* index_builders = (*strikes)[i]->IndexSubTableBuilders(); IntegerList removed_indexes; + BitmapGlyphInfoMap info_map; for (size_t j = 0; j < index_builders->size(); ++j) { - BitmapGlyphInfoMap info_map; + if (!HasOverlap((*index_builders)[j]->first_glyph_index(), + (*index_builders)[j]->last_glyph_index(), glyph_ids)) { + removed_indexes.push_back(j); + continue; + } for (IntegerSet::const_iterator gid = glyph_ids.begin(), gid_end = glyph_ids.end(); gid != gid_end; gid++) { BitmapGlyphInfoPtr info; info.Attach((*index_builders)[j]->GlyphInfo(*gid)); - if (info) { + if (info && info->length()) { // Do not include gid without bitmap info_map[*gid] = info; } } - if (!info_map.empty()) { - loca_list.push_back(info_map); - } else { - removed_indexes.push_back(j); - } + } + if (!info_map.empty()) { + loca_list.push_back(info_map); + } else { + removed_strikes.push_back(i); // Detected null entries. } // Remove unused index sub tables @@ -342,7 +360,11 @@ bool ShallSubset(EbdtTable::Builder* ebdt, EblcTable::Builder* eblc, // Remove unused strikes for (IntegerList::reverse_iterator j = removed_strikes.rbegin(), e = removed_strikes.rend(); j != e; j++) { - strikes->erase(strikes->begin() + *j); + strikes->erase(strikes->begin() + *j); + } + + if (strikes->empty()) { // no glyph covered, can safely drop the builders. + return false; } ebdt_builder->SetLoca(&loca_list); @@ -350,134 +372,134 @@ bool ShallSubset(EbdtTable::Builder* ebdt, EblcTable::Builder* eblc, return true; } -/****************************************************************************** - * EXPERIMENTAL CODE STARTS - * - * The following code is used for experiment. Will obsolete once we have - * support to create format 4 and 5 index sub tables from scratch. - *****************************************************************************/ -void GenerateOffsetArray(int32_t first_gid, int32_t last_gid, - const BitmapGlyphInfoMap& loca, - IntegerList* new_offsets) { - int32_t offset = 0; - int32_t length = 0; - for (int32_t i = first_gid; i <= last_gid; ++i) { - BitmapGlyphInfoMap::const_iterator it = loca.find(i); - if (it != loca.end()) { - offset = it->second->offset(); - length = it->second->length(); - new_offsets->push_back(offset); - if (i == last_gid) { - new_offsets->push_back(offset + length); - } - } else { // Glyph id is not in subset. - offset += length; - new_offsets->push_back(offset); - length = 0; +CALLER_ATTACH IndexSubTable::Builder* +ConstructIndexFormat4(IndexSubTable::Builder* b, const BitmapGlyphInfoMap& loca, + int32_t* image_data_offset) { + IndexSubTableFormat4BuilderPtr builder4; + builder4.Attach(IndexSubTableFormat4::Builder::CreateBuilder()); + CodeOffsetPairBuilderList offset_pairs; + + size_t offset = 0; + int32_t lower_bound = b->first_glyph_index(); + int32_t upper_bound = b->last_glyph_index(); + bool lower_bound_reached = false; + bool upper_bound_reached = false; + int32_t last_gid = -1; + BitmapGlyphInfoMap::const_iterator last_element = loca.end(); + --last_element; + for (BitmapGlyphInfoMap::const_iterator i = loca.begin(), e = loca.end(); + i != e; i++) { + int32_t gid = i->first; + if (gid < lower_bound) { + continue; + } + if (!lower_bound_reached) { + builder4->set_first_glyph_index(gid); + builder4->set_image_format(b->image_format()); + builder4->set_image_data_offset(*image_data_offset); + last_gid = gid; + lower_bound_reached = true; + } + if (gid > upper_bound || i == last_element) { + upper_bound_reached = true; + } + if (!upper_bound_reached || i == last_element) { + offset_pairs.push_back( + IndexSubTableFormat4::CodeOffsetPairBuilder(gid, offset)); + offset += i->second->length(); + last_gid = gid; + } + if (upper_bound_reached) { + offset_pairs.push_back( + IndexSubTableFormat4::CodeOffsetPairBuilder(-1, offset)); + builder4->set_last_glyph_index(last_gid); + *image_data_offset += offset; + break; } } -} - -void SubsetIndexSubTableFormat1(IndexSubTable::Builder* b, - const BitmapGlyphInfoMap& loca) { - IndexSubTableFormat1BuilderPtr builder = - down_cast<IndexSubTableFormat1::Builder*>(b); - if (builder->first_glyph_index() < loca.begin()->first) { - builder->set_first_glyph_index(loca.begin()->first); - } - if (builder->last_glyph_index() > loca.rbegin()->first) { - builder->set_last_glyph_index(loca.rbegin()->first); - } - builder->set_image_data_offset(loca.begin()->second->block_offset()); - - IntegerList new_offsets; - GenerateOffsetArray(builder->first_glyph_index(), builder->last_glyph_index(), - loca, &new_offsets); - builder->SetOffsetArray(new_offsets); -} - -void SubsetIndexSubTableFormat2(IndexSubTable::Builder* b, - const BitmapGlyphInfoMap& loca) { - UNREFERENCED_PARAMETER(b); - UNREFERENCED_PARAMETER(loca); -} - -void SubsetIndexSubTableFormat3(IndexSubTable::Builder* b, - const BitmapGlyphInfoMap& loca) { - IndexSubTableFormat3BuilderPtr builder = - down_cast<IndexSubTableFormat3::Builder*>(b); - if (builder->first_glyph_index() < loca.begin()->first) { - builder->set_first_glyph_index(loca.begin()->first); - } - if (builder->last_glyph_index() > loca.rbegin()->first) { - builder->set_last_glyph_index(loca.rbegin()->first); - } - builder->set_image_data_offset(loca.begin()->second->block_offset()); + builder4->SetOffsetArray(offset_pairs); - IntegerList new_offsets; - GenerateOffsetArray(builder->first_glyph_index(), builder->last_glyph_index(), - loca, &new_offsets); - builder->SetOffsetArray(new_offsets); + return builder4.Detach(); } -void SubsetIndexSubTableFormat4(IndexSubTable::Builder* b, - const BitmapGlyphInfoMap& loca) { - IndexSubTableFormat4BuilderPtr builder = - down_cast<IndexSubTableFormat4::Builder*>(b); - CodeOffsetPairBuilderList pairs; - pairs.resize(loca.size()); - size_t index = 0; +CALLER_ATTACH IndexSubTable::Builder* +ConstructIndexFormat5(IndexSubTable::Builder* b, const BitmapGlyphInfoMap& loca, + int32_t* image_data_offset) { + IndexSubTableFormat5BuilderPtr new_builder; + new_builder.Attach(IndexSubTableFormat5::Builder::CreateBuilder()); + + // Copy BigMetrics + int32_t image_size = 0; + if (b->index_format() == IndexSubTable::Format::FORMAT_2) { + IndexSubTableFormat2BuilderPtr builder2 = + down_cast<IndexSubTableFormat2::Builder*>(b); + new_builder->BigMetrics()->CopyFrom(builder2->BigMetrics()); + image_size = builder2->ImageSize(); + } else { + IndexSubTableFormat5BuilderPtr builder5 = + down_cast<IndexSubTableFormat5::Builder*>(b); + BigGlyphMetricsBuilderPtr metrics_builder; + new_builder->BigMetrics()->CopyFrom(builder5->BigMetrics()); + image_size = builder5->ImageSize(); + } + + IntegerList* glyph_array = new_builder->GlyphArray(); + size_t offset = 0; + int32_t lower_bound = b->first_glyph_index(); + int32_t upper_bound = b->last_glyph_index(); + bool lower_bound_reached = false; + bool upper_bound_reached = false; + int32_t last_gid = -1; + BitmapGlyphInfoMap::const_iterator last_element = loca.end(); + --last_element; for (BitmapGlyphInfoMap::const_iterator i = loca.begin(), e = loca.end(); i != e; i++) { - pairs[index].set_glyph_code(i->first); - pairs[index].set_offset(i->second->offset()); - index++; - } - builder->SetOffsetArray(pairs); -} - -void SubsetIndexSubTableFormat5(IndexSubTable::Builder* b, - const BitmapGlyphInfoMap& loca) { - IndexSubTableFormat5BuilderPtr builder = - down_cast<IndexSubTableFormat5::Builder*>(b); - IntegerList* glyph_array = builder->GlyphArray(); - for (IntegerList::iterator i = glyph_array->begin(); i != glyph_array->end(); - i++) { - if (loca.find(*i) == loca.end()) { - glyph_array->erase(i); + int32_t gid = i->first; + if (gid < lower_bound) { + continue; + } + if (!lower_bound_reached) { + new_builder->set_first_glyph_index(gid); + new_builder->set_image_format(b->image_format()); + new_builder->set_image_data_offset(*image_data_offset); + new_builder->SetImageSize(image_size); + last_gid = gid; + lower_bound_reached = true; + } + if (gid > upper_bound || i == last_element) { + upper_bound_reached = true; + } + if (!upper_bound_reached || i == last_element) { + glyph_array->push_back(gid); + offset += i->second->length(); + last_gid = gid; + } + if (upper_bound_reached) { + new_builder->set_last_glyph_index(last_gid); + *image_data_offset += offset; + break; } } - if (!glyph_array->empty()) { - builder->set_first_glyph_index(*(glyph_array->begin())); - builder->set_last_glyph_index(*(glyph_array->rbegin())); - } else { - builder->set_first_glyph_index(0); - builder->set_last_glyph_index(0); - } + return new_builder.Detach(); } -void SubsetIndexSubTable(IndexSubTable::Builder* builder, - const BitmapGlyphInfoMap& loca) { +CALLER_ATTACH IndexSubTable::Builder* +SubsetIndexSubTable(IndexSubTable::Builder* builder, + const BitmapGlyphInfoMap& loca, + int32_t* image_data_offset) { switch (builder->index_format()) { - case 1: - SubsetIndexSubTableFormat1(builder, loca); - break; - case 2: - SubsetIndexSubTableFormat2(builder, loca); - break; - case 3: - SubsetIndexSubTableFormat3(builder, loca); - break; - case 4: - SubsetIndexSubTableFormat4(builder, loca); - break; - case 5: - SubsetIndexSubTableFormat5(builder, loca); - break; + case IndexSubTable::Format::FORMAT_1: + case IndexSubTable::Format::FORMAT_3: + case IndexSubTable::Format::FORMAT_4: + return ConstructIndexFormat4(builder, loca, image_data_offset); + case IndexSubTable::Format::FORMAT_2: + case IndexSubTable::Format::FORMAT_5: + return ConstructIndexFormat5(builder, loca, image_data_offset); default: assert(false); // Shall not be here. break; } + return NULL; } void SubsetEBLC(EblcTable::Builder* eblc, const BitmapLocaList& new_loca) { @@ -487,25 +509,20 @@ void SubsetEBLC(EblcTable::Builder* eblc, const BitmapLocaList& new_loca) { return; // No valid EBLC. } + int32_t image_data_offset = EbdtTable::Offset::kHeaderLength; for (size_t strike = 0; strike < size_builders->size(); ++strike) { IndexSubTableBuilderList* index_builders = (*size_builders)[strike]->IndexSubTableBuilders(); - bool format4_processed = false; for (size_t index = 0; index < index_builders->size(); ++index) { - // Only one format 4 table per strike. - if ((*index_builders)[index]->index_format() == 4 && format4_processed) { - continue; - } - SubsetIndexSubTable((*index_builders)[index], new_loca[strike]); - if ((*index_builders)[index]->index_format() == 4) { - format4_processed = true; + IndexSubTable::Builder* new_builder_raw = + SubsetIndexSubTable((*index_builders)[index], new_loca[strike], + &image_data_offset); + if (NULL != new_builder_raw) { + (*index_builders)[index].Attach(new_builder_raw); } } } } -/****************************************************************************** - * EXPERIMENTAL CODE ENDS - *****************************************************************************/ /****************************************************************************** Long background comments @@ -542,34 +559,21 @@ Subsetting EBLC table: reconstructed to either format 4 or 5. *******************************************************************************/ bool SetupBitmapBuilders(Font* font, Font::Builder* builder, - const IntegerSet& glyph_ids) { + const IntegerSet& glyph_ids, bool use_ebdt) { if (!font || !builder) { return false; } - // Check if bitmap table exists. - bool use_ebdt = true; - EbdtTablePtr ebdt_table = down_cast<EbdtTable*>(font->GetTable(Tag::EBDT)); - EblcTablePtr eblc_table = down_cast<EblcTable*>(font->GetTable(Tag::EBLC)); - if (ebdt_table == NULL && eblc_table == NULL) { - use_ebdt = false; - // Check BDAT variants. - ebdt_table = down_cast<EbdtTable*>(font->GetTable(Tag::bdat)); - eblc_table = down_cast<EblcTable*>(font->GetTable(Tag::bloc)); - } - if (ebdt_table == NULL || eblc_table == NULL) { - // There's no bitmap tables. - return true; - } + EbdtTablePtr ebdt_table = + down_cast<EbdtTable*>(font->GetTable(use_ebdt ? Tag::EBDT : Tag::bdat)); + EblcTablePtr eblc_table = + down_cast<EblcTable*>(font->GetTable(use_ebdt ? Tag::EBLC : Tag::bloc)); // If the bitmap table's size is too small, skip subsetting. - // TODO(arthurhsu): temporarily comment out to use smaller font for testing. - /* if (ebdt_table->DataLength() + eblc_table->DataLength() < BITMAP_SIZE_THRESHOLD) { return true; } - */ // Get the builders. FontBuilderPtr font_builder = builder; @@ -586,11 +590,9 @@ bool SetupBitmapBuilders(Font* font, Font::Builder* builder, if (!ShallSubset(ebdt_table_builder, eblc_table_builder, glyph_ids)) { // Bitmap tables do not cover the glyphs in our subset. - ebdt_table_builder.Release(); - eblc_table_builder.Release(); - font_builder->RemoveTableBuilder(use_ebdt ? Tag::EBDT : Tag::bdat); font_builder->RemoveTableBuilder(use_ebdt ? Tag::EBLC : Tag::bloc); - return true; + font_builder->RemoveTableBuilder(use_ebdt ? Tag::EBDT : Tag::bdat); + return false; } BitmapLocaList new_loca; @@ -600,6 +602,30 @@ bool SetupBitmapBuilders(Font* font, Font::Builder* builder, return true; } +enum BitmapDetection { + kNotFound, + kEBDTFound, + kOnlyBDATFound +}; + +// Some fonts have both EBDT/EBLC and bdat/bloc, we need only one set of them. +int DetectBitmapBuilders(Font* font) { + // Check if bitmap table exists. + EbdtTablePtr ebdt_table = down_cast<EbdtTable*>(font->GetTable(Tag::EBDT)); + EblcTablePtr eblc_table = down_cast<EblcTable*>(font->GetTable(Tag::EBLC)); + if (ebdt_table == NULL && eblc_table == NULL) { + // Check BDAT variants. + ebdt_table = down_cast<EbdtTable*>(font->GetTable(Tag::bdat)); + eblc_table = down_cast<EblcTable*>(font->GetTable(Tag::bloc)); + if (ebdt_table == NULL || eblc_table == NULL) { + // There's no bitmap tables. + return kNotFound; + } + return kOnlyBDATFound; + } + return kEBDTFound; +} + SubsetterImpl::SubsetterImpl() { } @@ -735,13 +761,23 @@ CALLER_ATTACH Font* SubsetterImpl::Subset(const IntegerSet& glyph_ids) { remove_tags.insert(Tag::glyf); remove_tags.insert(Tag::loca); } - if (SetupBitmapBuilders(font_, font_builder, glyph_ids)) { - remove_tags.insert(Tag::bdat); - remove_tags.insert(Tag::bloc); - remove_tags.insert(Tag::bhed); - remove_tags.insert(Tag::EBDT); - remove_tags.insert(Tag::EBLC); - remove_tags.insert(Tag::EBSC); + + int flag = DetectBitmapBuilders(font_); + if (flag != kNotFound) { + bool use_ebdt = (flag == kEBDTFound); + bool subset_success = + SetupBitmapBuilders(font_, font_builder, glyph_ids, use_ebdt); + + if (use_ebdt || !subset_success) { + remove_tags.insert(Tag::bdat); + remove_tags.insert(Tag::bloc); + remove_tags.insert(Tag::bhed); + } + if (use_ebdt && !subset_success) { + remove_tags.insert(Tag::EBDT); + remove_tags.insert(Tag::EBLC); + remove_tags.insert(Tag::EBSC); + } } IntegerSet allowed_tags; diff --git a/test/subsetter_impl.h b/test/subsetter_impl.h index abcc420..5e6debe 100644 --- a/test/subsetter_impl.h +++ b/test/subsetter_impl.h @@ -47,13 +47,6 @@ namespace sfntly { // } // ref count = 1, obj2 out of scope // obj.release(); // ref count = 0, object destroyed -namespace { - -// The bitmap tables must be greater than 256KB to trigger bitmap subsetter. -static const int BITMAP_SIZE_THRESHOLD = 262144; - -} - class SubsetterImpl { public: SubsetterImpl(); diff --git a/test/test_data.cc b/test/test_data.cc index 6c26f0e..05bc759 100644 --- a/test/test_data.cc +++ b/test/test_data.cc @@ -31,6 +31,7 @@ const char* SAMPLE_BITMAP_FONT = "AnonymousPro-Regular.ttf"; const size_t SAMPLE_TTF_SIZE = 183936; const size_t SAMPLE_TTF_TABLES = 17; const size_t SAMPLE_TTF_KNOWN_TAGS = 16; +const size_t SAMPLE_BITMAP_KNOWN_TAGS = 20; const size_t SAMPLE_TTF_FEAT = 3; const size_t SAMPLE_TTF_HEAD = 6; const size_t SAMPLE_TTF_POST = 14; @@ -41,6 +42,12 @@ const int32_t TTF_KNOWN_TAGS[] = { Tag::loca, Tag::maxp, Tag::morx, Tag::name, Tag::post, Tag::prop }; +const int32_t BITMAP_KNOWN_TAGS[] = { + Tag::EBDT, Tag::EBLC, Tag::EBSC, Tag::LTSH, Tag::OS_2, + Tag::VDMX, Tag::cmap, Tag::cvt, Tag::fpgm, Tag::gasp, + Tag::glyf, Tag::hdmx, Tag::head, Tag::hhea, Tag::hmtx, + Tag::loca, Tag::maxp, Tag::name, Tag::post, Tag::prep }; + const int64_t TTF_CHECKSUM[] = { 0xD463FC48, 0x252028D1, 0x0065078A, 0xC01407B5, 0xFFFF0003, 0x9544342B, 0xFC8F16AD, 0x0EC30C7A, 0xA029CD5D, 0x32513087, diff --git a/test/test_data.h b/test/test_data.h index b6a5ed6..d5e576f 100644 --- a/test/test_data.h +++ b/test/test_data.h @@ -27,11 +27,13 @@ extern const char* SAMPLE_BITMAP_FONT; extern const size_t SAMPLE_TTF_SIZE; extern const size_t SAMPLE_TTF_TABLES; extern const size_t SAMPLE_TTF_KNOWN_TAGS; +extern const size_t SAMPLE_BITMAP_KNOWN_TAGS; extern const size_t SAMPLE_TTF_FEAT; extern const size_t SAMPLE_TTF_HEAD; extern const size_t SAMPLE_TTF_POST; extern const int32_t TTF_KNOWN_TAGS[]; +extern const int32_t BITMAP_KNOWN_TAGS[]; extern const int64_t TTF_CHECKSUM[]; extern const int64_t TTF_OFFSET[]; extern const int32_t TTF_LENGTH[]; |