aboutsummaryrefslogtreecommitdiff
path: root/woff2/normalize.cc
diff options
context:
space:
mode:
Diffstat (limited to 'woff2/normalize.cc')
-rw-r--r--woff2/normalize.cc103
1 files changed, 80 insertions, 23 deletions
diff --git a/woff2/normalize.cc b/woff2/normalize.cc
index 0812b00..a816feb 100644
--- a/woff2/normalize.cc
+++ b/woff2/normalize.cc
@@ -63,29 +63,16 @@ void NormalizeSimpleGlyphBoundingBox(Glyph* glyph) {
} // namespace
-bool NormalizeGlyphs(Font* font) {
- Font::Table* head_table = font->FindTable(kHeadTableTag);
+namespace {
+
+bool WriteNormalizedLoca(int index_fmt, int num_glyphs, Font* font) {
Font::Table* glyf_table = font->FindTable(kGlyfTableTag);
Font::Table* loca_table = font->FindTable(kLocaTableTag);
- if (head_table == NULL || loca_table == NULL || glyf_table == NULL) {
- return FONT_COMPRESSION_FAILURE();
- }
- int index_fmt = head_table->data[51];
- int num_glyphs = NumGlyphs(*font);
- // We need to allocate a bit more than its original length for the normalized
- // glyf table, since it can happen that the glyphs in the original table are
- // 2-byte aligned, while in the normalized table they are 4-byte aligned.
- // That gives a maximum of 2 bytes increase per glyph. However, there is no
- // theoretical guarantee that the total size of the flags plus the coordinates
- // is the smallest possible in the normalized version, so we have to allow
- // some general overhead.
- // TODO(user) Figure out some more precise upper bound on the size of
- // the overhead.
- size_t max_normalized_glyf_size = 1.1 * glyf_table->length + 2 * num_glyphs;
+ int glyph_sz = index_fmt == 0 ? 2 : 4;
+ loca_table->buffer.resize(Round4(num_glyphs + 1) * glyph_sz);
+ loca_table->length = (num_glyphs + 1) * glyph_sz;
- glyf_table->buffer.resize(max_normalized_glyf_size);
- loca_table->buffer.resize(Round4(loca_table->length));
uint8_t* glyf_dst = &glyf_table->buffer[0];
uint8_t* loca_dst = &loca_table->buffer[0];
uint32_t glyf_offset = 0;
@@ -113,6 +100,10 @@ bool NormalizeGlyphs(Font* font) {
}
glyf_offset += glyf_dst_size;
}
+ if (glyf_offset == 0) {
+ return false;
+ }
+
StoreLoca(index_fmt, glyf_offset, &loca_offset, loca_dst);
glyf_table->buffer.resize(glyf_offset);
@@ -123,6 +114,74 @@ bool NormalizeGlyphs(Font* font) {
return true;
}
+} // namespace
+
+namespace {
+
+bool MakeEditableBuffer(Font* font, int tableTag) {
+ Font::Table* table = font->FindTable(tableTag);
+ if (table == NULL) {
+ return FONT_COMPRESSION_FAILURE();
+ }
+ int sz = Round4(table->length);
+ table->buffer.resize(sz);
+ uint8_t* buf = &table->buffer[0];
+ memcpy(buf, table->data, sz);
+ table->data = buf;
+ return true;
+}
+
+} // namespace
+
+bool NormalizeGlyphs(Font* font) {
+ Font::Table* cff_table = font->FindTable(kCffTableTag);
+ Font::Table* head_table = font->FindTable(kHeadTableTag);
+ Font::Table* glyf_table = font->FindTable(kGlyfTableTag);
+ Font::Table* loca_table = font->FindTable(kLocaTableTag);
+ if (head_table == NULL) {
+ return FONT_COMPRESSION_FAILURE();
+ }
+ // CFF, no loca, no glyf is OK for CFF. If so, don't normalize.
+ if (cff_table != NULL && loca_table == NULL && glyf_table == NULL) {
+ return true;
+ }
+ if (loca_table == NULL || glyf_table == NULL) {
+ return FONT_COMPRESSION_FAILURE();
+ }
+ int index_fmt = head_table->data[51];
+ int num_glyphs = NumGlyphs(*font);
+
+ // We need to allocate a bit more than its original length for the normalized
+ // glyf table, since it can happen that the glyphs in the original table are
+ // 2-byte aligned, while in the normalized table they are 4-byte aligned.
+ // That gives a maximum of 2 bytes increase per glyph. However, there is no
+ // theoretical guarantee that the total size of the flags plus the coordinates
+ // is the smallest possible in the normalized version, so we have to allow
+ // some general overhead.
+ // TODO(user) Figure out some more precise upper bound on the size of
+ // the overhead.
+ size_t max_normalized_glyf_size = 1.1 * glyf_table->length + 2 * num_glyphs;
+
+ glyf_table->buffer.resize(max_normalized_glyf_size);
+
+ // if we can't write a loca using short's (index_fmt 0)
+ // try again using longs (index_fmt 1)
+ if (!WriteNormalizedLoca(index_fmt, num_glyphs, font)) {
+ if (index_fmt != 0) {
+ return FONT_COMPRESSION_FAILURE();
+ }
+
+ // Rewrite loca with 4-byte entries & update head to match
+ index_fmt = 1;
+ if (!WriteNormalizedLoca(index_fmt, num_glyphs, font)) {
+ return FONT_COMPRESSION_FAILURE();
+ }
+ head_table->buffer[51] = 1;
+ }
+
+ return true;
+}
+
bool NormalizeOffsets(Font* font) {
uint32_t offset = 12 + 16 * font->num_tables;
for (auto& i : font->tables) {
@@ -168,10 +227,7 @@ bool FixChecksums(Font* font) {
if (head_table == NULL || head_table->length < 12) {
return FONT_COMPRESSION_FAILURE();
}
- head_table->buffer.resize(Round4(head_table->length));
uint8_t* head_buf = &head_table->buffer[0];
- memcpy(head_buf, head_table->data, Round4(head_table->length));
- head_table->data = head_buf;
size_t offset = 8;
StoreU32(0, &offset, head_buf);
uint32_t file_checksum = 0;
@@ -187,7 +243,8 @@ bool FixChecksums(Font* font) {
}
bool NormalizeFont(Font* font) {
- return (RemoveDigitalSignature(font) &&
+ return (MakeEditableBuffer(font, kHeadTableTag) &&
+ RemoveDigitalSignature(font) &&
NormalizeGlyphs(font) &&
NormalizeOffsets(font) &&
FixChecksums(font));