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
3 // found in the LICENSE file.
10 // OS/2 - OS/2 and Windows Metrics
11 // http://www.microsoft.com/typography/otspec/os2.htm
13 #define TABLE_NAME "OS/2"
17 bool ots_os2_parse(OpenTypeFile
*file
, const uint8_t *data
, size_t length
) {
18 Buffer
table(data
, length
);
20 OpenTypeOS2
*os2
= new OpenTypeOS2
;
23 if (!table
.ReadU16(&os2
->version
) ||
24 !table
.ReadS16(&os2
->avg_char_width
) ||
25 !table
.ReadU16(&os2
->weight_class
) ||
26 !table
.ReadU16(&os2
->width_class
) ||
27 !table
.ReadU16(&os2
->type
) ||
28 !table
.ReadS16(&os2
->subscript_x_size
) ||
29 !table
.ReadS16(&os2
->subscript_y_size
) ||
30 !table
.ReadS16(&os2
->subscript_x_offset
) ||
31 !table
.ReadS16(&os2
->subscript_y_offset
) ||
32 !table
.ReadS16(&os2
->superscript_x_size
) ||
33 !table
.ReadS16(&os2
->superscript_y_size
) ||
34 !table
.ReadS16(&os2
->superscript_x_offset
) ||
35 !table
.ReadS16(&os2
->superscript_y_offset
) ||
36 !table
.ReadS16(&os2
->strikeout_size
) ||
37 !table
.ReadS16(&os2
->strikeout_position
) ||
38 !table
.ReadS16(&os2
->family_class
)) {
39 return OTS_FAILURE_MSG("Error reading basic table elements");
42 if (os2
->version
> 5) {
43 return OTS_FAILURE_MSG("Unsupported table version: %u", os2
->version
);
46 // Follow WPF Font Selection Model's advice.
47 if (1 <= os2
->weight_class
&& os2
->weight_class
<= 9) {
48 OTS_WARNING("Bad usWeightClass: %u, changing it to: %u", os2
->weight_class
, os2
->weight_class
* 100);
49 os2
->weight_class
*= 100;
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;
57 if (os2
->width_class
< 1) {
58 OTS_WARNING("Bad usWidthClass: %u, changing it to: %d", os2
->width_class
, 1);
60 } else if (os2
->width_class
> 9) {
61 OTS_WARNING("Bad usWidthClass: %u, changing it to: %d", os2
->width_class
, 9);
65 // lowest 3 bits of fsType are exclusive.
66 if (os2
->type
& 0x2) {
69 } else if (os2
->type
& 0x4) {
72 } else if (os2
->type
& 0x8) {
77 // mask reserved bits. use only 0..3, 8, 9 bits.
80 #define SET_TO_ZERO(a, b) \
82 OTS_WARNING("Bad " a ": %d, setting it to zero", os2->b); \
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
);
93 static std::string panose_strings
[10] = {
105 for (unsigned i
= 0; i
< 10; ++i
) {
106 if (!table
.ReadU8(&os2
->panose
[i
])) {
107 return OTS_FAILURE_MSG("Error reading PANOSE %s", panose_strings
[i
].c_str());
111 if (!table
.ReadU32(&os2
->unicode_range_1
) ||
112 !table
.ReadU32(&os2
->unicode_range_2
) ||
113 !table
.ReadU32(&os2
->unicode_range_3
) ||
114 !table
.ReadU32(&os2
->unicode_range_4
) ||
115 !table
.ReadU32(&os2
->vendor_id
) ||
116 !table
.ReadU16(&os2
->selection
) ||
117 !table
.ReadU16(&os2
->first_char_index
) ||
118 !table
.ReadU16(&os2
->last_char_index
) ||
119 !table
.ReadS16(&os2
->typo_ascender
) ||
120 !table
.ReadS16(&os2
->typo_descender
) ||
121 !table
.ReadS16(&os2
->typo_linegap
) ||
122 !table
.ReadU16(&os2
->win_ascent
) ||
123 !table
.ReadU16(&os2
->win_descent
)) {
124 return OTS_FAILURE_MSG("Error reading more basic table fields");
127 // If bit 6 is set, then bits 0 and 5 must be clear.
128 if (os2
->selection
& 0x40) {
129 os2
->selection
&= 0xffdeu
;
132 // the settings of bits 0 and 1 must be reflected in the macStyle bits
133 // in the 'head' table.
135 return OTS_FAILURE_MSG("Needed head table is missing from the font");
137 if ((os2
->selection
& 0x1) &&
138 !(file
->head
->mac_style
& 0x2)) {
139 OTS_WARNING("adjusting Mac style (italic)");
140 file
->head
->mac_style
|= 0x2;
142 if ((os2
->selection
& 0x2) &&
143 !(file
->head
->mac_style
& 0x4)) {
144 OTS_WARNING("adjusting Mac style (underscore)");
145 file
->head
->mac_style
|= 0x4;
148 // While bit 6 on implies that bits 0 and 1 of macStyle are clear,
149 // the reverse is not true.
150 if ((os2
->selection
& 0x40) &&
151 (file
->head
->mac_style
& 0x3)) {
152 OTS_WARNING("adjusting Mac style (regular)");
153 file
->head
->mac_style
&= 0xfffcu
;
156 if ((os2
->version
< 4) &&
157 (os2
->selection
& 0x300)) {
158 // bit 8 and 9 must be unset in OS/2 table versions less than 4.
159 return OTS_FAILURE_MSG("Version %d incompatible with selection %d", os2
->version
, os2
->selection
);
162 // mask reserved bits. use only 0..9 bits.
163 os2
->selection
&= 0x3ff;
165 if (os2
->first_char_index
> os2
->last_char_index
) {
166 return OTS_FAILURE_MSG("first char index %d > last char index %d in os2", os2
->first_char_index
, os2
->last_char_index
);
168 if (os2
->typo_linegap
< 0) {
169 OTS_WARNING("bad linegap: %d", os2
->typo_linegap
);
170 os2
->typo_linegap
= 0;
173 if (os2
->version
< 1) {
174 // http://www.microsoft.com/typography/otspec/os2ver0.htm
178 if (length
< offsetof(OpenTypeOS2
, code_page_range_2
)) {
179 OTS_WARNING("bad version number: %u", os2
->version
);
180 // Some fonts (e.g., kredit1.ttf and quinquef.ttf) have weird version
181 // numbers. Fix them.
186 if (!table
.ReadU32(&os2
->code_page_range_1
) ||
187 !table
.ReadU32(&os2
->code_page_range_2
)) {
188 return OTS_FAILURE_MSG("Failed to read codepage ranges");
191 if (os2
->version
< 2) {
192 // http://www.microsoft.com/typography/otspec/os2ver1.htm
196 if (length
< offsetof(OpenTypeOS2
, max_context
)) {
197 OTS_WARNING("bad version number: %u", os2
->version
);
198 // some Japanese fonts (e.g., mona.ttf) have weird version number.
204 if (!table
.ReadS16(&os2
->x_height
) ||
205 !table
.ReadS16(&os2
->cap_height
) ||
206 !table
.ReadU16(&os2
->default_char
) ||
207 !table
.ReadU16(&os2
->break_char
) ||
208 !table
.ReadU16(&os2
->max_context
)) {
209 return OTS_FAILURE_MSG("Failed to read version 2-specific fields");
212 if (os2
->x_height
< 0) {
213 OTS_WARNING("bad x_height: %d", os2
->x_height
);
216 if (os2
->cap_height
< 0) {
217 OTS_WARNING("bad cap_height: %d", os2
->cap_height
);
221 if (os2
->version
< 5) {
222 // http://www.microsoft.com/typography/otspec/os2ver4.htm
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");
231 if (os2
->lower_optical_pointsize
> 0xFFFE) {
232 OTS_WARNING("'usLowerOpticalPointSize' is bigger than 0xFFFE: %d", os2
->lower_optical_pointsize
);
233 os2
->lower_optical_pointsize
= 0xFFFE;
236 if (os2
->upper_optical_pointsize
< 2) {
237 OTS_WARNING("'usUpperOpticalPointSize' is lower than 2: %d", os2
->upper_optical_pointsize
);
238 os2
->upper_optical_pointsize
= 2;
244 bool ots_os2_should_serialise(OpenTypeFile
*file
) {
245 return file
->os2
!= NULL
;
248 bool ots_os2_serialise(OTSStream
*out
, OpenTypeFile
*file
) {
249 const OpenTypeOS2
*os2
= file
->os2
;
251 if (!out
->WriteU16(os2
->version
) ||
252 !out
->WriteS16(os2
->avg_char_width
) ||
253 !out
->WriteU16(os2
->weight_class
) ||
254 !out
->WriteU16(os2
->width_class
) ||
255 !out
->WriteU16(os2
->type
) ||
256 !out
->WriteS16(os2
->subscript_x_size
) ||
257 !out
->WriteS16(os2
->subscript_y_size
) ||
258 !out
->WriteS16(os2
->subscript_x_offset
) ||
259 !out
->WriteS16(os2
->subscript_y_offset
) ||
260 !out
->WriteS16(os2
->superscript_x_size
) ||
261 !out
->WriteS16(os2
->superscript_y_size
) ||
262 !out
->WriteS16(os2
->superscript_x_offset
) ||
263 !out
->WriteS16(os2
->superscript_y_offset
) ||
264 !out
->WriteS16(os2
->strikeout_size
) ||
265 !out
->WriteS16(os2
->strikeout_position
) ||
266 !out
->WriteS16(os2
->family_class
)) {
267 return OTS_FAILURE_MSG("Failed to write basic OS2 information");
270 for (unsigned i
= 0; i
< 10; ++i
) {
271 if (!out
->Write(&os2
->panose
[i
], 1)) {
272 return OTS_FAILURE_MSG("Failed to write os2 panose information");
276 if (!out
->WriteU32(os2
->unicode_range_1
) ||
277 !out
->WriteU32(os2
->unicode_range_2
) ||
278 !out
->WriteU32(os2
->unicode_range_3
) ||
279 !out
->WriteU32(os2
->unicode_range_4
) ||
280 !out
->WriteU32(os2
->vendor_id
) ||
281 !out
->WriteU16(os2
->selection
) ||
282 !out
->WriteU16(os2
->first_char_index
) ||
283 !out
->WriteU16(os2
->last_char_index
) ||
284 !out
->WriteS16(os2
->typo_ascender
) ||
285 !out
->WriteS16(os2
->typo_descender
) ||
286 !out
->WriteS16(os2
->typo_linegap
) ||
287 !out
->WriteU16(os2
->win_ascent
) ||
288 !out
->WriteU16(os2
->win_descent
)) {
289 return OTS_FAILURE_MSG("Failed to write version 1-specific fields");
292 if (os2
->version
< 1) {
296 if (!out
->WriteU32(os2
->code_page_range_1
) ||
297 !out
->WriteU32(os2
->code_page_range_2
)) {
298 return OTS_FAILURE_MSG("Failed to write codepage ranges");
301 if (os2
->version
< 2) {
305 if (!out
->WriteS16(os2
->x_height
) ||
306 !out
->WriteS16(os2
->cap_height
) ||
307 !out
->WriteU16(os2
->default_char
) ||
308 !out
->WriteU16(os2
->break_char
) ||
309 !out
->WriteU16(os2
->max_context
)) {
310 return OTS_FAILURE_MSG("Failed to write version 2-specific fields");
313 if (os2
->version
< 5) {
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");
325 void ots_os2_free(OpenTypeFile
*file
) {