hmtx optimization decoding. never encodes hmtx optimized as yet; need a cli param.

This commit is contained in:
Rod Sheeter
2016-01-20 14:10:02 -08:00
parent db0448815a
commit c817c969bf
9 changed files with 447 additions and 55 deletions
+1
View File
@@ -79,6 +79,7 @@ bool ReadTrueTypeFont(Buffer* file, const uint8_t* data, size_t len,
std::map<uint32_t, uint32_t> intervals;
for (uint16_t i = 0; i < font->num_tables; ++i) {
Font::Table table;
table.flag_byte = 0;
table.reuse_of = NULL;
if (!file->ReadU32(&table.tag) ||
!file->ReadU32(&table.checksum) ||
+2
View File
@@ -47,6 +47,8 @@ struct Font {
// Intended use is to bypass re-processing tables
Font::Table* reuse_of;
uint8_t flag_byte;
// Is this table reused by a TTC
bool IsReused() const;
};
+5 -5
View File
@@ -78,11 +78,6 @@ bool ReadGlyph(const uint8_t* data, size_t len, Glyph* glyph) {
return FONT_COMPRESSION_FAILURE();
}
if (num_contours == 0) {
// Empty glyph.
return true;
}
// Read the bounding box.
if (!buffer.ReadS16(&glyph->x_min) ||
!buffer.ReadS16(&glyph->y_min) ||
@@ -91,6 +86,11 @@ bool ReadGlyph(const uint8_t* data, size_t len, Glyph* glyph) {
return FONT_COMPRESSION_FAILURE();
}
if (num_contours == 0) {
// Empty glyph.
return true;
}
if (num_contours > 0) {
// Simple glyph.
glyph->contours.resize(num_contours);
+3
View File
@@ -27,6 +27,9 @@ static const uint32_t kHeadTableTag = 0x68656164;
static const uint32_t kLocaTableTag = 0x6c6f6361;
static const uint32_t kDsigTableTag = 0x44534947;
static const uint32_t kCffTableTag = 0x43464620;
static const uint32_t kHmtxTableTag = 0x686d7478;
static const uint32_t kHheaTableTag = 0x68686561;
static const uint32_t kMaxpTableTag = 0x6d617870;
extern const uint32_t kKnownTags[];
+127
View File
@@ -290,4 +290,131 @@ bool TransformGlyfAndLocaTables(Font* font) {
return true;
}
// See https://www.microsoft.com/typography/otspec/hmtx.htm
// See WOFF2 spec, 5.4. Transformed hmtx table format
bool TransformHmtxTable(Font* font) {
const Font::Table* glyf_table = font->FindTable(kGlyfTableTag);
const Font::Table* hmtx_table = font->FindTable(kHmtxTableTag);
const Font::Table* hhea_table = font->FindTable(kHheaTableTag);
// If you don't have hmtx or a glyf not much is going to happen here
if (hmtx_table == NULL || glyf_table == NULL) {
return true;
}
// hmtx without hhea doesn't make sense
if (hhea_table == NULL) {
return FONT_COMPRESSION_FAILURE();
}
// Skip 34 to reach 'hhea' numberOfHMetrics
Buffer hhea_buf(hhea_table->data, hhea_table->length);
uint16_t num_hmetrics;
if (!hhea_buf.Skip(34) || !hhea_buf.ReadU16(&num_hmetrics)) {
return FONT_COMPRESSION_FAILURE();
}
// Must have at least one hMetric
if (num_hmetrics < 1) {
return FONT_COMPRESSION_FAILURE();
}
int num_glyphs = NumGlyphs(*font);
// Most fonts can be transformed; assume it's a go until proven otherwise
std::vector<uint16_t> advance_widths;
std::vector<int16_t> proportional_lsbs;
std::vector<int16_t> monospace_lsbs;
bool remove_proportional_lsb = true;
bool remove_monospace_lsb = (num_glyphs - num_hmetrics) > 0;
Buffer hmtx_buf(hmtx_table->data, hmtx_table->length);
for (int i = 0; i < num_glyphs; i++) {
Glyph glyph;
const uint8_t* glyph_data;
size_t glyph_size;
if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) ||
(glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) {
return FONT_COMPRESSION_FAILURE();
}
uint16_t advance_width = 0;
int16_t lsb = 0;
if (i < num_hmetrics) {
// [0, num_hmetrics) are proportional hMetrics
if (!hmtx_buf.ReadU16(&advance_width)) {
return FONT_COMPRESSION_FAILURE();
}
if (!hmtx_buf.ReadS16(&lsb)) {
return FONT_COMPRESSION_FAILURE();
}
if (glyph_size > 0 && glyph.x_min != lsb) {
remove_proportional_lsb = false;
}
advance_widths.push_back(advance_width);
proportional_lsbs.push_back(lsb);
} else {
// [num_hmetrics, num_glyphs) are monospace leftSideBearing's
if (!hmtx_buf.ReadS16(&lsb)) {
return FONT_COMPRESSION_FAILURE();
}
if (glyph_size > 0 && glyph.x_min != lsb) {
remove_monospace_lsb = false;
}
monospace_lsbs.push_back(lsb);
}
// If we know we can't optimize, bail out completely
if (!remove_proportional_lsb && !remove_monospace_lsb) {
return true;
}
}
Font::Table* transformed_hmtx = &font->tables[kHmtxTableTag ^ 0x80808080];
uint8_t flags = 0;
size_t transformed_size = 1 + 2 * advance_widths.size();
if (remove_proportional_lsb) {
flags |= 1;
} else {
transformed_size += 2 * proportional_lsbs.size();
}
if (remove_monospace_lsb) {
flags |= 1 << 1;
} else {
transformed_size += 2 * monospace_lsbs.size();
}
transformed_hmtx->buffer.reserve(transformed_size);
std::vector<uint8_t>* out = &transformed_hmtx->buffer;
WriteBytes(out, &flags, 1);
for (uint16_t advance_width : advance_widths) {
WriteUShort(out, advance_width);
}
if (!remove_proportional_lsb) {
for (int16_t lsb : proportional_lsbs) {
WriteUShort(out, lsb);
}
}
if (!remove_monospace_lsb) {
for (int16_t lsb : monospace_lsbs) {
WriteUShort(out, lsb);
}
}
transformed_hmtx->tag = kHmtxTableTag ^ 0x80808080;
transformed_hmtx->flag_byte = 1 << 6;
transformed_hmtx->length = transformed_hmtx->buffer.size();
transformed_hmtx->data = transformed_hmtx->buffer.data();
return true;
}
} // namespace woff2
+3
View File
@@ -26,6 +26,9 @@ namespace woff2 {
// derived from the original tag by flipping the MSBs of every byte.
bool TransformGlyfAndLocaTables(Font* font);
// Apply transformation to hmtx table if applicable for this font.
bool TransformHmtxTable(Font* font);
} // namespace woff2
#endif // WOFF2_TRANSFORM_H_
+2 -1
View File
@@ -26,7 +26,8 @@ namespace woff2 {
static const uint32_t kWoff2Signature = 0x774f4632; // "wOF2"
const unsigned int kWoff2FlagsTransform = 1 << 5;
// Leave the first byte open to store flag_byte
const unsigned int kWoff2FlagsTransform = 1 << 8;
// TrueType Collection ID string: 'ttcf'
static const uint32_t kTtcFontFlavor = 0x74746366;
+282 -28
View File
@@ -24,6 +24,7 @@
#include <string>
#include <vector>
#include <map>
#include <unordered_set>
#include <memory>
#include "./buffer.h"
@@ -401,6 +402,7 @@ bool ReconstructGlyf(const uint8_t* data, size_t data_size,
}
uint8_t* glyf_dst = dst + loca_offset;
size_t glyf_dst_size = dst_size - loca_offset;
if (n_contours == 0xffff) {
// composite glyph
bool have_instructions = false;
@@ -542,6 +544,200 @@ const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) {
return NULL;
}
// https://www.microsoft.com/typography/otspec/maxp.htm
bool ReadNumGlyphs(const Table* maxp_table,
uint8_t* dst, size_t dst_length, uint16_t* num_glyphs) {
if (PREDICT_FALSE(static_cast<uint64_t>(maxp_table->dst_offset +
maxp_table->dst_length) > dst_length)) {
return FONT_COMPRESSION_FAILURE();
}
Buffer buffer(dst + maxp_table->dst_offset, maxp_table->dst_length);
// Skip 4 to reach 'maxp' numGlyphs
if (PREDICT_FALSE(!buffer.Skip(4) || !buffer.ReadU16(num_glyphs))) {
return FONT_COMPRESSION_FAILURE();
}
return true;
}
// Get numberOfHMetrics, https://www.microsoft.com/typography/otspec/hhea.htm
bool ReadNumHMetrics(const Table* hhea_table,
uint8_t* dst, size_t dst_length, uint16_t* num_hmetrics) {
if (PREDICT_FALSE(static_cast<uint64_t>(hhea_table->dst_offset +
hhea_table->dst_length) > dst_length)) {
return FONT_COMPRESSION_FAILURE();
}
// Skip 34 to reach 'hhea' numberOfHMetrics
Buffer buffer(dst + hhea_table->dst_offset, hhea_table->dst_length);
if (PREDICT_FALSE(!buffer.Skip(34) || !buffer.ReadU16(num_hmetrics))) {
return FONT_COMPRESSION_FAILURE();
}
return true;
}
// x_min for glyph; https://www.microsoft.com/typography/otspec/glyf.htm
bool ReadGlyphXMin(Buffer* glyf_buff, Buffer* loca_buff, int16_t loca_format,
uint16_t index, int16_t* x_min) {
uint32_t offset1, offset2;
loca_buff->set_offset((loca_format == 0 ? 2 : 4) * index);
if (loca_format == 0) {
uint16_t tmp1, tmp2;
if (PREDICT_FALSE(!loca_buff->ReadU16(&tmp1) ||
!loca_buff->ReadU16(&tmp2))) {
return FONT_COMPRESSION_FAILURE();
}
// https://www.microsoft.com/typography/otspec/loca.htm
// "The actual local offset divided by 2 is stored."
offset1 = tmp1 * 2;
offset2 = tmp2 * 2;
} else if (PREDICT_FALSE(!loca_buff->ReadU32(&offset1) ||
!loca_buff->ReadU32(&offset2))) {
return FONT_COMPRESSION_FAILURE();
}
if (offset1 != offset2) {
glyf_buff->set_offset(offset1 + 2);
if (!glyf_buff->ReadS16(x_min)) {
return FONT_COMPRESSION_FAILURE();
}
} else {
*x_min = 0;
}
return true;
}
// http://dev.w3.org/webfonts/WOFF2/spec/Overview.html#hmtx_table_format
bool ReconstructTransformedHmtx(const uint8_t* transformed_buf,
size_t transformed_size,
const Table* glyf_table,
const Table* hhea_table,
const Table* hmtx_table,
const Table* loca_table,
const Table* maxp_table,
uint8_t* dst, size_t dst_length) {
if (PREDICT_FALSE(!glyf_table)) {
return FONT_COMPRESSION_FAILURE();
}
if (PREDICT_FALSE(!hhea_table)) {
return FONT_COMPRESSION_FAILURE();
}
if (PREDICT_FALSE(!hmtx_table)) {
return FONT_COMPRESSION_FAILURE();
}
if (PREDICT_FALSE(!loca_table)) {
return FONT_COMPRESSION_FAILURE();
}
if (PREDICT_FALSE(!maxp_table)) {
return FONT_COMPRESSION_FAILURE();
}
uint16_t num_glyphs, num_hmetrics;
if (!ReadNumGlyphs(maxp_table, dst, dst_length, &num_glyphs)) {
return FONT_COMPRESSION_FAILURE();
}
if (!ReadNumHMetrics(hhea_table, dst, dst_length, &num_hmetrics)) {
return FONT_COMPRESSION_FAILURE();
}
if (PREDICT_FALSE(static_cast<uint64_t>(hmtx_table->dst_offset +
hmtx_table->dst_length) > dst_length)) {
return FONT_COMPRESSION_FAILURE();
}
Buffer hmtx_buff_in(transformed_buf, transformed_size);
uint8_t hmtx_flags;
if (PREDICT_FALSE(!hmtx_buff_in.ReadU8(&hmtx_flags))) {
return FONT_COMPRESSION_FAILURE();
}
std::vector<uint16_t> advance_widths;
std::vector<int16_t> lsbs;
bool has_proportional_lsbs = (hmtx_flags & 1) == 0;
bool has_monospace_lsbs = (hmtx_flags & 2) == 0;
// you say you transformed but there is little evidence of it
if (has_proportional_lsbs && has_monospace_lsbs) {
return FONT_COMPRESSION_FAILURE();
}
// glyf/loca are done already so we can use them to recover x_min's
if (PREDICT_FALSE(static_cast<uint64_t>(glyf_table->dst_offset +
glyf_table->dst_length) > dst_length)) {
return FONT_COMPRESSION_FAILURE();
}
if (PREDICT_FALSE(static_cast<uint64_t>(loca_table->dst_offset +
loca_table->dst_length) > dst_length)) {
return FONT_COMPRESSION_FAILURE();
}
Buffer glyf_buff(dst + glyf_table->dst_offset, glyf_table->dst_length);
Buffer loca_buff(dst + loca_table->dst_offset, loca_table->dst_length);
int16_t loca_format;
if (loca_table->dst_length == 2 * (num_glyphs + 1)) {
loca_format = 0;
} else if (loca_table->dst_length == 4 * (num_glyphs + 1)) {
loca_format = 1;
} else {
return FONT_COMPRESSION_FAILURE();
}
for (uint16_t i = 0; i < num_hmetrics; i++) {
uint16_t advance_width;
if (PREDICT_FALSE(!hmtx_buff_in.ReadU16(&advance_width))) {
return FONT_COMPRESSION_FAILURE();
}
advance_widths.push_back(advance_width);
}
for (uint16_t i = 0; i < num_hmetrics; i++) {
int16_t lsb;
if (has_proportional_lsbs) {
if (PREDICT_FALSE(!hmtx_buff_in.ReadS16(&lsb))) {
return FONT_COMPRESSION_FAILURE();
}
} else {
if (PREDICT_FALSE(!ReadGlyphXMin(&glyf_buff, &loca_buff, loca_format, i,
&lsb))) {
return FONT_COMPRESSION_FAILURE();
}
}
lsbs.push_back(lsb);
}
for (uint16_t i = num_hmetrics; i < num_glyphs; i++) {
int16_t lsb;
if (has_monospace_lsbs) {
if (PREDICT_FALSE(!hmtx_buff_in.ReadS16(&lsb))) {
return FONT_COMPRESSION_FAILURE();
}
} else {
if (PREDICT_FALSE(!ReadGlyphXMin(&glyf_buff, &loca_buff, loca_format, i,
&lsb))) {
return FONT_COMPRESSION_FAILURE();
}
}
lsbs.push_back(lsb);
}
// bake me a shiny new hmtx table
uint32_t hmtx_output_size = 2 * num_glyphs + 2 * num_hmetrics;
if (hmtx_output_size > hmtx_table->dst_length) {
return FONT_COMPRESSION_FAILURE();
}
if (PREDICT_FALSE(static_cast<uint64_t>(hmtx_table->dst_offset +
hmtx_table->dst_length) > dst_length)) {
return FONT_COMPRESSION_FAILURE();
}
size_t dst_offset = hmtx_table->dst_offset;
for (uint32_t i = 0; i < num_glyphs; i++) {
if (i < num_hmetrics) {
Store16(advance_widths[i], &dst_offset, dst);
}
Store16(lsbs[i], &dst_offset, dst);
}
return true;
}
bool ReconstructTransformedGlyf(const uint8_t* transformed_buf,
size_t transformed_size, const Table* glyf_table, const Table* loca_table,
uint8_t* dst, size_t dst_length) {
@@ -561,9 +757,11 @@ bool ReconstructTransformedGlyf(const uint8_t* transformed_buf,
dst + loca_table->dst_offset, loca_table->dst_length);
}
// Reconstructs a single font. tables must not contain duplicates.
bool ReconstructTransformed(const std::vector<Table>& tables, uint32_t tag,
const uint8_t* transformed_buf, size_t transformed_size,
uint8_t* dst, size_t dst_length) {
if (tag == kGlyfTableTag) {
const Table* glyf_table = FindTable(tables, tag);
const Table* loca_table = FindTable(tables, kLocaTableTag);
@@ -574,6 +772,20 @@ bool ReconstructTransformed(const std::vector<Table>& tables, uint32_t tag,
if (PREDICT_FALSE(!FindTable(tables, kGlyfTableTag))) {
return FONT_COMPRESSION_FAILURE();
}
} else if (tag == kHmtxTableTag) {
// Tables are sorted for a non-collection.
// glyf is before hmtx and includes loca so all our accesses are safe.
const Table* glyf_table = FindTable(tables, kGlyfTableTag);
const Table* hhea_table = FindTable(tables, kHheaTableTag);
const Table* hmtx_table = FindTable(tables, kHmtxTableTag);
const Table* loca_table = FindTable(tables, kLocaTableTag);
const Table* maxp_table = FindTable(tables, kMaxpTableTag);
if (PREDICT_FALSE(!ReconstructTransformedHmtx(
transformed_buf, transformed_size, glyf_table, hhea_table,
hmtx_table, loca_table, maxp_table, dst, dst_length))) {
return FONT_COMPRESSION_FAILURE();
}
} else {
// transform for the tag is not known
return FONT_COMPRESSION_FAILURE();
@@ -696,15 +908,19 @@ bool ReadTableDirectory(Buffer* file, std::vector<Table>* tables,
} else {
tag = kKnownTags[flag_byte & 0x3f];
}
// Bits 6 and 7 are reserved and must be 0.
if (PREDICT_FALSE((flag_byte & 0xC0)) != 0) {
return FONT_COMPRESSION_FAILURE();
}
uint32_t flags = 0;
// Always transform the glyf and loca tables
uint8_t xform_version = (flag_byte >> 6) & 0x03;
// 0 means xform for glyph/loca, non-0 for others
if (tag == kGlyfTableTag || tag == kLocaTableTag) {
if (xform_version == 0) {
flags |= kWoff2FlagsTransform;
}
} else if (xform_version != 0) {
flags |= kWoff2FlagsTransform;
}
flags |= xform_version;
uint32_t dst_length;
if (PREDICT_FALSE(!ReadBase128(file, &dst_length))) {
return FONT_COMPRESSION_FAILURE();
@@ -781,6 +997,29 @@ uint64_t ComputeOffsetToFirstTable(const uint32_t header_version,
return offset;
}
bool ReconstructTransformedFont(const std::vector<Table>& tables,
std::map<uint32_t, const uint8_t*>* src_by_dest,
uint8_t* result, size_t result_length) {
for (const auto& table : tables) {
if ((table.flags & kWoff2FlagsTransform) != kWoff2FlagsTransform) {
continue;
}
const auto it = src_by_dest->find(table.dst_offset);
if (it == src_by_dest->end()) {
continue;
}
const uint8_t* transform_buf = (*it).second;
src_by_dest->erase(table.dst_offset);
size_t transform_length = table.transform_length;
if (PREDICT_FALSE(!ReconstructTransformed(tables, table.tag,
transform_buf, transform_length, result, result_length))) {
return FONT_COMPRESSION_FAILURE();
}
}
return true;
}
bool ConvertWOFF2ToTTF(uint8_t* result, size_t result_length,
const uint8_t* data, size_t length) {
Buffer file(data, length);
@@ -1046,14 +1285,31 @@ bool ConvertWOFF2ToTTF(uint8_t* result, size_t result_length,
src_buf, compressed_length))) {
return FONT_COMPRESSION_FAILURE();
}
// round 1, copy across all the unmodified tables
transform_buf = &uncompressed_buf[0];
const uint8_t* const transform_buf_end = &uncompressed_buf[0]
+ uncompressed_buf.size();
// We wipe out the values as they get written into the final result to dedup
std::map<uint32_t, const uint8_t*> src_by_dest;
for (uint16_t i = 0; i < num_tables; ++i) {
const Table* table = &tables[i];
size_t transform_length = table->transform_length;
src_by_dest[table->dst_offset] = transform_buf;
if (PREDICT_FALSE(transform_buf + transform_length > transform_buf_end)) {
return FONT_COMPRESSION_FAILURE();
}
transform_buf += transform_length;
}
for (uint16_t i = 0; i < num_tables; ++i) {
const Table* table = &tables[i];
uint32_t flags = table->flags;
size_t transform_length = table->transform_length;
const size_t transform_length = table->transform_length;
if ((flags & kWoff2FlagsTransform) == 0) {
if ((table->flags & kWoff2FlagsTransform) != kWoff2FlagsTransform) {
if (PREDICT_FALSE(transform_length != table->dst_length)) {
return FONT_COMPRESSION_FAILURE();
}
@@ -1061,31 +1317,29 @@ bool ConvertWOFF2ToTTF(uint8_t* result, size_t result_length,
transform_length) > result_length)) {
return FONT_COMPRESSION_FAILURE();
}
transform_buf = src_by_dest.at(table->dst_offset);
src_by_dest.erase(table->dst_offset);
std::memcpy(result + table->dst_offset, transform_buf, transform_length);
}
}
std::memcpy(result + table->dst_offset, transform_buf,
transform_length);
} else {
if (header_version) {
if (table->tag == kGlyfTableTag) {
const Table* loca_table = loca_by_glyf[table];
if (PREDICT_FALSE(!ReconstructTransformedGlyf(transform_buf,
transform_length, table, loca_table, result, result_length))) {
// round 2, reconstruct transformed tables
if (PREDICT_FALSE(header_version)) {
// Rebuild collection font by font.
std::vector<Table> font_tables;
for (const auto& ttc_font : ttc_fonts) {
font_tables.resize(ttc_font.table_indices.size());
for (auto i = 0; i < ttc_font.table_indices.size(); i++) {
font_tables[i] = tables[ttc_font.table_indices[i]];
}
if (PREDICT_FALSE(!ReconstructTransformedFont(font_tables, &src_by_dest,
result, result_length))) {
return FONT_COMPRESSION_FAILURE();
}
} else if (PREDICT_FALSE(table->tag != kLocaTableTag)) {
// transform for this tag not known
return FONT_COMPRESSION_FAILURE();
}
} else {
if (PREDICT_FALSE(!ReconstructTransformed(tables, table->tag,
transform_buf, transform_length, result, result_length))) {
return FONT_COMPRESSION_FAILURE();
}
}
}
transform_buf += transform_length;
if (PREDICT_FALSE(
transform_buf > &uncompressed_buf[0] + uncompressed_buf.size())) {
if (PREDICT_FALSE(!ReconstructTransformedFont(tables, &src_by_dest, result,
result_length))) {
return FONT_COMPRESSION_FAILURE();
}
}
+18 -17
View File
@@ -34,10 +34,12 @@
#include "./variable_length.h"
#include "./woff2_common.h"
namespace woff2 {
namespace {
using std::string;
using std::vector;
@@ -82,7 +84,7 @@ int KnownTableIndex(uint32_t tag) {
}
void StoreTableEntry(const Table& table, size_t* offset, uint8_t* dst) {
uint8_t flag_byte = KnownTableIndex(table.tag);
uint8_t flag_byte = (table.flags & 0xC0) | KnownTableIndex(table.tag);
dst[(*offset)++] = flag_byte;
// The index here is treated as a set of flag bytes because
// bits 6 and 7 of the byte are reserved for future use as flags.
@@ -109,6 +111,7 @@ size_t TableEntrySize(const Table& table) {
size_t ComputeWoff2Length(const FontCollection& font_collection,
const std::vector<Table>& tables,
std::map<uint32_t, uint16_t> index_by_offset,
size_t compressed_data_length,
size_t extended_metadata_length) {
size_t size = kWoff2HeaderSize;
@@ -137,10 +140,8 @@ size_t ComputeWoff2Length(const FontCollection& font_collection,
}
// compressed data
for (const auto& table : tables) {
size += table.dst_length;
size += compressed_data_length;
size = Round4(size);
}
size += extended_metadata_length;
return size;
@@ -217,7 +218,7 @@ bool TransformFontCollection(FontCollection* font_collection) {
for (auto& font : font_collection->fonts) {
if (!TransformGlyfAndLocaTables(&font)) {
#ifdef FONT_COMPRESSION_BIN
fprintf(stderr, "Font transformation failed.\n");
fprintf(stderr, "glyf/loca transformation failed.\n");
#endif
return FONT_COMPRESSION_FAILURE();
}
@@ -291,6 +292,11 @@ bool ConvertTTFToWOFF2(const uint8_t *data, size_t length,
return FONT_COMPRESSION_FAILURE();
}
#ifdef FONT_COMPRESSION_BIN
fprintf(stderr, "Compressed %zu to %u.\n", total_transform_length,
total_compressed_length);
#endif
// Compress the extended metadata
// TODO(user): how does this apply to collections
uint32_t compressed_metadata_buf_length =
@@ -331,30 +337,25 @@ bool ConvertTTFToWOFF2(const uint8_t *data, size_t length,
Table table;
table.tag = src_table.tag;
table.flags = 0;
table.flags = src_table.flag_byte;
table.src_length = src_table.length;
table.transform_length = src_table.length;
const uint8_t* transformed_data = src_table.data;
const Font::Table* transformed_table =
font.FindTable(src_table.tag ^ 0x80808080);
if (transformed_table != NULL) {
table.flags = transformed_table->flag_byte;
table.flags |= kWoff2FlagsTransform;
table.transform_length = transformed_table->length;
transformed_data = transformed_table->data;
}
if (tables.empty()) {
table.dst_length = total_compressed_length;
table.dst_data = &compression_buf[0];
} else {
table.dst_length = 0;
table.dst_data = NULL;
}
tables.push_back(table);
}
}
size_t woff2_length = ComputeWoff2Length(font_collection, tables,
index_by_offset, compressed_metadata_buf_length);
index_by_offset, total_compressed_length, compressed_metadata_buf_length);
if (woff2_length > *result_length) {
#ifdef FONT_COMPRESSION_BIN
fprintf(stderr, "Result allocation was too small (%zd vs %zd bytes).\n",
@@ -444,10 +445,10 @@ bool ConvertTTFToWOFF2(const uint8_t *data, size_t length,
}
// compressed data format (http://www.w3.org/TR/WOFF2/#table_format)
for (const auto& table : tables) {
StoreBytes(table.dst_data, table.dst_length, &offset, result);
StoreBytes(&compression_buf[0], total_compressed_length, &offset, result);
offset = Round4(offset);
}
StoreBytes(compressed_metadata_buf.data(), compressed_metadata_buf_length,
&offset, result);