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> |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 for (unsigned i = 0; i < 4; ++i) { | 42 for (unsigned i = 0; i < 4; ++i) { |
43 const uint32_t check = tag_value & 0xff; | 43 const uint32_t check = tag_value & 0xff; |
44 if (check < 32 || check > 126) { | 44 if (check < 32 || check > 126) { |
45 return false; // non-ASCII character found. | 45 return false; // non-ASCII character found. |
46 } | 46 } |
47 tag_value >>= 8; | 47 tag_value >>= 8; |
48 } | 48 } |
49 return true; | 49 return true; |
50 } | 50 } |
51 | 51 |
| 52 uint32_t Tag(const char *tag_str) { |
| 53 uint32_t ret; |
| 54 std::memcpy(&ret, tag_str, 4); |
| 55 return ret; |
| 56 } |
| 57 |
52 struct OutputTable { | 58 struct OutputTable { |
53 uint32_t tag; | 59 uint32_t tag; |
54 size_t offset; | 60 size_t offset; |
55 size_t length; | 61 size_t length; |
56 uint32_t chksum; | 62 uint32_t chksum; |
57 | 63 |
58 static bool SortByTag(const OutputTable& a, const OutputTable& b) { | 64 static bool SortByTag(const OutputTable& a, const OutputTable& b) { |
59 const uint32_t atag = ntohl(a.tag); | 65 const uint32_t atag = ntohl(a.tag); |
60 const uint32_t btag = ntohl(b.tag); | 66 const uint32_t btag = ntohl(b.tag); |
61 return atag < btag; | 67 return atag < btag; |
(...skipping 12 matching lines...) Expand all Loading... |
74 uint8_t* Allocate(size_t length) { | 80 uint8_t* Allocate(size_t length) { |
75 uint8_t* p = new uint8_t[length]; | 81 uint8_t* p = new uint8_t[length]; |
76 hunks_.push_back(p); | 82 hunks_.push_back(p); |
77 return p; | 83 return p; |
78 } | 84 } |
79 | 85 |
80 private: | 86 private: |
81 std::vector<uint8_t*> hunks_; | 87 std::vector<uint8_t*> hunks_; |
82 }; | 88 }; |
83 | 89 |
84 // Use a macro instead of a function because gcc 4.4.3 creates static | |
85 // initializers in that case. | |
86 #if defined(__BIG_ENDIAN__) || defined(_BIG_ENDIAN) | |
87 #define TAG(d, c, b, a) (a | (b << 8) | (c << 16) | (d << 24)) | |
88 #else | |
89 #define TAG(a, b, c, d) (a | (b << 8) | (c << 16) | (d << 24)) | |
90 #endif | |
91 | |
92 const struct { | 90 const struct { |
93 uint32_t tag; | 91 const char* tag; |
94 bool (*parse)(ots::OpenTypeFile *otf, const uint8_t *data, size_t length); | 92 bool (*parse)(ots::OpenTypeFile *otf, const uint8_t *data, size_t length); |
95 bool (*serialise)(ots::OTSStream *out, ots::OpenTypeFile *file); | 93 bool (*serialise)(ots::OTSStream *out, ots::OpenTypeFile *file); |
96 bool (*should_serialise)(ots::OpenTypeFile *file); | 94 bool (*should_serialise)(ots::OpenTypeFile *file); |
97 void (*free)(ots::OpenTypeFile *file); | 95 void (*free)(ots::OpenTypeFile *file); |
98 bool required; | 96 bool required; |
99 } table_parsers[] = { | 97 } table_parsers[] = { |
100 { TAG('m', 'a', 'x', 'p'), ots::ots_maxp_parse, ots::ots_maxp_serialise, | 98 { "maxp", ots::ots_maxp_parse, ots::ots_maxp_serialise, |
101 ots::ots_maxp_should_serialise, ots::ots_maxp_free, true }, | 99 ots::ots_maxp_should_serialise, ots::ots_maxp_free, true }, |
102 { TAG('h', 'e', 'a', 'd'), ots::ots_head_parse, ots::ots_head_serialise, | 100 { "head", ots::ots_head_parse, ots::ots_head_serialise, |
103 ots::ots_head_should_serialise, ots::ots_head_free, true }, | 101 ots::ots_head_should_serialise, ots::ots_head_free, true }, |
104 { TAG('O', 'S', '/', '2'), ots::ots_os2_parse, ots::ots_os2_serialise, | 102 { "OS/2", ots::ots_os2_parse, ots::ots_os2_serialise, |
105 ots::ots_os2_should_serialise, ots::ots_os2_free, true }, | 103 ots::ots_os2_should_serialise, ots::ots_os2_free, true }, |
106 { TAG('c', 'm', 'a', 'p'), ots::ots_cmap_parse, ots::ots_cmap_serialise, | 104 { "cmap", ots::ots_cmap_parse, ots::ots_cmap_serialise, |
107 ots::ots_cmap_should_serialise, ots::ots_cmap_free, true }, | 105 ots::ots_cmap_should_serialise, ots::ots_cmap_free, true }, |
108 { TAG('h', 'h', 'e', 'a'), ots::ots_hhea_parse, ots::ots_hhea_serialise, | 106 { "hhea", ots::ots_hhea_parse, ots::ots_hhea_serialise, |
109 ots::ots_hhea_should_serialise, ots::ots_hhea_free, true }, | 107 ots::ots_hhea_should_serialise, ots::ots_hhea_free, true }, |
110 { TAG('h', 'm', 't', 'x'), ots::ots_hmtx_parse, ots::ots_hmtx_serialise, | 108 { "hmtx", ots::ots_hmtx_parse, ots::ots_hmtx_serialise, |
111 ots::ots_hmtx_should_serialise, ots::ots_hmtx_free, true }, | 109 ots::ots_hmtx_should_serialise, ots::ots_hmtx_free, true }, |
112 { TAG('n', 'a', 'm', 'e'), ots::ots_name_parse, ots::ots_name_serialise, | 110 { "name", ots::ots_name_parse, ots::ots_name_serialise, |
113 ots::ots_name_should_serialise, ots::ots_name_free, true }, | 111 ots::ots_name_should_serialise, ots::ots_name_free, true }, |
114 { TAG('p', 'o', 's', 't'), ots::ots_post_parse, ots::ots_post_serialise, | 112 { "post", ots::ots_post_parse, ots::ots_post_serialise, |
115 ots::ots_post_should_serialise, ots::ots_post_free, true }, | 113 ots::ots_post_should_serialise, ots::ots_post_free, true }, |
116 { TAG('l', 'o', 'c', 'a'), ots::ots_loca_parse, ots::ots_loca_serialise, | 114 { "loca", ots::ots_loca_parse, ots::ots_loca_serialise, |
117 ots::ots_loca_should_serialise, ots::ots_loca_free, false }, | 115 ots::ots_loca_should_serialise, ots::ots_loca_free, false }, |
118 { TAG('g', 'l', 'y', 'f'), ots::ots_glyf_parse, ots::ots_glyf_serialise, | 116 { "glyf", ots::ots_glyf_parse, ots::ots_glyf_serialise, |
119 ots::ots_glyf_should_serialise, ots::ots_glyf_free, false }, | 117 ots::ots_glyf_should_serialise, ots::ots_glyf_free, false }, |
120 { TAG('C', 'F', 'F', ' '), ots::ots_cff_parse, ots::ots_cff_serialise, | 118 { "CFF ", ots::ots_cff_parse, ots::ots_cff_serialise, |
121 ots::ots_cff_should_serialise, ots::ots_cff_free, false }, | 119 ots::ots_cff_should_serialise, ots::ots_cff_free, false }, |
122 { TAG('V', 'D', 'M', 'X'), ots::ots_vdmx_parse, ots::ots_vdmx_serialise, | 120 { "VDMX", ots::ots_vdmx_parse, ots::ots_vdmx_serialise, |
123 ots::ots_vdmx_should_serialise, ots::ots_vdmx_free, false }, | 121 ots::ots_vdmx_should_serialise, ots::ots_vdmx_free, false }, |
124 { TAG('h', 'd', 'm', 'x'), ots::ots_hdmx_parse, ots::ots_hdmx_serialise, | 122 { "hdmx", ots::ots_hdmx_parse, ots::ots_hdmx_serialise, |
125 ots::ots_hdmx_should_serialise, ots::ots_hdmx_free, false }, | 123 ots::ots_hdmx_should_serialise, ots::ots_hdmx_free, false }, |
126 { TAG('g', 'a', 's', 'p'), ots::ots_gasp_parse, ots::ots_gasp_serialise, | 124 { "gasp", ots::ots_gasp_parse, ots::ots_gasp_serialise, |
127 ots::ots_gasp_should_serialise, ots::ots_gasp_free, false }, | 125 ots::ots_gasp_should_serialise, ots::ots_gasp_free, false }, |
128 { TAG('c', 'v', 't', ' '), ots::ots_cvt_parse, ots::ots_cvt_serialise, | 126 { "cvt ", ots::ots_cvt_parse, ots::ots_cvt_serialise, |
129 ots::ots_cvt_should_serialise, ots::ots_cvt_free, false }, | 127 ots::ots_cvt_should_serialise, ots::ots_cvt_free, false }, |
130 { TAG('f', 'p', 'g', 'm'), ots::ots_fpgm_parse, ots::ots_fpgm_serialise, | 128 { "fpgm", ots::ots_fpgm_parse, ots::ots_fpgm_serialise, |
131 ots::ots_fpgm_should_serialise, ots::ots_fpgm_free, false }, | 129 ots::ots_fpgm_should_serialise, ots::ots_fpgm_free, false }, |
132 { TAG('p', 'r', 'e', 'p'), ots::ots_prep_parse, ots::ots_prep_serialise, | 130 { "prep", ots::ots_prep_parse, ots::ots_prep_serialise, |
133 ots::ots_prep_should_serialise, ots::ots_prep_free, false }, | 131 ots::ots_prep_should_serialise, ots::ots_prep_free, false }, |
134 { TAG('L', 'T', 'S', 'H'), ots::ots_ltsh_parse, ots::ots_ltsh_serialise, | 132 { "LTSH", ots::ots_ltsh_parse, ots::ots_ltsh_serialise, |
135 ots::ots_ltsh_should_serialise, ots::ots_ltsh_free, false }, | 133 ots::ots_ltsh_should_serialise, ots::ots_ltsh_free, false }, |
136 { TAG('V', 'O', 'R', 'G'), ots::ots_vorg_parse, ots::ots_vorg_serialise, | 134 { "VORG", ots::ots_vorg_parse, ots::ots_vorg_serialise, |
137 ots::ots_vorg_should_serialise, ots::ots_vorg_free, false }, | 135 ots::ots_vorg_should_serialise, ots::ots_vorg_free, false }, |
138 { TAG('k', 'e', 'r', 'n'), ots::ots_kern_parse, ots::ots_kern_serialise, | 136 { "kern", ots::ots_kern_parse, ots::ots_kern_serialise, |
139 ots::ots_kern_should_serialise, ots::ots_kern_free, false }, | 137 ots::ots_kern_should_serialise, ots::ots_kern_free, false }, |
140 // We need to parse GDEF table in advance of parsing GSUB/GPOS tables | 138 // We need to parse GDEF table in advance of parsing GSUB/GPOS tables |
141 // because they could refer GDEF table. | 139 // because they could refer GDEF table. |
142 { TAG('G', 'D', 'E', 'F'), ots::ots_gdef_parse, ots::ots_gdef_serialise, | 140 { "GDEF", ots::ots_gdef_parse, ots::ots_gdef_serialise, |
143 ots::ots_gdef_should_serialise, ots::ots_gdef_free, false }, | 141 ots::ots_gdef_should_serialise, ots::ots_gdef_free, false }, |
144 { TAG('G', 'P', 'O', 'S'), ots::ots_gpos_parse, ots::ots_gpos_serialise, | 142 { "GPOS", ots::ots_gpos_parse, ots::ots_gpos_serialise, |
145 ots::ots_gpos_should_serialise, ots::ots_gpos_free, false }, | 143 ots::ots_gpos_should_serialise, ots::ots_gpos_free, false }, |
146 { TAG('G', 'S', 'U', 'B'), ots::ots_gsub_parse, ots::ots_gsub_serialise, | 144 { "GSUB", ots::ots_gsub_parse, ots::ots_gsub_serialise, |
147 ots::ots_gsub_should_serialise, ots::ots_gsub_free, false }, | 145 ots::ots_gsub_should_serialise, ots::ots_gsub_free, false }, |
148 { TAG('v', 'h', 'e', 'a'), ots::ots_vhea_parse, ots::ots_vhea_serialise, | 146 { "vhea", ots::ots_vhea_parse, ots::ots_vhea_serialise, |
149 ots::ots_vhea_should_serialise, ots::ots_vhea_free, false }, | 147 ots::ots_vhea_should_serialise, ots::ots_vhea_free, false }, |
150 { TAG('v', 'm', 't', 'x'), ots::ots_vmtx_parse, ots::ots_vmtx_serialise, | 148 { "vmtx", ots::ots_vmtx_parse, ots::ots_vmtx_serialise, |
151 ots::ots_vmtx_should_serialise, ots::ots_vmtx_free, false }, | 149 ots::ots_vmtx_should_serialise, ots::ots_vmtx_free, false }, |
152 // TODO(bashi): Support mort, base, and jstf tables. | 150 // TODO(bashi): Support mort, base, and jstf tables. |
153 { 0, NULL, NULL, NULL, NULL, false }, | 151 { 0, NULL, NULL, NULL, NULL, false }, |
154 }; | 152 }; |
155 | 153 |
156 bool IsValidVersionTag(uint32_t tag) { | 154 bool IsValidVersionTag(uint32_t tag) { |
157 return tag == TAG('\x00', '\x01', '\x00', '\x00') || | 155 return tag == Tag("\x00\x01\x00\x00") || |
158 // OpenType fonts with CFF data have 'OTTO' tag. | 156 // OpenType fonts with CFF data have 'OTTO' tag. |
159 tag == TAG('O', 'T', 'T', 'O') || | 157 tag == Tag("OTTO") || |
160 // Older Mac fonts might have 'true' or 'typ1' tag. | 158 // Older Mac fonts might have 'true' or 'typ1' tag. |
161 tag == TAG('t', 'r', 'u', 'e') || | 159 tag == Tag("true") || |
162 tag == TAG('t', 'y', 'p', '1'); | 160 tag == Tag("typ1"); |
163 } | 161 } |
164 | 162 |
165 bool ProcessGeneric(ots::OpenTypeFile *header, ots::OTSStream *output, | 163 bool ProcessGeneric(ots::OpenTypeFile *header, ots::OTSStream *output, |
166 const uint8_t *data, size_t length, | 164 const uint8_t *data, size_t length, |
167 const std::vector<OpenTypeTable>& tables, | 165 const std::vector<OpenTypeTable>& tables, |
168 ots::Buffer& file); | 166 ots::Buffer& file); |
169 | 167 |
170 bool ProcessTTF(ots::OpenTypeFile *header, | 168 bool ProcessTTF(ots::OpenTypeFile *header, |
171 ots::OTSStream *output, const uint8_t *data, size_t length) { | 169 ots::OTSStream *output, const uint8_t *data, size_t length) { |
172 ots::Buffer file(data, length); | 170 ots::Buffer file(data, length); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
250 // we disallow all files > 1GB in size for sanity. | 248 // we disallow all files > 1GB in size for sanity. |
251 if (length > 1024 * 1024 * 1024) { | 249 if (length > 1024 * 1024 * 1024) { |
252 return OTS_FAILURE(); | 250 return OTS_FAILURE(); |
253 } | 251 } |
254 | 252 |
255 uint32_t woff_tag; | 253 uint32_t woff_tag; |
256 if (!file.ReadTag(&woff_tag)) { | 254 if (!file.ReadTag(&woff_tag)) { |
257 return OTS_FAILURE(); | 255 return OTS_FAILURE(); |
258 } | 256 } |
259 | 257 |
260 if (woff_tag != TAG('w', 'O', 'F', 'F')) { | 258 if (woff_tag != Tag("wOFF")) { |
261 return OTS_FAILURE(); | 259 return OTS_FAILURE(); |
262 } | 260 } |
263 | 261 |
264 if (!file.ReadTag(&header->version)) { | 262 if (!file.ReadTag(&header->version)) { |
265 return OTS_FAILURE(); | 263 return OTS_FAILURE(); |
266 } | 264 } |
267 if (!IsValidVersionTag(header->version)) { | 265 if (!IsValidVersionTag(header->version)) { |
268 return OTS_FAILURE(); | 266 return OTS_FAILURE(); |
269 } | 267 } |
270 | 268 |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 return OTS_FAILURE(); | 496 return OTS_FAILURE(); |
499 } | 497 } |
500 } | 498 } |
501 | 499 |
502 Arena arena; | 500 Arena arena; |
503 | 501 |
504 for (unsigned i = 0; ; ++i) { | 502 for (unsigned i = 0; ; ++i) { |
505 if (table_parsers[i].parse == NULL) break; | 503 if (table_parsers[i].parse == NULL) break; |
506 | 504 |
507 const std::map<uint32_t, OpenTypeTable>::const_iterator it | 505 const std::map<uint32_t, OpenTypeTable>::const_iterator it |
508 = table_map.find(table_parsers[i].tag); | 506 = table_map.find(Tag(table_parsers[i].tag)); |
509 | 507 |
510 if (it == table_map.end()) { | 508 if (it == table_map.end()) { |
511 if (table_parsers[i].required) { | 509 if (table_parsers[i].required) { |
512 return OTS_FAILURE(); | 510 return OTS_FAILURE(); |
513 } | 511 } |
514 continue; | 512 continue; |
515 } | 513 } |
516 | 514 |
517 const uint8_t* table_data; | 515 const uint8_t* table_data; |
518 size_t table_length; | 516 size_t table_length; |
(...skipping 14 matching lines...) Expand all Loading... |
533 table_length = it->second.length; | 531 table_length = it->second.length; |
534 } | 532 } |
535 | 533 |
536 if (!table_parsers[i].parse(header, table_data, table_length)) { | 534 if (!table_parsers[i].parse(header, table_data, table_length)) { |
537 return OTS_FAILURE(); | 535 return OTS_FAILURE(); |
538 } | 536 } |
539 } | 537 } |
540 | 538 |
541 if (header->cff) { | 539 if (header->cff) { |
542 // font with PostScript glyph | 540 // font with PostScript glyph |
543 if (header->version != TAG('O', 'T', 'T', 'O')) { | 541 if (header->version != Tag("OTTO")) { |
544 return OTS_FAILURE(); | 542 return OTS_FAILURE(); |
545 } | 543 } |
546 if (header->glyf || header->loca) { | 544 if (header->glyf || header->loca) { |
547 // mixing outline formats is not recommended | 545 // mixing outline formats is not recommended |
548 return OTS_FAILURE(); | 546 return OTS_FAILURE(); |
549 } | 547 } |
550 } else { | 548 } else { |
551 if (!header->glyf || !header->loca) { | 549 if (!header->glyf || !header->loca) { |
552 // No TrueType glyph found. | 550 // No TrueType glyph found. |
553 // Note: bitmap-only fonts are not supported. | 551 // Note: bitmap-only fonts are not supported. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 for (unsigned i = 0; ; ++i) { | 591 for (unsigned i = 0; ; ++i) { |
594 if (table_parsers[i].parse == NULL) { | 592 if (table_parsers[i].parse == NULL) { |
595 break; | 593 break; |
596 } | 594 } |
597 | 595 |
598 if (!table_parsers[i].should_serialise(header)) { | 596 if (!table_parsers[i].should_serialise(header)) { |
599 continue; | 597 continue; |
600 } | 598 } |
601 | 599 |
602 OutputTable out; | 600 OutputTable out; |
603 out.tag = table_parsers[i].tag; | 601 uint32_t tag = Tag(table_parsers[i].tag); |
| 602 out.tag = tag; |
604 out.offset = output->Tell(); | 603 out.offset = output->Tell(); |
605 | 604 |
606 output->ResetChecksum(); | 605 output->ResetChecksum(); |
607 if (table_parsers[i].tag == TAG('h', 'e', 'a', 'd')) { | 606 if (tag == Tag("head")) { |
608 head_table_offset = out.offset; | 607 head_table_offset = out.offset; |
609 } | 608 } |
610 if (!table_parsers[i].serialise(output, header)) { | 609 if (!table_parsers[i].serialise(output, header)) { |
611 return OTS_FAILURE(); | 610 return OTS_FAILURE(); |
612 } | 611 } |
613 | 612 |
614 const size_t end_offset = output->Tell(); | 613 const size_t end_offset = output->Tell(); |
615 if (end_offset <= out.offset) { | 614 if (end_offset <= out.offset) { |
616 // paranoid check. |end_offset| is supposed to be greater than the offset, | 615 // paranoid check. |end_offset| is supposed to be greater than the offset, |
617 // as long as the Tell() interface is implemented correctly. | 616 // as long as the Tell() interface is implemented correctly. |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
715 va_start(va, format); | 714 va_start(va, format); |
716 std::vfprintf(stderr, format, va); | 715 std::vfprintf(stderr, format, va); |
717 va_end(va); | 716 va_end(va); |
718 std::fprintf(stderr, "\n"); | 717 std::fprintf(stderr, "\n"); |
719 std::fflush(stderr); | 718 std::fflush(stderr); |
720 } | 719 } |
721 } | 720 } |
722 #endif | 721 #endif |
723 | 722 |
724 } // namespace ots | 723 } // namespace ots |
OLD | NEW |