Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(81)

Side by Side Diff: src/ots.cc

Issue 13918002: [OTS] Integrate WOFF 2.0 algorithm into OTS (Closed) Base URL: http://ots.googlecode.com/svn/trunk/
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ots.h ('k') | src/woff2.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/ots.h ('k') | src/woff2.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698