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 "./encode.h" |
26 #include "./buffer.h" | 27 #include "./buffer.h" |
27 #include "./encode.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 namespace woff2 { | 38 namespace woff2 { |
38 | 39 |
39 namespace { | 40 namespace { |
40 | 41 |
| 42 |
41 using std::string; | 43 using std::string; |
42 using std::vector; | 44 using std::vector; |
43 | 45 |
44 | 46 |
45 const size_t kWoff2HeaderSize = 48; | 47 const size_t kWoff2HeaderSize = 48; |
46 const size_t kWoff2EntrySize = 20; | 48 const size_t kWoff2EntrySize = 20; |
47 | 49 |
| 50 |
48 bool Compress(const uint8_t* data, const size_t len, | 51 bool Compress(const uint8_t* data, const size_t len, |
49 uint8_t* result, uint32_t* result_len, | 52 uint8_t* result, uint32_t* result_len, |
50 brotli::BrotliParams::Mode mode, int quality) { | 53 brotli::BrotliParams::Mode mode, int quality) { |
51 size_t compressed_len = *result_len; | 54 size_t compressed_len = *result_len; |
52 brotli::BrotliParams params; | 55 brotli::BrotliParams params; |
53 params.mode = mode; | 56 params.mode = mode; |
54 params.quality = quality; | 57 params.quality = quality; |
55 if (brotli::BrotliCompressBuffer(params, len, data, &compressed_len, result) | 58 if (brotli::BrotliCompressBuffer(params, len, data, &compressed_len, result) |
56 == 0) { | 59 == 0) { |
57 return false; | 60 return false; |
(...skipping 17 matching lines...) Expand all Loading... |
75 } | 78 } |
76 | 79 |
77 int KnownTableIndex(uint32_t tag) { | 80 int KnownTableIndex(uint32_t tag) { |
78 for (int i = 0; i < 63; ++i) { | 81 for (int i = 0; i < 63; ++i) { |
79 if (tag == kKnownTags[i]) return i; | 82 if (tag == kKnownTags[i]) return i; |
80 } | 83 } |
81 return 63; | 84 return 63; |
82 } | 85 } |
83 | 86 |
84 void StoreTableEntry(const Table& table, size_t* offset, uint8_t* dst) { | 87 void StoreTableEntry(const Table& table, size_t* offset, uint8_t* dst) { |
85 uint8_t flag_byte = KnownTableIndex(table.tag); | 88 uint8_t flag_byte = (table.flags & 0xC0) | KnownTableIndex(table.tag); |
86 dst[(*offset)++] = flag_byte; | 89 dst[(*offset)++] = flag_byte; |
87 // The index here is treated as a set of flag bytes because | 90 // The index here is treated as a set of flag bytes because |
88 // bits 6 and 7 of the byte are reserved for future use as flags. | 91 // bits 6 and 7 of the byte are reserved for future use as flags. |
89 // 0x3f or 63 means an arbitrary table tag. | 92 // 0x3f or 63 means an arbitrary table tag. |
90 if ((flag_byte & 0x3f) == 0x3f) { | 93 if ((flag_byte & 0x3f) == 0x3f) { |
91 StoreU32(table.tag, offset, dst); | 94 StoreU32(table.tag, offset, dst); |
92 } | 95 } |
93 StoreBase128(table.src_length, offset, dst); | 96 StoreBase128(table.src_length, offset, dst); |
94 if ((table.flags & kWoff2FlagsTransform) != 0) { | 97 if ((table.flags & kWoff2FlagsTransform) != 0) { |
95 StoreBase128(table.transform_length, offset, dst); | 98 StoreBase128(table.transform_length, offset, dst); |
96 } | 99 } |
97 } | 100 } |
98 | 101 |
99 size_t TableEntrySize(const Table& table) { | 102 size_t TableEntrySize(const Table& table) { |
100 uint8_t flag_byte = KnownTableIndex(table.tag); | 103 uint8_t flag_byte = KnownTableIndex(table.tag); |
101 size_t size = ((flag_byte & 0x3f) != 0x3f) ? 1 : 5; | 104 size_t size = ((flag_byte & 0x3f) != 0x3f) ? 1 : 5; |
102 size += Base128Size(table.src_length); | 105 size += Base128Size(table.src_length); |
103 if ((table.flags & kWoff2FlagsTransform) != 0) { | 106 if ((table.flags & kWoff2FlagsTransform) != 0) { |
104 size += Base128Size(table.transform_length); | 107 size += Base128Size(table.transform_length); |
105 } | 108 } |
106 return size; | 109 return size; |
107 } | 110 } |
108 | 111 |
109 size_t ComputeWoff2Length(const FontCollection& font_collection, | 112 size_t ComputeWoff2Length(const FontCollection& font_collection, |
110 const std::vector<Table>& tables, | 113 const std::vector<Table>& tables, |
111 std::map<uint32_t, uint16_t> index_by_offset, | 114 std::map<uint32_t, uint16_t> index_by_offset, |
| 115 size_t compressed_data_length, |
112 size_t extended_metadata_length) { | 116 size_t extended_metadata_length) { |
113 size_t size = kWoff2HeaderSize; | 117 size_t size = kWoff2HeaderSize; |
114 | 118 |
115 for (const auto& table : tables) { | 119 for (const auto& table : tables) { |
116 size += TableEntrySize(table); | 120 size += TableEntrySize(table); |
117 } | 121 } |
118 | 122 |
119 // for collections only, collection tables | 123 // for collections only, collection tables |
120 if (font_collection.fonts.size() > 1) { | 124 if (font_collection.fonts.size() > 1) { |
121 size += 4; // UInt32 Version of TTC Header | 125 size += 4; // UInt32 Version of TTC Header |
122 size += Size255UShort(font_collection.fonts.size()); // 255UInt16 numFonts | 126 size += Size255UShort(font_collection.fonts.size()); // 255UInt16 numFonts |
123 | 127 |
124 size += 4 * font_collection.fonts.size(); // UInt32 flavor for each | 128 size += 4 * font_collection.fonts.size(); // UInt32 flavor for each |
125 | 129 |
126 for (const auto& font : font_collection.fonts) { | 130 for (const auto& font : font_collection.fonts) { |
127 size += Size255UShort(font.tables.size()); // 255UInt16 numTables | 131 size += Size255UShort(font.tables.size()); // 255UInt16 numTables |
128 for (const auto& entry : font.tables) { | 132 for (const auto& entry : font.tables) { |
129 const Font::Table& table = entry.second; | 133 const Font::Table& table = entry.second; |
130 // no collection entry for xform table | 134 // no collection entry for xform table |
131 if (table.tag & 0x80808080) continue; | 135 if (table.tag & 0x80808080) continue; |
132 | 136 |
133 uint16_t table_index = index_by_offset[table.offset]; | 137 uint16_t table_index = index_by_offset[table.offset]; |
134 size += Size255UShort(table_index); // 255UInt16 index entry | 138 size += Size255UShort(table_index); // 255UInt16 index entry |
135 } | 139 } |
136 } | 140 } |
137 } | 141 } |
138 | 142 |
139 // compressed data | 143 // compressed data |
140 for (const auto& table : tables) { | 144 size += compressed_data_length; |
141 size += table.dst_length; | 145 size = Round4(size); |
142 size = Round4(size); | |
143 } | |
144 | 146 |
145 size += extended_metadata_length; | 147 size += extended_metadata_length; |
146 return size; | 148 return size; |
147 } | 149 } |
148 | 150 |
149 size_t ComputeTTFLength(const std::vector<Table>& tables) { | 151 size_t ComputeTTFLength(const std::vector<Table>& tables) { |
150 size_t size = 12 + 16 * tables.size(); // sfnt header | 152 size_t size = 12 + 16 * tables.size(); // sfnt header |
151 for (const auto& table : tables) { | 153 for (const auto& table : tables) { |
152 size += Round4(table.src_length); | 154 size += Round4(table.src_length); |
153 } | 155 } |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 } | 212 } |
211 | 213 |
212 uint32_t CompressedBufferSize(uint32_t original_size) { | 214 uint32_t CompressedBufferSize(uint32_t original_size) { |
213 return 1.2 * original_size + 10240; | 215 return 1.2 * original_size + 10240; |
214 } | 216 } |
215 | 217 |
216 bool TransformFontCollection(FontCollection* font_collection) { | 218 bool TransformFontCollection(FontCollection* font_collection) { |
217 for (auto& font : font_collection->fonts) { | 219 for (auto& font : font_collection->fonts) { |
218 if (!TransformGlyfAndLocaTables(&font)) { | 220 if (!TransformGlyfAndLocaTables(&font)) { |
219 #ifdef FONT_COMPRESSION_BIN | 221 #ifdef FONT_COMPRESSION_BIN |
220 fprintf(stderr, "Font transformation failed.\n"); | 222 fprintf(stderr, "glyf/loca transformation failed.\n"); |
221 #endif | 223 #endif |
222 return FONT_COMPRESSION_FAILURE(); | 224 return FONT_COMPRESSION_FAILURE(); |
223 } | 225 } |
224 } | 226 } |
225 | 227 |
226 return true; | 228 return true; |
227 } | 229 } |
228 | 230 |
229 bool ConvertTTFToWOFF2(const uint8_t *data, size_t length, | 231 bool ConvertTTFToWOFF2(const uint8_t *data, size_t length, |
230 uint8_t *result, size_t *result_length) { | 232 uint8_t *result, size_t *result_length) { |
(...skipping 10 matching lines...) Expand all Loading... |
241 #ifdef FONT_COMPRESSION_BIN | 243 #ifdef FONT_COMPRESSION_BIN |
242 fprintf(stderr, "Parsing of the input font failed.\n"); | 244 fprintf(stderr, "Parsing of the input font failed.\n"); |
243 #endif | 245 #endif |
244 return FONT_COMPRESSION_FAILURE(); | 246 return FONT_COMPRESSION_FAILURE(); |
245 } | 247 } |
246 | 248 |
247 if (!NormalizeFontCollection(&font_collection)) { | 249 if (!NormalizeFontCollection(&font_collection)) { |
248 return FONT_COMPRESSION_FAILURE(); | 250 return FONT_COMPRESSION_FAILURE(); |
249 } | 251 } |
250 | 252 |
251 if (!TransformFontCollection(&font_collection)) { | 253 if (params.allow_transforms && !TransformFontCollection(&font_collection)) { |
252 return FONT_COMPRESSION_FAILURE(); | 254 return FONT_COMPRESSION_FAILURE(); |
| 255 } else { |
| 256 // glyf/loca use 11 to flag "not transformed" |
| 257 for (auto& font : font_collection.fonts) { |
| 258 Font::Table* glyf_table = font.FindTable(kGlyfTableTag); |
| 259 Font::Table* loca_table = font.FindTable(kLocaTableTag); |
| 260 if (glyf_table) { |
| 261 glyf_table->flag_byte |= 0xc0; |
| 262 } |
| 263 if (loca_table) { |
| 264 loca_table->flag_byte |= 0xc0; |
| 265 } |
| 266 } |
253 } | 267 } |
254 | 268 |
255 // Although the compressed size of each table in the final woff2 file won't | 269 // Although the compressed size of each table in the final woff2 file won't |
256 // be larger than its transform_length, we have to allocate a large enough | 270 // be larger than its transform_length, we have to allocate a large enough |
257 // buffer for the compressor, since the compressor can potentially increase | 271 // buffer for the compressor, since the compressor can potentially increase |
258 // the size. If the compressor overflows this, it should return false and | 272 // the size. If the compressor overflows this, it should return false and |
259 // then this function will also return false. | 273 // then this function will also return false. |
260 | 274 |
261 size_t total_transform_length = 0; | 275 size_t total_transform_length = 0; |
262 for (const auto& font : font_collection.fonts) { | 276 for (const auto& font : font_collection.fonts) { |
(...skipping 21 matching lines...) Expand all Loading... |
284 if (!Woff2Compress(transform_buf.data(), total_transform_length, | 298 if (!Woff2Compress(transform_buf.data(), total_transform_length, |
285 &compression_buf[0], | 299 &compression_buf[0], |
286 &total_compressed_length, | 300 &total_compressed_length, |
287 params.brotli_quality)) { | 301 params.brotli_quality)) { |
288 #ifdef FONT_COMPRESSION_BIN | 302 #ifdef FONT_COMPRESSION_BIN |
289 fprintf(stderr, "Compression of combined table failed.\n"); | 303 fprintf(stderr, "Compression of combined table failed.\n"); |
290 #endif | 304 #endif |
291 return FONT_COMPRESSION_FAILURE(); | 305 return FONT_COMPRESSION_FAILURE(); |
292 } | 306 } |
293 | 307 |
| 308 #ifdef FONT_COMPRESSION_BIN |
| 309 fprintf(stderr, "Compressed %zu to %u.\n", total_transform_length, |
| 310 total_compressed_length); |
| 311 #endif |
| 312 |
294 // Compress the extended metadata | 313 // Compress the extended metadata |
295 // TODO(user): how does this apply to collections | 314 // TODO(user): how does this apply to collections |
296 uint32_t compressed_metadata_buf_length = | 315 uint32_t compressed_metadata_buf_length = |
297 CompressedBufferSize(params.extended_metadata.length()); | 316 CompressedBufferSize(params.extended_metadata.length()); |
298 std::vector<uint8_t> compressed_metadata_buf(compressed_metadata_buf_length); | 317 std::vector<uint8_t> compressed_metadata_buf(compressed_metadata_buf_length); |
299 | 318 |
300 if (params.extended_metadata.length() > 0) { | 319 if (params.extended_metadata.length() > 0) { |
301 if (!TextCompress((const uint8_t*)params.extended_metadata.data(), | 320 if (!TextCompress((const uint8_t*)params.extended_metadata.data(), |
302 params.extended_metadata.length(), | 321 params.extended_metadata.length(), |
303 compressed_metadata_buf.data(), | 322 compressed_metadata_buf.data(), |
(...skipping 20 matching lines...) Expand all Loading... |
324 } | 343 } |
325 | 344 |
326 if (index_by_offset.find(src_table.offset) == index_by_offset.end()) { | 345 if (index_by_offset.find(src_table.offset) == index_by_offset.end()) { |
327 index_by_offset[src_table.offset] = tables.size(); | 346 index_by_offset[src_table.offset] = tables.size(); |
328 } else { | 347 } else { |
329 return false; | 348 return false; |
330 } | 349 } |
331 | 350 |
332 Table table; | 351 Table table; |
333 table.tag = src_table.tag; | 352 table.tag = src_table.tag; |
334 table.flags = 0; | 353 table.flags = src_table.flag_byte; |
335 table.src_length = src_table.length; | 354 table.src_length = src_table.length; |
336 table.transform_length = src_table.length; | 355 table.transform_length = src_table.length; |
337 const uint8_t* transformed_data = src_table.data; | 356 const uint8_t* transformed_data = src_table.data; |
338 const Font::Table* transformed_table = | 357 const Font::Table* transformed_table = |
339 font.FindTable(src_table.tag ^ 0x80808080); | 358 font.FindTable(src_table.tag ^ 0x80808080); |
340 if (transformed_table != NULL) { | 359 if (transformed_table != NULL) { |
| 360 table.flags = transformed_table->flag_byte; |
341 table.flags |= kWoff2FlagsTransform; | 361 table.flags |= kWoff2FlagsTransform; |
342 table.transform_length = transformed_table->length; | 362 table.transform_length = transformed_table->length; |
343 transformed_data = transformed_table->data; | 363 transformed_data = transformed_table->data; |
344 } | 364 |
345 if (tables.empty()) { | |
346 table.dst_length = total_compressed_length; | |
347 table.dst_data = &compression_buf[0]; | |
348 } else { | |
349 table.dst_length = 0; | |
350 table.dst_data = NULL; | |
351 } | 365 } |
352 tables.push_back(table); | 366 tables.push_back(table); |
353 } | 367 } |
354 } | 368 } |
355 | 369 |
356 size_t woff2_length = ComputeWoff2Length(font_collection, tables, | 370 size_t woff2_length = ComputeWoff2Length(font_collection, tables, |
357 index_by_offset, compressed_metadata_buf_length); | 371 index_by_offset, total_compressed_length, compressed_metadata_buf_length); |
358 if (woff2_length > *result_length) { | 372 if (woff2_length > *result_length) { |
359 #ifdef FONT_COMPRESSION_BIN | 373 #ifdef FONT_COMPRESSION_BIN |
360 fprintf(stderr, "Result allocation was too small (%zd vs %zd bytes).\n", | 374 fprintf(stderr, "Result allocation was too small (%zd vs %zd bytes).\n", |
361 *result_length, woff2_length); | 375 *result_length, woff2_length); |
362 #endif | 376 #endif |
363 return FONT_COMPRESSION_FAILURE(); | 377 return FONT_COMPRESSION_FAILURE(); |
364 } | 378 } |
365 *result_length = woff2_length; | 379 *result_length = woff2_length; |
366 | 380 |
367 const Font& first_font = font_collection.fonts[0]; | 381 const Font& first_font = font_collection.fonts[0]; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 } | 451 } |
438 uint16_t index = index_by_offset[table_offset]; | 452 uint16_t index = index_by_offset[table_offset]; |
439 Store255UShort(index, &offset, result); | 453 Store255UShort(index, &offset, result); |
440 | 454 |
441 } | 455 } |
442 | 456 |
443 } | 457 } |
444 } | 458 } |
445 | 459 |
446 // compressed data format (http://www.w3.org/TR/WOFF2/#table_format) | 460 // compressed data format (http://www.w3.org/TR/WOFF2/#table_format) |
447 for (const auto& table : tables) { | 461 |
448 StoreBytes(table.dst_data, table.dst_length, &offset, result); | 462 StoreBytes(&compression_buf[0], total_compressed_length, &offset, result); |
449 offset = Round4(offset); | 463 offset = Round4(offset); |
450 } | 464 |
451 StoreBytes(compressed_metadata_buf.data(), compressed_metadata_buf_length, | 465 StoreBytes(compressed_metadata_buf.data(), compressed_metadata_buf_length, |
452 &offset, result); | 466 &offset, result); |
453 | 467 |
454 if (*result_length != offset) { | 468 if (*result_length != offset) { |
455 #ifdef FONT_COMPRESSION_BIN | 469 #ifdef FONT_COMPRESSION_BIN |
456 fprintf(stderr, "Mismatch between computed and actual length " | 470 fprintf(stderr, "Mismatch between computed and actual length " |
457 "(%zd vs %zd)\n", *result_length, offset); | 471 "(%zd vs %zd)\n", *result_length, offset); |
458 #endif | 472 #endif |
459 return FONT_COMPRESSION_FAILURE(); | 473 return FONT_COMPRESSION_FAILURE(); |
460 } | 474 } |
461 return true; | 475 return true; |
462 } | 476 } |
463 | 477 |
464 } // namespace woff2 | 478 } // namespace woff2 |
OLD | NEW |