Index: src/ots.cc |
=================================================================== |
--- src/ots.cc (revision 99) |
+++ src/ots.cc (working copy) |
@@ -14,12 +14,15 @@ |
#include <map> |
#include <vector> |
+#include "woff2.h" |
+ |
// The OpenType Font File |
// http://www.microsoft.com/typography/otspec/cmap.htm |
namespace { |
bool g_debug_output = true; |
+bool g_enable_woff2 = false; |
struct OpenTypeTable { |
uint32_t tag; |
@@ -29,15 +32,6 @@ |
uint32_t uncompressed_length; |
}; |
-// Round a value up to the nearest multiple of 4. Don't round the value in the |
-// case that rounding up overflows. |
-template<typename T> T Round4(T value) { |
- if (std::numeric_limits<T>::max() - value < 3) { |
- return value; |
- } |
- return (value + 3) & ~3; |
-} |
- |
bool CheckTag(uint32_t tag_value) { |
for (unsigned i = 0; i < 4; ++i) { |
const uint32_t check = tag_value & 0xff; |
@@ -151,15 +145,6 @@ |
{ 0, NULL, NULL, NULL, NULL, false }, |
}; |
-bool IsValidVersionTag(uint32_t tag) { |
- return tag == Tag("\x00\x01\x00\x00") || |
- // OpenType fonts with CFF data have 'OTTO' tag. |
- tag == Tag("OTTO") || |
- // Older Mac fonts might have 'true' or 'typ1' tag. |
- tag == Tag("true") || |
- tag == Tag("typ1"); |
-} |
- |
bool ProcessGeneric(ots::OpenTypeFile *header, |
uint32_t signature, |
ots::OTSStream *output, |
@@ -179,7 +164,7 @@ |
if (!file.ReadTag(&header->version)) { |
return OTS_FAILURE(); |
} |
- if (!IsValidVersionTag(header->version)) { |
+ if (!ots::IsValidVersionTag(header->version)) { |
return OTS_FAILURE(); |
} |
@@ -265,7 +250,7 @@ |
if (!file.ReadTag(&header->version)) { |
return OTS_FAILURE(); |
} |
- if (!IsValidVersionTag(header->version)) { |
+ if (!ots::IsValidVersionTag(header->version)) { |
return OTS_FAILURE(); |
} |
@@ -343,7 +328,7 @@ |
return OTS_FAILURE(); |
} |
- total_sfnt_size += Round4(table.uncompressed_length); |
+ total_sfnt_size += ots::Round4(table.uncompressed_length); |
if (total_sfnt_size > std::numeric_limits<uint32_t>::max()) { |
return OTS_FAILURE(); |
} |
@@ -359,7 +344,7 @@ |
} |
// Table data must follow immediately after the header. |
- if (tables[first_index].offset != Round4(file.offset())) { |
+ if (tables[first_index].offset != ots::Round4(file.offset())) { |
return OTS_FAILURE(); |
} |
@@ -369,7 +354,7 @@ |
} |
// Blocks must follow immediately after the previous block. |
// (Except for padding with a maximum of three null bytes) |
- uint64_t block_end = Round4( |
+ uint64_t block_end = ots::Round4( |
static_cast<uint64_t>(tables[last_index].offset) + |
static_cast<uint64_t>(tables[last_index].length)); |
if (block_end > std::numeric_limits<uint32_t>::max()) { |
@@ -379,8 +364,8 @@ |
if (block_end != meta_offset) { |
return OTS_FAILURE(); |
} |
- block_end = Round4(static_cast<uint64_t>(meta_offset) + |
- static_cast<uint64_t>(meta_length)); |
+ block_end = ots::Round4(static_cast<uint64_t>(meta_offset) + |
+ static_cast<uint64_t>(meta_length)); |
if (block_end > std::numeric_limits<uint32_t>::max()) { |
return OTS_FAILURE(); |
} |
@@ -389,19 +374,38 @@ |
if (block_end != priv_offset) { |
return OTS_FAILURE(); |
} |
- block_end = Round4(static_cast<uint64_t>(priv_offset) + |
- static_cast<uint64_t>(priv_length)); |
+ block_end = ots::Round4(static_cast<uint64_t>(priv_offset) + |
+ static_cast<uint64_t>(priv_length)); |
if (block_end > std::numeric_limits<uint32_t>::max()) { |
return OTS_FAILURE(); |
} |
} |
- if (block_end != Round4(length)) { |
+ if (block_end != ots::Round4(length)) { |
return OTS_FAILURE(); |
} |
return ProcessGeneric(header, woff_tag, output, data, length, tables, file); |
} |
+bool ProcessWOFF2(ots::OpenTypeFile *header, |
+ ots::OTSStream *output, const uint8_t *data, size_t length) { |
+ size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length); |
+ if (decompressed_size == 0) { |
+ return OTS_FAILURE(); |
+ } |
+ // decompressed font must be <= 30MB |
+ if (decompressed_size > 30 * 1024 * 1024) { |
+ return OTS_FAILURE(); |
+ } |
+ |
+ std::vector<uint8_t> decompressed_buffer(decompressed_size); |
+ if (!ots::ConvertWOFF2ToTTF(&decompressed_buffer[0], decompressed_size, |
+ data, length)) { |
+ return OTS_FAILURE(); |
+ } |
+ return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size); |
+} |
+ |
bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature, |
ots::OTSStream *output, |
const uint8_t *data, size_t length, |
@@ -467,7 +471,7 @@ |
uint32_t end_byte = tables[i].offset + tables[i].length; |
// Tables in the WOFF file must be aligned 4-byte boundary. |
if (signature == Tag("wOFF")) { |
- end_byte = Round4(end_byte); |
+ end_byte = ots::Round4(end_byte); |
} |
if (!end_byte || end_byte > length) { |
return OTS_FAILURE(); |
@@ -679,10 +683,23 @@ |
namespace ots { |
+bool IsValidVersionTag(uint32_t tag) { |
+ return tag == Tag("\x00\x01\x00\x00") || |
+ // OpenType fonts with CFF data have 'OTTO' tag. |
+ tag == Tag("OTTO") || |
+ // Older Mac fonts might have 'true' or 'typ1' tag. |
+ tag == Tag("true") || |
+ tag == Tag("typ1"); |
+} |
+ |
void DisableDebugOutput() { |
g_debug_output = false; |
} |
+void EnableWOFF2() { |
+ g_enable_woff2 = true; |
+} |
+ |
bool Process(OTSStream *output, const uint8_t *data, size_t length) { |
OpenTypeFile header; |
if (length < 4) { |
@@ -692,6 +709,10 @@ |
bool result; |
if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') { |
result = ProcessWOFF(&header, output, data, length); |
+ } else if (g_enable_woff2 && |
+ data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && |
+ data[3] == '2') { |
+ result = ProcessWOFF2(&header, output, data, length); |
} else { |
result = ProcessTTF(&header, output, data, length); |
} |