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 <string> |
| 6 |
5 #include "os2.h" | 7 #include "os2.h" |
6 | |
7 #include "head.h" | 8 #include "head.h" |
8 | 9 |
9 // OS/2 - OS/2 and Windows Metrics | 10 // OS/2 - OS/2 and Windows Metrics |
10 // http://www.microsoft.com/typography/otspec/os2.htm | 11 // http://www.microsoft.com/typography/otspec/os2.htm |
11 | 12 |
12 #define TABLE_NAME "OS/2" | 13 #define TABLE_NAME "OS/2" |
13 | 14 |
14 namespace ots { | 15 namespace ots { |
15 | 16 |
16 bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { | 17 bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { |
(...skipping 11 matching lines...) Expand all Loading... |
28 !table.ReadS16(&os2->subscript_y_size) || | 29 !table.ReadS16(&os2->subscript_y_size) || |
29 !table.ReadS16(&os2->subscript_x_offset) || | 30 !table.ReadS16(&os2->subscript_x_offset) || |
30 !table.ReadS16(&os2->subscript_y_offset) || | 31 !table.ReadS16(&os2->subscript_y_offset) || |
31 !table.ReadS16(&os2->superscript_x_size) || | 32 !table.ReadS16(&os2->superscript_x_size) || |
32 !table.ReadS16(&os2->superscript_y_size) || | 33 !table.ReadS16(&os2->superscript_y_size) || |
33 !table.ReadS16(&os2->superscript_x_offset) || | 34 !table.ReadS16(&os2->superscript_x_offset) || |
34 !table.ReadS16(&os2->superscript_y_offset) || | 35 !table.ReadS16(&os2->superscript_y_offset) || |
35 !table.ReadS16(&os2->strikeout_size) || | 36 !table.ReadS16(&os2->strikeout_size) || |
36 !table.ReadS16(&os2->strikeout_position) || | 37 !table.ReadS16(&os2->strikeout_position) || |
37 !table.ReadS16(&os2->family_class)) { | 38 !table.ReadS16(&os2->family_class)) { |
38 return OTS_FAILURE_MSG("Failed toi read basic os2 elements"); | 39 return OTS_FAILURE_MSG("Error reading basic table elements"); |
39 } | 40 } |
40 | 41 |
41 if (os2->version > 4) { | 42 if (os2->version > 5) { |
42 return OTS_FAILURE_MSG("os2 version too high %d", os2->version); | 43 return OTS_FAILURE_MSG("Unsupported table version: %u", os2->version); |
43 } | 44 } |
44 | 45 |
45 // Some linux fonts (e.g., Kedage-t.ttf and LucidaSansDemiOblique.ttf) have | 46 // Follow WPF Font Selection Model's advice. |
46 // weird weight/width classes. Overwrite them with FW_NORMAL/1/9. | 47 if (1 <= os2->weight_class && os2->weight_class <= 9) { |
47 if (os2->weight_class < 100 || | 48 OTS_WARNING("Bad usWeightClass: %u, changing it to: %u", os2->weight_class,
os2->weight_class * 100); |
48 os2->weight_class > 900 || | 49 os2->weight_class *= 100; |
49 os2->weight_class % 100) { | |
50 OTS_WARNING("bad weight: %u", os2->weight_class); | |
51 os2->weight_class = 400; // FW_NORMAL | |
52 } | 50 } |
| 51 // Ditto. |
| 52 if (os2->weight_class > 999) { |
| 53 OTS_WARNING("Bad usWeightClass: %u, changing it to: %d", os2->weight_class,
999); |
| 54 os2->weight_class = 999; |
| 55 } |
| 56 |
53 if (os2->width_class < 1) { | 57 if (os2->width_class < 1) { |
54 OTS_WARNING("bad width: %u", os2->width_class); | 58 OTS_WARNING("Bad usWidthClass: %u, changing it to: %d", os2->width_class, 1)
; |
55 os2->width_class = 1; | 59 os2->width_class = 1; |
56 } else if (os2->width_class > 9) { | 60 } else if (os2->width_class > 9) { |
57 OTS_WARNING("bad width: %u", os2->width_class); | 61 OTS_WARNING("Bad usWidthClass: %u, changing it to: %d", os2->width_class, 9)
; |
58 os2->width_class = 9; | 62 os2->width_class = 9; |
59 } | 63 } |
60 | 64 |
61 // lowest 3 bits of fsType are exclusive. | 65 // lowest 3 bits of fsType are exclusive. |
62 if (os2->type & 0x2) { | 66 if (os2->type & 0x2) { |
63 // mask bits 2 & 3. | 67 // mask bits 2 & 3. |
64 os2->type &= 0xfff3u; | 68 os2->type &= 0xfff3u; |
65 } else if (os2->type & 0x4) { | 69 } else if (os2->type & 0x4) { |
66 // mask bits 1 & 3. | 70 // mask bits 1 & 3. |
67 os2->type &= 0xfff4u; | 71 os2->type &= 0xfff4u; |
68 } else if (os2->type & 0x8) { | 72 } else if (os2->type & 0x8) { |
69 // mask bits 1 & 2. | 73 // mask bits 1 & 2. |
70 os2->type &= 0xfff9u; | 74 os2->type &= 0xfff9u; |
71 } | 75 } |
72 | 76 |
73 // mask reserved bits. use only 0..3, 8, 9 bits. | 77 // mask reserved bits. use only 0..3, 8, 9 bits. |
74 os2->type &= 0x30f; | 78 os2->type &= 0x30f; |
75 | 79 |
76 if (os2->subscript_x_size < 0) { | 80 #define SET_TO_ZERO(a, b) \ |
77 OTS_WARNING("bad subscript_x_size: %d", os2->subscript_x_size); | 81 if (os2->b < 0) { \ |
78 os2->subscript_x_size = 0; | 82 OTS_WARNING("Bad " a ": %d, setting it to zero", os2->b); \ |
79 } | 83 os2->b = 0; \ |
80 if (os2->subscript_y_size < 0) { | |
81 OTS_WARNING("bad subscript_y_size: %d", os2->subscript_y_size); | |
82 os2->subscript_y_size = 0; | |
83 } | |
84 if (os2->superscript_x_size < 0) { | |
85 OTS_WARNING("bad superscript_x_size: %d", os2->superscript_x_size); | |
86 os2->superscript_x_size = 0; | |
87 } | |
88 if (os2->superscript_y_size < 0) { | |
89 OTS_WARNING("bad superscript_y_size: %d", os2->superscript_y_size); | |
90 os2->superscript_y_size = 0; | |
91 } | |
92 if (os2->strikeout_size < 0) { | |
93 OTS_WARNING("bad strikeout_size: %d", os2->strikeout_size); | |
94 os2->strikeout_size = 0; | |
95 } | 84 } |
96 | 85 |
| 86 SET_TO_ZERO("ySubscriptXSize", subscript_x_size); |
| 87 SET_TO_ZERO("ySubscriptYSize", subscript_y_size); |
| 88 SET_TO_ZERO("ySuperscriptXSize", superscript_x_size); |
| 89 SET_TO_ZERO("ySuperscriptYSize", superscript_y_size); |
| 90 SET_TO_ZERO("yStrikeoutSize", strikeout_size); |
| 91 #undef SET_TO_ZERO |
| 92 |
| 93 static std::string panose_strings[10] = { |
| 94 "bFamilyType", |
| 95 "bSerifStyle", |
| 96 "bWeight", |
| 97 "bProportion", |
| 98 "bContrast", |
| 99 "bStrokeVariation", |
| 100 "bArmStyle", |
| 101 "bLetterform", |
| 102 "bMidline", |
| 103 "bXHeight", |
| 104 }; |
97 for (unsigned i = 0; i < 10; ++i) { | 105 for (unsigned i = 0; i < 10; ++i) { |
98 if (!table.ReadU8(&os2->panose[i])) { | 106 if (!table.ReadU8(&os2->panose[i])) { |
99 return OTS_FAILURE_MSG("Failed to read panose in os2 table"); | 107 return OTS_FAILURE_MSG("Error reading PANOSE %s", panose_strings[i].c_str(
)); |
100 } | 108 } |
101 } | 109 } |
102 | 110 |
103 if (!table.ReadU32(&os2->unicode_range_1) || | 111 if (!table.ReadU32(&os2->unicode_range_1) || |
104 !table.ReadU32(&os2->unicode_range_2) || | 112 !table.ReadU32(&os2->unicode_range_2) || |
105 !table.ReadU32(&os2->unicode_range_3) || | 113 !table.ReadU32(&os2->unicode_range_3) || |
106 !table.ReadU32(&os2->unicode_range_4) || | 114 !table.ReadU32(&os2->unicode_range_4) || |
107 !table.ReadU32(&os2->vendor_id) || | 115 !table.ReadU32(&os2->vendor_id) || |
108 !table.ReadU16(&os2->selection) || | 116 !table.ReadU16(&os2->selection) || |
109 !table.ReadU16(&os2->first_char_index) || | 117 !table.ReadU16(&os2->first_char_index) || |
110 !table.ReadU16(&os2->last_char_index) || | 118 !table.ReadU16(&os2->last_char_index) || |
111 !table.ReadS16(&os2->typo_ascender) || | 119 !table.ReadS16(&os2->typo_ascender) || |
112 !table.ReadS16(&os2->typo_descender) || | 120 !table.ReadS16(&os2->typo_descender) || |
113 !table.ReadS16(&os2->typo_linegap) || | 121 !table.ReadS16(&os2->typo_linegap) || |
114 !table.ReadU16(&os2->win_ascent) || | 122 !table.ReadU16(&os2->win_ascent) || |
115 !table.ReadU16(&os2->win_descent)) { | 123 !table.ReadU16(&os2->win_descent)) { |
116 return OTS_FAILURE_MSG("Failed to read more basic os2 fields"); | 124 return OTS_FAILURE_MSG("Error reading more basic table fields"); |
117 } | 125 } |
118 | 126 |
119 // If bit 6 is set, then bits 0 and 5 must be clear. | 127 // If bit 6 is set, then bits 0 and 5 must be clear. |
120 if (os2->selection & 0x40) { | 128 if (os2->selection & 0x40) { |
121 os2->selection &= 0xffdeu; | 129 os2->selection &= 0xffdeu; |
122 } | 130 } |
123 | 131 |
124 // the settings of bits 0 and 1 must be reflected in the macStyle bits | 132 // the settings of bits 0 and 1 must be reflected in the macStyle bits |
125 // in the 'head' table. | 133 // in the 'head' table. |
126 if (!file->head) { | 134 if (!file->head) { |
127 return OTS_FAILURE_MSG("Head table missing from font as needed by os2 table"
); | 135 return OTS_FAILURE_MSG("Needed head table is missing from the font"); |
128 } | 136 } |
129 if ((os2->selection & 0x1) && | 137 if ((os2->selection & 0x1) && |
130 !(file->head->mac_style & 0x2)) { | 138 !(file->head->mac_style & 0x2)) { |
131 OTS_WARNING("adjusting Mac style (italic)"); | 139 OTS_WARNING("adjusting Mac style (italic)"); |
132 file->head->mac_style |= 0x2; | 140 file->head->mac_style |= 0x2; |
133 } | 141 } |
134 if ((os2->selection & 0x2) && | 142 if ((os2->selection & 0x2) && |
135 !(file->head->mac_style & 0x4)) { | 143 !(file->head->mac_style & 0x4)) { |
136 OTS_WARNING("adjusting Mac style (underscore)"); | 144 OTS_WARNING("adjusting Mac style (underscore)"); |
137 file->head->mac_style |= 0x4; | 145 file->head->mac_style |= 0x4; |
138 } | 146 } |
139 | 147 |
140 // While bit 6 on implies that bits 0 and 1 of macStyle are clear, | 148 // While bit 6 on implies that bits 0 and 1 of macStyle are clear, |
141 // the reverse is not true. | 149 // the reverse is not true. |
142 if ((os2->selection & 0x40) && | 150 if ((os2->selection & 0x40) && |
143 (file->head->mac_style & 0x3)) { | 151 (file->head->mac_style & 0x3)) { |
144 OTS_WARNING("adjusting Mac style (regular)"); | 152 OTS_WARNING("adjusting Mac style (regular)"); |
145 file->head->mac_style &= 0xfffcu; | 153 file->head->mac_style &= 0xfffcu; |
146 } | 154 } |
147 | 155 |
148 if ((os2->version < 4) && | 156 if ((os2->version < 4) && |
149 (os2->selection & 0x300)) { | 157 (os2->selection & 0x300)) { |
150 // bit 8 and 9 must be unset in OS/2 table versions less than 4. | 158 // bit 8 and 9 must be unset in OS/2 table versions less than 4. |
151 return OTS_FAILURE_MSG("OS2 version %d incompatible with selection %d", os2-
>version, os2->selection); | 159 return OTS_FAILURE_MSG("Version %d incompatible with selection %d", os2->ver
sion, os2->selection); |
152 } | 160 } |
153 | 161 |
154 // mask reserved bits. use only 0..9 bits. | 162 // mask reserved bits. use only 0..9 bits. |
155 os2->selection &= 0x3ff; | 163 os2->selection &= 0x3ff; |
156 | 164 |
157 if (os2->first_char_index > os2->last_char_index) { | 165 if (os2->first_char_index > os2->last_char_index) { |
158 return OTS_FAILURE_MSG("first char index %d > last char index %d in os2", os
2->first_char_index, os2->last_char_index); | 166 return OTS_FAILURE_MSG("first char index %d > last char index %d in os2", os
2->first_char_index, os2->last_char_index); |
159 } | 167 } |
160 if (os2->typo_linegap < 0) { | 168 if (os2->typo_linegap < 0) { |
161 OTS_WARNING("bad linegap: %d", os2->typo_linegap); | 169 OTS_WARNING("bad linegap: %d", os2->typo_linegap); |
(...skipping 29 matching lines...) Expand all Loading... |
191 // fix them. | 199 // fix them. |
192 os2->version = 1; | 200 os2->version = 1; |
193 return true; | 201 return true; |
194 } | 202 } |
195 | 203 |
196 if (!table.ReadS16(&os2->x_height) || | 204 if (!table.ReadS16(&os2->x_height) || |
197 !table.ReadS16(&os2->cap_height) || | 205 !table.ReadS16(&os2->cap_height) || |
198 !table.ReadU16(&os2->default_char) || | 206 !table.ReadU16(&os2->default_char) || |
199 !table.ReadU16(&os2->break_char) || | 207 !table.ReadU16(&os2->break_char) || |
200 !table.ReadU16(&os2->max_context)) { | 208 !table.ReadU16(&os2->max_context)) { |
201 return OTS_FAILURE_MSG("Failed to read os2 version 2 information"); | 209 return OTS_FAILURE_MSG("Failed to read version 2-specific fields"); |
202 } | 210 } |
203 | 211 |
204 if (os2->x_height < 0) { | 212 if (os2->x_height < 0) { |
205 OTS_WARNING("bad x_height: %d", os2->x_height); | 213 OTS_WARNING("bad x_height: %d", os2->x_height); |
206 os2->x_height = 0; | 214 os2->x_height = 0; |
207 } | 215 } |
208 if (os2->cap_height < 0) { | 216 if (os2->cap_height < 0) { |
209 OTS_WARNING("bad cap_height: %d", os2->cap_height); | 217 OTS_WARNING("bad cap_height: %d", os2->cap_height); |
210 os2->cap_height = 0; | 218 os2->cap_height = 0; |
211 } | 219 } |
212 | 220 |
| 221 if (os2->version < 5) { |
| 222 // http://www.microsoft.com/typography/otspec/os2ver4.htm |
| 223 return true; |
| 224 } |
| 225 |
| 226 if (!table.ReadU16(&os2->lower_optical_pointsize) || |
| 227 !table.ReadU16(&os2->upper_optical_pointsize)) { |
| 228 return OTS_FAILURE_MSG("Failed to read version 5-specific fields"); |
| 229 } |
| 230 |
| 231 if (os2->lower_optical_pointsize > 0xFFFE) { |
| 232 OTS_WARNING("'usLowerOpticalPointSize' is bigger than 0xFFFE: %d", os2->lowe
r_optical_pointsize); |
| 233 os2->lower_optical_pointsize = 0xFFFE; |
| 234 } |
| 235 |
| 236 if (os2->upper_optical_pointsize < 2) { |
| 237 OTS_WARNING("'usUpperOpticalPointSize' is lower than 2: %d", os2->upper_opti
cal_pointsize); |
| 238 os2->upper_optical_pointsize = 2; |
| 239 } |
| 240 |
213 return true; | 241 return true; |
214 } | 242 } |
215 | 243 |
216 bool ots_os2_should_serialise(OpenTypeFile *file) { | 244 bool ots_os2_should_serialise(OpenTypeFile *file) { |
217 return file->os2 != NULL; | 245 return file->os2 != NULL; |
218 } | 246 } |
219 | 247 |
220 bool ots_os2_serialise(OTSStream *out, OpenTypeFile *file) { | 248 bool ots_os2_serialise(OTSStream *out, OpenTypeFile *file) { |
221 const OpenTypeOS2 *os2 = file->os2; | 249 const OpenTypeOS2 *os2 = file->os2; |
222 | 250 |
(...skipping 28 matching lines...) Expand all Loading... |
251 !out->WriteU32(os2->unicode_range_4) || | 279 !out->WriteU32(os2->unicode_range_4) || |
252 !out->WriteU32(os2->vendor_id) || | 280 !out->WriteU32(os2->vendor_id) || |
253 !out->WriteU16(os2->selection) || | 281 !out->WriteU16(os2->selection) || |
254 !out->WriteU16(os2->first_char_index) || | 282 !out->WriteU16(os2->first_char_index) || |
255 !out->WriteU16(os2->last_char_index) || | 283 !out->WriteU16(os2->last_char_index) || |
256 !out->WriteS16(os2->typo_ascender) || | 284 !out->WriteS16(os2->typo_ascender) || |
257 !out->WriteS16(os2->typo_descender) || | 285 !out->WriteS16(os2->typo_descender) || |
258 !out->WriteS16(os2->typo_linegap) || | 286 !out->WriteS16(os2->typo_linegap) || |
259 !out->WriteU16(os2->win_ascent) || | 287 !out->WriteU16(os2->win_ascent) || |
260 !out->WriteU16(os2->win_descent)) { | 288 !out->WriteU16(os2->win_descent)) { |
261 return OTS_FAILURE_MSG("Failed to write os2 version 1 information"); | 289 return OTS_FAILURE_MSG("Failed to write version 1-specific fields"); |
262 } | 290 } |
263 | 291 |
264 if (os2->version < 1) { | 292 if (os2->version < 1) { |
265 return true; | 293 return true; |
266 } | 294 } |
267 | 295 |
268 if (!out->WriteU32(os2->code_page_range_1) || | 296 if (!out->WriteU32(os2->code_page_range_1) || |
269 !out->WriteU32(os2->code_page_range_2)) { | 297 !out->WriteU32(os2->code_page_range_2)) { |
270 return OTS_FAILURE_MSG("Failed to write codepage ranges"); | 298 return OTS_FAILURE_MSG("Failed to write codepage ranges"); |
271 } | 299 } |
272 | 300 |
273 if (os2->version < 2) { | 301 if (os2->version < 2) { |
274 return true; | 302 return true; |
275 } | 303 } |
276 | 304 |
277 if (!out->WriteS16(os2->x_height) || | 305 if (!out->WriteS16(os2->x_height) || |
278 !out->WriteS16(os2->cap_height) || | 306 !out->WriteS16(os2->cap_height) || |
279 !out->WriteU16(os2->default_char) || | 307 !out->WriteU16(os2->default_char) || |
280 !out->WriteU16(os2->break_char) || | 308 !out->WriteU16(os2->break_char) || |
281 !out->WriteU16(os2->max_context)) { | 309 !out->WriteU16(os2->max_context)) { |
282 return OTS_FAILURE_MSG("Failed to write os2 version 2 information"); | 310 return OTS_FAILURE_MSG("Failed to write version 2-specific fields"); |
| 311 } |
| 312 |
| 313 if (os2->version < 2) { |
| 314 return true; |
| 315 } |
| 316 |
| 317 if (!out->WriteU16(os2->lower_optical_pointsize) || |
| 318 !out->WriteU16(os2->upper_optical_pointsize)) { |
| 319 return OTS_FAILURE_MSG("Failed to write version 5-specific fields"); |
283 } | 320 } |
284 | 321 |
285 return true; | 322 return true; |
286 } | 323 } |
287 | 324 |
288 void ots_os2_free(OpenTypeFile *file) { | 325 void ots_os2_free(OpenTypeFile *file) { |
289 delete file->os2; | 326 delete file->os2; |
290 } | 327 } |
291 | 328 |
292 } // namespace ots | 329 } // namespace ots |
293 | 330 |
294 #undef TABLE_NAME | 331 #undef TABLE_NAME |
OLD | NEW |