OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ots.h" | 5 #include "ots.h" |
6 | 6 |
7 #include <sys/types.h> | 7 #include <sys/types.h> |
8 #include <zlib.h> | 8 #include <zlib.h> |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
11 #include <cstdlib> | 11 #include <cstdlib> |
12 #include <cstring> | 12 #include <cstring> |
13 #include <limits> | 13 #include <limits> |
14 #include <map> | 14 #include <map> |
15 #include <vector> | 15 #include <vector> |
16 | 16 |
| 17 #include "woff2.h" |
| 18 |
17 // The OpenType Font File | 19 // The OpenType Font File |
18 // http://www.microsoft.com/typography/otspec/cmap.htm | 20 // http://www.microsoft.com/typography/otspec/cmap.htm |
19 | 21 |
20 namespace { | 22 namespace { |
21 | 23 |
22 bool g_debug_output = true; | 24 bool g_debug_output = true; |
| 25 bool g_enable_woff2 = false; |
23 | 26 |
24 struct OpenTypeTable { | 27 struct OpenTypeTable { |
25 uint32_t tag; | 28 uint32_t tag; |
26 uint32_t chksum; | 29 uint32_t chksum; |
27 uint32_t offset; | 30 uint32_t offset; |
28 uint32_t length; | 31 uint32_t length; |
29 uint32_t uncompressed_length; | 32 uint32_t uncompressed_length; |
30 }; | 33 }; |
31 | 34 |
32 // Round a value up to the nearest multiple of 4. Don't round the value in the | |
33 // case that rounding up overflows. | |
34 template<typename T> T Round4(T value) { | |
35 if (std::numeric_limits<T>::max() - value < 3) { | |
36 return value; | |
37 } | |
38 return (value + 3) & ~3; | |
39 } | |
40 | |
41 bool CheckTag(uint32_t tag_value) { | 35 bool CheckTag(uint32_t tag_value) { |
42 for (unsigned i = 0; i < 4; ++i) { | 36 for (unsigned i = 0; i < 4; ++i) { |
43 const uint32_t check = tag_value & 0xff; | 37 const uint32_t check = tag_value & 0xff; |
44 if (check < 32 || check > 126) { | 38 if (check < 32 || check > 126) { |
45 return false; // non-ASCII character found. | 39 return false; // non-ASCII character found. |
46 } | 40 } |
47 tag_value >>= 8; | 41 tag_value >>= 8; |
48 } | 42 } |
49 return true; | 43 return true; |
50 } | 44 } |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 { "GSUB", ots::ots_gsub_parse, ots::ots_gsub_serialise, | 138 { "GSUB", ots::ots_gsub_parse, ots::ots_gsub_serialise, |
145 ots::ots_gsub_should_serialise, ots::ots_gsub_free, false }, | 139 ots::ots_gsub_should_serialise, ots::ots_gsub_free, false }, |
146 { "vhea", ots::ots_vhea_parse, ots::ots_vhea_serialise, | 140 { "vhea", ots::ots_vhea_parse, ots::ots_vhea_serialise, |
147 ots::ots_vhea_should_serialise, ots::ots_vhea_free, false }, | 141 ots::ots_vhea_should_serialise, ots::ots_vhea_free, false }, |
148 { "vmtx", ots::ots_vmtx_parse, ots::ots_vmtx_serialise, | 142 { "vmtx", ots::ots_vmtx_parse, ots::ots_vmtx_serialise, |
149 ots::ots_vmtx_should_serialise, ots::ots_vmtx_free, false }, | 143 ots::ots_vmtx_should_serialise, ots::ots_vmtx_free, false }, |
150 // TODO(bashi): Support mort, base, and jstf tables. | 144 // TODO(bashi): Support mort, base, and jstf tables. |
151 { 0, NULL, NULL, NULL, NULL, false }, | 145 { 0, NULL, NULL, NULL, NULL, false }, |
152 }; | 146 }; |
153 | 147 |
154 bool IsValidVersionTag(uint32_t tag) { | |
155 return tag == Tag("\x00\x01\x00\x00") || | |
156 // OpenType fonts with CFF data have 'OTTO' tag. | |
157 tag == Tag("OTTO") || | |
158 // Older Mac fonts might have 'true' or 'typ1' tag. | |
159 tag == Tag("true") || | |
160 tag == Tag("typ1"); | |
161 } | |
162 | |
163 bool ProcessGeneric(ots::OpenTypeFile *header, | 148 bool ProcessGeneric(ots::OpenTypeFile *header, |
164 uint32_t signature, | 149 uint32_t signature, |
165 ots::OTSStream *output, | 150 ots::OTSStream *output, |
166 const uint8_t *data, size_t length, | 151 const uint8_t *data, size_t length, |
167 const std::vector<OpenTypeTable>& tables, | 152 const std::vector<OpenTypeTable>& tables, |
168 ots::Buffer& file); | 153 ots::Buffer& file); |
169 | 154 |
170 bool ProcessTTF(ots::OpenTypeFile *header, | 155 bool ProcessTTF(ots::OpenTypeFile *header, |
171 ots::OTSStream *output, const uint8_t *data, size_t length) { | 156 ots::OTSStream *output, const uint8_t *data, size_t length) { |
172 ots::Buffer file(data, length); | 157 ots::Buffer file(data, length); |
173 | 158 |
174 // we disallow all files > 1GB in size for sanity. | 159 // we disallow all files > 1GB in size for sanity. |
175 if (length > 1024 * 1024 * 1024) { | 160 if (length > 1024 * 1024 * 1024) { |
176 return OTS_FAILURE(); | 161 return OTS_FAILURE(); |
177 } | 162 } |
178 | 163 |
179 if (!file.ReadTag(&header->version)) { | 164 if (!file.ReadTag(&header->version)) { |
180 return OTS_FAILURE(); | 165 return OTS_FAILURE(); |
181 } | 166 } |
182 if (!IsValidVersionTag(header->version)) { | 167 if (!ots::IsValidVersionTag(header->version)) { |
183 return OTS_FAILURE(); | 168 return OTS_FAILURE(); |
184 } | 169 } |
185 | 170 |
186 if (!file.ReadU16(&header->num_tables) || | 171 if (!file.ReadU16(&header->num_tables) || |
187 !file.ReadU16(&header->search_range) || | 172 !file.ReadU16(&header->search_range) || |
188 !file.ReadU16(&header->entry_selector) || | 173 !file.ReadU16(&header->entry_selector) || |
189 !file.ReadU16(&header->range_shift)) { | 174 !file.ReadU16(&header->range_shift)) { |
190 return OTS_FAILURE(); | 175 return OTS_FAILURE(); |
191 } | 176 } |
192 | 177 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 return OTS_FAILURE(); | 243 return OTS_FAILURE(); |
259 } | 244 } |
260 | 245 |
261 if (woff_tag != Tag("wOFF")) { | 246 if (woff_tag != Tag("wOFF")) { |
262 return OTS_FAILURE(); | 247 return OTS_FAILURE(); |
263 } | 248 } |
264 | 249 |
265 if (!file.ReadTag(&header->version)) { | 250 if (!file.ReadTag(&header->version)) { |
266 return OTS_FAILURE(); | 251 return OTS_FAILURE(); |
267 } | 252 } |
268 if (!IsValidVersionTag(header->version)) { | 253 if (!ots::IsValidVersionTag(header->version)) { |
269 return OTS_FAILURE(); | 254 return OTS_FAILURE(); |
270 } | 255 } |
271 | 256 |
272 header->search_range = 0; | 257 header->search_range = 0; |
273 header->entry_selector = 0; | 258 header->entry_selector = 0; |
274 header->range_shift = 0; | 259 header->range_shift = 0; |
275 | 260 |
276 uint32_t reported_length; | 261 uint32_t reported_length; |
277 if (!file.ReadU32(&reported_length) || length != reported_length) { | 262 if (!file.ReadU32(&reported_length) || length != reported_length) { |
278 return OTS_FAILURE(); | 263 return OTS_FAILURE(); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 for (unsigned i = 0; i < header->num_tables; ++i) { | 321 for (unsigned i = 0; i < header->num_tables; ++i) { |
337 OpenTypeTable table; | 322 OpenTypeTable table; |
338 if (!file.ReadTag(&table.tag) || | 323 if (!file.ReadTag(&table.tag) || |
339 !file.ReadU32(&table.offset) || | 324 !file.ReadU32(&table.offset) || |
340 !file.ReadU32(&table.length) || | 325 !file.ReadU32(&table.length) || |
341 !file.ReadU32(&table.uncompressed_length) || | 326 !file.ReadU32(&table.uncompressed_length) || |
342 !file.ReadU32(&table.chksum)) { | 327 !file.ReadU32(&table.chksum)) { |
343 return OTS_FAILURE(); | 328 return OTS_FAILURE(); |
344 } | 329 } |
345 | 330 |
346 total_sfnt_size += Round4(table.uncompressed_length); | 331 total_sfnt_size += ots::Round4(table.uncompressed_length); |
347 if (total_sfnt_size > std::numeric_limits<uint32_t>::max()) { | 332 if (total_sfnt_size > std::numeric_limits<uint32_t>::max()) { |
348 return OTS_FAILURE(); | 333 return OTS_FAILURE(); |
349 } | 334 } |
350 tables.push_back(table); | 335 tables.push_back(table); |
351 if (i == 0 || tables[first_index].offset > table.offset) | 336 if (i == 0 || tables[first_index].offset > table.offset) |
352 first_index = i; | 337 first_index = i; |
353 if (i == 0 || tables[last_index].offset < table.offset) | 338 if (i == 0 || tables[last_index].offset < table.offset) |
354 last_index = i; | 339 last_index = i; |
355 } | 340 } |
356 | 341 |
357 if (reported_total_sfnt_size != total_sfnt_size) { | 342 if (reported_total_sfnt_size != total_sfnt_size) { |
358 return OTS_FAILURE(); | 343 return OTS_FAILURE(); |
359 } | 344 } |
360 | 345 |
361 // Table data must follow immediately after the header. | 346 // Table data must follow immediately after the header. |
362 if (tables[first_index].offset != Round4(file.offset())) { | 347 if (tables[first_index].offset != ots::Round4(file.offset())) { |
363 return OTS_FAILURE(); | 348 return OTS_FAILURE(); |
364 } | 349 } |
365 | 350 |
366 if (tables[last_index].offset >= length || | 351 if (tables[last_index].offset >= length || |
367 length - tables[last_index].offset < tables[last_index].length) { | 352 length - tables[last_index].offset < tables[last_index].length) { |
368 return OTS_FAILURE(); | 353 return OTS_FAILURE(); |
369 } | 354 } |
370 // Blocks must follow immediately after the previous block. | 355 // Blocks must follow immediately after the previous block. |
371 // (Except for padding with a maximum of three null bytes) | 356 // (Except for padding with a maximum of three null bytes) |
372 uint64_t block_end = Round4( | 357 uint64_t block_end = ots::Round4( |
373 static_cast<uint64_t>(tables[last_index].offset) + | 358 static_cast<uint64_t>(tables[last_index].offset) + |
374 static_cast<uint64_t>(tables[last_index].length)); | 359 static_cast<uint64_t>(tables[last_index].length)); |
375 if (block_end > std::numeric_limits<uint32_t>::max()) { | 360 if (block_end > std::numeric_limits<uint32_t>::max()) { |
376 return OTS_FAILURE(); | 361 return OTS_FAILURE(); |
377 } | 362 } |
378 if (meta_offset) { | 363 if (meta_offset) { |
379 if (block_end != meta_offset) { | 364 if (block_end != meta_offset) { |
380 return OTS_FAILURE(); | 365 return OTS_FAILURE(); |
381 } | 366 } |
382 block_end = Round4(static_cast<uint64_t>(meta_offset) + | 367 block_end = ots::Round4(static_cast<uint64_t>(meta_offset) + |
383 static_cast<uint64_t>(meta_length)); | 368 static_cast<uint64_t>(meta_length)); |
384 if (block_end > std::numeric_limits<uint32_t>::max()) { | 369 if (block_end > std::numeric_limits<uint32_t>::max()) { |
385 return OTS_FAILURE(); | 370 return OTS_FAILURE(); |
386 } | 371 } |
387 } | 372 } |
388 if (priv_offset) { | 373 if (priv_offset) { |
389 if (block_end != priv_offset) { | 374 if (block_end != priv_offset) { |
390 return OTS_FAILURE(); | 375 return OTS_FAILURE(); |
391 } | 376 } |
392 block_end = Round4(static_cast<uint64_t>(priv_offset) + | 377 block_end = ots::Round4(static_cast<uint64_t>(priv_offset) + |
393 static_cast<uint64_t>(priv_length)); | 378 static_cast<uint64_t>(priv_length)); |
394 if (block_end > std::numeric_limits<uint32_t>::max()) { | 379 if (block_end > std::numeric_limits<uint32_t>::max()) { |
395 return OTS_FAILURE(); | 380 return OTS_FAILURE(); |
396 } | 381 } |
397 } | 382 } |
398 if (block_end != Round4(length)) { | 383 if (block_end != ots::Round4(length)) { |
399 return OTS_FAILURE(); | 384 return OTS_FAILURE(); |
400 } | 385 } |
401 | 386 |
402 return ProcessGeneric(header, woff_tag, output, data, length, tables, file); | 387 return ProcessGeneric(header, woff_tag, output, data, length, tables, file); |
403 } | 388 } |
404 | 389 |
| 390 bool ProcessWOFF2(ots::OpenTypeFile *header, |
| 391 ots::OTSStream *output, const uint8_t *data, size_t length) { |
| 392 size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length); |
| 393 if (decompressed_size == 0) { |
| 394 return OTS_FAILURE(); |
| 395 } |
| 396 // decompressed font must be <= 30MB |
| 397 if (decompressed_size > 30 * 1024 * 1024) { |
| 398 return OTS_FAILURE(); |
| 399 } |
| 400 |
| 401 std::vector<uint8_t> decompressed_buffer(decompressed_size); |
| 402 if (!ots::ConvertWOFF2ToTTF(&decompressed_buffer[0], decompressed_size, |
| 403 data, length)) { |
| 404 return OTS_FAILURE(); |
| 405 } |
| 406 return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size); |
| 407 } |
| 408 |
405 bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature, | 409 bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature, |
406 ots::OTSStream *output, | 410 ots::OTSStream *output, |
407 const uint8_t *data, size_t length, | 411 const uint8_t *data, size_t length, |
408 const std::vector<OpenTypeTable>& tables, | 412 const std::vector<OpenTypeTable>& tables, |
409 ots::Buffer& file) { | 413 ots::Buffer& file) { |
410 const size_t data_offset = file.offset(); | 414 const size_t data_offset = file.offset(); |
411 | 415 |
412 uint32_t uncompressed_sum = 0; | 416 uint32_t uncompressed_sum = 0; |
413 | 417 |
414 for (unsigned i = 0; i < header->num_tables; ++i) { | 418 for (unsigned i = 0; i < header->num_tables; ++i) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
460 return OTS_FAILURE(); | 464 return OTS_FAILURE(); |
461 } | 465 } |
462 | 466 |
463 uncompressed_sum += tables[i].uncompressed_length; | 467 uncompressed_sum += tables[i].uncompressed_length; |
464 } | 468 } |
465 // since we required that the file be < 1GB in length, and that the table | 469 // since we required that the file be < 1GB in length, and that the table |
466 // length is < 1GB, the following addtion doesn't overflow | 470 // length is < 1GB, the following addtion doesn't overflow |
467 uint32_t end_byte = tables[i].offset + tables[i].length; | 471 uint32_t end_byte = tables[i].offset + tables[i].length; |
468 // Tables in the WOFF file must be aligned 4-byte boundary. | 472 // Tables in the WOFF file must be aligned 4-byte boundary. |
469 if (signature == Tag("wOFF")) { | 473 if (signature == Tag("wOFF")) { |
470 end_byte = Round4(end_byte); | 474 end_byte = ots::Round4(end_byte); |
471 } | 475 } |
472 if (!end_byte || end_byte > length) { | 476 if (!end_byte || end_byte > length) { |
473 return OTS_FAILURE(); | 477 return OTS_FAILURE(); |
474 } | 478 } |
475 } | 479 } |
476 | 480 |
477 // All decompressed tables uncompressed must be <= 30MB. | 481 // All decompressed tables uncompressed must be <= 30MB. |
478 if (uncompressed_sum > 30 * 1024 * 1024) { | 482 if (uncompressed_sum > 30 * 1024 * 1024) { |
479 return OTS_FAILURE(); | 483 return OTS_FAILURE(); |
480 } | 484 } |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
672 return OTS_FAILURE(); | 676 return OTS_FAILURE(); |
673 } | 677 } |
674 | 678 |
675 return true; | 679 return true; |
676 } | 680 } |
677 | 681 |
678 } // namespace | 682 } // namespace |
679 | 683 |
680 namespace ots { | 684 namespace ots { |
681 | 685 |
| 686 bool IsValidVersionTag(uint32_t tag) { |
| 687 return tag == Tag("\x00\x01\x00\x00") || |
| 688 // OpenType fonts with CFF data have 'OTTO' tag. |
| 689 tag == Tag("OTTO") || |
| 690 // Older Mac fonts might have 'true' or 'typ1' tag. |
| 691 tag == Tag("true") || |
| 692 tag == Tag("typ1"); |
| 693 } |
| 694 |
682 void DisableDebugOutput() { | 695 void DisableDebugOutput() { |
683 g_debug_output = false; | 696 g_debug_output = false; |
684 } | 697 } |
685 | 698 |
| 699 void EnableWOFF2() { |
| 700 g_enable_woff2 = true; |
| 701 } |
| 702 |
686 bool Process(OTSStream *output, const uint8_t *data, size_t length) { | 703 bool Process(OTSStream *output, const uint8_t *data, size_t length) { |
687 OpenTypeFile header; | 704 OpenTypeFile header; |
688 if (length < 4) { | 705 if (length < 4) { |
689 return OTS_FAILURE(); | 706 return OTS_FAILURE(); |
690 } | 707 } |
691 | 708 |
692 bool result; | 709 bool result; |
693 if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') { | 710 if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') { |
694 result = ProcessWOFF(&header, output, data, length); | 711 result = ProcessWOFF(&header, output, data, length); |
| 712 } else if (g_enable_woff2 && |
| 713 data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && |
| 714 data[3] == '2') { |
| 715 result = ProcessWOFF2(&header, output, data, length); |
695 } else { | 716 } else { |
696 result = ProcessTTF(&header, output, data, length); | 717 result = ProcessTTF(&header, output, data, length); |
697 } | 718 } |
698 | 719 |
699 for (unsigned i = 0; ; ++i) { | 720 for (unsigned i = 0; ; ++i) { |
700 if (table_parsers[i].parse == NULL) break; | 721 if (table_parsers[i].parse == NULL) break; |
701 table_parsers[i].free(&header); | 722 table_parsers[i].free(&header); |
702 } | 723 } |
703 return result; | 724 return result; |
704 } | 725 } |
(...skipping 14 matching lines...) Expand all Loading... |
719 va_start(va, format); | 740 va_start(va, format); |
720 std::vfprintf(stderr, format, va); | 741 std::vfprintf(stderr, format, va); |
721 va_end(va); | 742 va_end(va); |
722 std::fprintf(stderr, "\n"); | 743 std::fprintf(stderr, "\n"); |
723 std::fflush(stderr); | 744 std::fflush(stderr); |
724 } | 745 } |
725 } | 746 } |
726 #endif | 747 #endif |
727 | 748 |
728 } // namespace ots | 749 } // namespace ots |
OLD | NEW |