OLD | NEW |
1 // Copyright 2014 Google Inc. All Rights Reserved. | 1 // Copyright 2014 Google Inc. All Rights Reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
13 // limitations under the License. | 13 // limitations under the License. |
14 // | 14 // |
15 // Library for converting TTF format font files to their WOFF2 versions. | 15 // Library for converting TTF format font files to their WOFF2 versions. |
16 | 16 |
17 #include "./woff2_enc.h" | 17 #include "./woff2_enc.h" |
18 | 18 |
19 #include <stdlib.h> | 19 #include <stdlib.h> |
20 #include <complex> | 20 #include <complex> |
21 #include <cstring> | 21 #include <cstring> |
22 #include <limits> | 22 #include <limits> |
23 #include <string> | 23 #include <string> |
24 #include <vector> | 24 #include <vector> |
25 | 25 |
26 #include "./compressor.h" | 26 #include "./brotli/encode.h" |
27 #include "./buffer.h" | 27 #include "./buffer.h" |
28 #include "./font.h" | 28 #include "./font.h" |
29 #include "./normalize.h" | 29 #include "./normalize.h" |
30 #include "./round.h" | 30 #include "./round.h" |
31 #include "./store_bytes.h" | 31 #include "./store_bytes.h" |
32 #include "./table_tags.h" | 32 #include "./table_tags.h" |
33 #include "./transform.h" | 33 #include "./transform.h" |
34 #include "./variable_length.h" | 34 #include "./variable_length.h" |
35 #include "./woff2_common.h" | 35 #include "./woff2_common.h" |
36 | 36 |
37 | 37 |
38 namespace woff2 { | 38 namespace woff2 { |
39 | 39 |
40 namespace { | 40 namespace { |
41 | 41 |
42 | 42 |
43 using std::string; | 43 using std::string; |
44 using std::vector; | 44 using std::vector; |
45 | 45 |
46 | 46 |
47 const size_t kWoff2HeaderSize = 48; | 47 const size_t kWoff2HeaderSize = 48; |
48 const size_t kWoff2EntrySize = 20; | 48 const size_t kWoff2EntrySize = 20; |
49 | 49 |
50 | 50 bool Compress(const uint8_t* data, const size_t len, uint8_t* result, |
51 bool Compress(const uint8_t* data, const size_t len, | 51 uint32_t* result_len, BrotliEncoderMode mode, int quality) { |
52 uint8_t* result, uint32_t* result_len, | |
53 brotli::BrotliParams::Mode mode, int quality) { | |
54 size_t compressed_len = *result_len; | 52 size_t compressed_len = *result_len; |
55 brotli::BrotliParams params; | 53 if (BrotliEncoderCompress(quality, BROTLI_DEFAULT_WINDOW, mode, len, data, |
56 params.mode = mode; | 54 &compressed_len, result) == 0) { |
57 params.quality = quality; | |
58 if (brotli::BrotliCompressBuffer(params, len, data, &compressed_len, result) | |
59 == 0) { | |
60 return false; | 55 return false; |
61 } | 56 } |
62 *result_len = compressed_len; | 57 *result_len = compressed_len; |
63 return true; | 58 return true; |
64 } | 59 } |
65 | 60 |
66 bool Woff2Compress(const uint8_t* data, const size_t len, | 61 bool Woff2Compress(const uint8_t* data, const size_t len, |
67 uint8_t* result, uint32_t* result_len, | 62 uint8_t* result, uint32_t* result_len, |
68 int quality) { | 63 int quality) { |
69 return Compress(data, len, result, result_len, | 64 return Compress(data, len, result, result_len, |
70 brotli::BrotliParams::MODE_FONT, quality); | 65 BROTLI_MODE_FONT, quality); |
71 } | 66 } |
72 | 67 |
73 bool TextCompress(const uint8_t* data, const size_t len, | 68 bool TextCompress(const uint8_t* data, const size_t len, |
74 uint8_t* result, uint32_t* result_len, | 69 uint8_t* result, uint32_t* result_len, |
75 int quality) { | 70 int quality) { |
76 return Compress(data, len, result, result_len, | 71 return Compress(data, len, result, result_len, |
77 brotli::BrotliParams::MODE_TEXT, quality); | 72 BROTLI_MODE_TEXT, quality); |
78 } | 73 } |
79 | 74 |
80 int KnownTableIndex(uint32_t tag) { | 75 int KnownTableIndex(uint32_t tag) { |
81 for (int i = 0; i < 63; ++i) { | 76 for (int i = 0; i < 63; ++i) { |
82 if (tag == kKnownTags[i]) return i; | 77 if (tag == kKnownTags[i]) return i; |
83 } | 78 } |
84 return 63; | 79 return 63; |
85 } | 80 } |
86 | 81 |
87 void StoreTableEntry(const Table& table, size_t* offset, uint8_t* dst) { | 82 void StoreTableEntry(const Table& table, size_t* offset, uint8_t* dst) { |
(...skipping 26 matching lines...) Expand all Loading... |
114 std::map<uint32_t, uint16_t> index_by_offset, | 109 std::map<uint32_t, uint16_t> index_by_offset, |
115 size_t compressed_data_length, | 110 size_t compressed_data_length, |
116 size_t extended_metadata_length) { | 111 size_t extended_metadata_length) { |
117 size_t size = kWoff2HeaderSize; | 112 size_t size = kWoff2HeaderSize; |
118 | 113 |
119 for (const auto& table : tables) { | 114 for (const auto& table : tables) { |
120 size += TableEntrySize(table); | 115 size += TableEntrySize(table); |
121 } | 116 } |
122 | 117 |
123 // for collections only, collection tables | 118 // for collections only, collection tables |
124 if (font_collection.fonts.size() > 1) { | 119 if (font_collection.flavor == kTtcFontFlavor) { |
125 size += 4; // UInt32 Version of TTC Header | 120 size += 4; // UInt32 Version of TTC Header |
126 size += Size255UShort(font_collection.fonts.size()); // 255UInt16 numFonts | 121 size += Size255UShort(font_collection.fonts.size()); // 255UInt16 numFonts |
127 | 122 |
128 size += 4 * font_collection.fonts.size(); // UInt32 flavor for each | 123 size += 4 * font_collection.fonts.size(); // UInt32 flavor for each |
129 | 124 |
130 for (const auto& font : font_collection.fonts) { | 125 for (const auto& font : font_collection.fonts) { |
131 size += Size255UShort(font.tables.size()); // 255UInt16 numTables | 126 size += Size255UShort(font.tables.size()); // 255UInt16 numTables |
132 for (const auto& entry : font.tables) { | 127 for (const auto& entry : font.tables) { |
133 const Font::Table& table = entry.second; | 128 const Font::Table& table = entry.second; |
134 // no collection entry for xform table | 129 // no collection entry for xform table |
(...skipping 19 matching lines...) Expand all Loading... |
154 for (const auto& entry : font.tables) { | 149 for (const auto& entry : font.tables) { |
155 const Font::Table& table = entry.second; | 150 const Font::Table& table = entry.second; |
156 if (table.tag & 0x80808080) continue; // xform tables don't stay | 151 if (table.tag & 0x80808080) continue; // xform tables don't stay |
157 if (table.IsReused()) continue; // don't have to pay twice | 152 if (table.IsReused()) continue; // don't have to pay twice |
158 size += Round4(table.length); | 153 size += Round4(table.length); |
159 } | 154 } |
160 return size; | 155 return size; |
161 } | 156 } |
162 | 157 |
163 size_t ComputeUncompressedLength(const FontCollection& font_collection) { | 158 size_t ComputeUncompressedLength(const FontCollection& font_collection) { |
164 if (font_collection.fonts.size() == 1) { | 159 if (font_collection.flavor != kTtcFontFlavor) { |
165 return ComputeUncompressedLength(font_collection.fonts[0]); | 160 return ComputeUncompressedLength(font_collection.fonts[0]); |
166 } | 161 } |
167 size_t size = CollectionHeaderSize(font_collection.header_version, | 162 size_t size = CollectionHeaderSize(font_collection.header_version, |
168 font_collection.fonts.size()); | 163 font_collection.fonts.size()); |
169 for (const auto& font : font_collection.fonts) { | 164 for (const auto& font : font_collection.fonts) { |
170 size += ComputeUncompressedLength(font); | 165 size += ComputeUncompressedLength(font); |
171 } | 166 } |
172 return size; | 167 return size; |
173 } | 168 } |
174 | 169 |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 index_by_offset, total_compressed_length, compressed_metadata_buf_length); | 360 index_by_offset, total_compressed_length, compressed_metadata_buf_length); |
366 if (woff2_length > *result_length) { | 361 if (woff2_length > *result_length) { |
367 #ifdef FONT_COMPRESSION_BIN | 362 #ifdef FONT_COMPRESSION_BIN |
368 fprintf(stderr, "Result allocation was too small (%zd vs %zd bytes).\n", | 363 fprintf(stderr, "Result allocation was too small (%zd vs %zd bytes).\n", |
369 *result_length, woff2_length); | 364 *result_length, woff2_length); |
370 #endif | 365 #endif |
371 return FONT_COMPRESSION_FAILURE(); | 366 return FONT_COMPRESSION_FAILURE(); |
372 } | 367 } |
373 *result_length = woff2_length; | 368 *result_length = woff2_length; |
374 | 369 |
375 const Font& first_font = font_collection.fonts[0]; | |
376 size_t offset = 0; | 370 size_t offset = 0; |
377 | 371 |
378 // start of woff2 header (http://www.w3.org/TR/WOFF2/#woff20Header) | 372 // start of woff2 header (http://www.w3.org/TR/WOFF2/#woff20Header) |
379 StoreU32(kWoff2Signature, &offset, result); | 373 StoreU32(kWoff2Signature, &offset, result); |
380 if (font_collection.fonts.size() == 1) { | 374 if (font_collection.flavor != kTtcFontFlavor) { |
381 StoreU32(first_font.flavor, &offset, result); | 375 StoreU32(font_collection.fonts[0].flavor, &offset, result); |
382 } else { | 376 } else { |
383 StoreU32(kTtcFontFlavor, &offset, result); | 377 StoreU32(kTtcFontFlavor, &offset, result); |
384 } | 378 } |
385 StoreU32(woff2_length, &offset, result); | 379 StoreU32(woff2_length, &offset, result); |
386 Store16(tables.size(), &offset, result); | 380 Store16(tables.size(), &offset, result); |
387 Store16(0, &offset, result); // reserved | 381 Store16(0, &offset, result); // reserved |
388 // totalSfntSize | 382 // totalSfntSize |
389 StoreU32(ComputeUncompressedLength(font_collection), &offset, result); | 383 StoreU32(ComputeUncompressedLength(font_collection), &offset, result); |
390 StoreU32(total_compressed_length, &offset, result); // totalCompressedSize | 384 StoreU32(total_compressed_length, &offset, result); // totalCompressedSize |
391 | 385 |
392 // TODO(user): is always taking this from the first tables head OK? | 386 // Let's just all be v1.0 |
393 // font revision | 387 Store16(1, &offset, result); // majorVersion |
394 StoreBytes(first_font.FindTable(kHeadTableTag)->data + 4, 4, &offset, result); | 388 Store16(0, &offset, result); // minorVersion |
395 if (compressed_metadata_buf_length > 0) { | 389 if (compressed_metadata_buf_length > 0) { |
396 StoreU32(woff2_length - compressed_metadata_buf_length, | 390 StoreU32(woff2_length - compressed_metadata_buf_length, |
397 &offset, result); // metaOffset | 391 &offset, result); // metaOffset |
398 StoreU32(compressed_metadata_buf_length, &offset, result); // metaLength | 392 StoreU32(compressed_metadata_buf_length, &offset, result); // metaLength |
399 StoreU32(params.extended_metadata.length(), | 393 StoreU32(params.extended_metadata.length(), |
400 &offset, result); // metaOrigLength | 394 &offset, result); // metaOrigLength |
401 } else { | 395 } else { |
402 StoreU32(0, &offset, result); // metaOffset | 396 StoreU32(0, &offset, result); // metaOffset |
403 StoreU32(0, &offset, result); // metaLength | 397 StoreU32(0, &offset, result); // metaLength |
404 StoreU32(0, &offset, result); // metaOrigLength | 398 StoreU32(0, &offset, result); // metaOrigLength |
405 } | 399 } |
406 StoreU32(0, &offset, result); // privOffset | 400 StoreU32(0, &offset, result); // privOffset |
407 StoreU32(0, &offset, result); // privLength | 401 StoreU32(0, &offset, result); // privLength |
408 // end of woff2 header | 402 // end of woff2 header |
409 | 403 |
410 // table directory (http://www.w3.org/TR/WOFF2/#table_dir_format) | 404 // table directory (http://www.w3.org/TR/WOFF2/#table_dir_format) |
411 for (const auto& table : tables) { | 405 for (const auto& table : tables) { |
412 StoreTableEntry(table, &offset, result); | 406 StoreTableEntry(table, &offset, result); |
413 } | 407 } |
414 | 408 |
415 // for collections only, collection table directory | 409 // for collections only, collection table directory |
416 if (font_collection.fonts.size() > 1) { | 410 if (font_collection.flavor == kTtcFontFlavor) { |
417 StoreU32(font_collection.header_version, &offset, result); | 411 StoreU32(font_collection.header_version, &offset, result); |
418 Store255UShort(font_collection.fonts.size(), &offset, result); | 412 Store255UShort(font_collection.fonts.size(), &offset, result); |
419 for (const Font& font : font_collection.fonts) { | 413 for (const Font& font : font_collection.fonts) { |
420 | 414 |
421 uint16_t num_tables = 0; | 415 uint16_t num_tables = 0; |
422 for (const auto& entry : font.tables) { | 416 for (const auto& entry : font.tables) { |
423 const Font::Table& table = entry.second; | 417 const Font::Table& table = entry.second; |
424 if (table.tag & 0x80808080) continue; // don't write xform tables | 418 if (table.tag & 0x80808080) continue; // don't write xform tables |
425 num_tables++; | 419 num_tables++; |
426 } | 420 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
463 #ifdef FONT_COMPRESSION_BIN | 457 #ifdef FONT_COMPRESSION_BIN |
464 fprintf(stderr, "Mismatch between computed and actual length " | 458 fprintf(stderr, "Mismatch between computed and actual length " |
465 "(%zd vs %zd)\n", *result_length, offset); | 459 "(%zd vs %zd)\n", *result_length, offset); |
466 #endif | 460 #endif |
467 return FONT_COMPRESSION_FAILURE(); | 461 return FONT_COMPRESSION_FAILURE(); |
468 } | 462 } |
469 return true; | 463 return true; |
470 } | 464 } |
471 | 465 |
472 } // namespace woff2 | 466 } // namespace woff2 |
OLD | NEW |