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.
9 // hdmx - Horizontal Device Metrics
10 // http://www.microsoft.com/typography/otspec/hdmx.htm
12 #define TABLE_NAME "hdmx"
14 #define DROP_THIS_TABLE(...) \
16 OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__); \
17 OTS_FAILURE_MSG("Table discarded"); \
24 bool ots_hdmx_parse(Font
*font
, const uint8_t *data
, size_t length
) {
25 Buffer
table(data
, length
);
26 font
->hdmx
= new OpenTypeHDMX
;
27 OpenTypeHDMX
* const hdmx
= font
->hdmx
;
29 if (!font
->head
|| !font
->maxp
) {
30 return OTS_FAILURE_MSG("Missing maxp or head tables in font, needed by hdmx");
33 if ((font
->head
->flags
& 0x14) == 0) {
34 // http://www.microsoft.com/typography/otspec/recom.htm
35 DROP_THIS_TABLE("the table should not be present when bit 2 and 4 of the "
36 "head->flags are not set");
41 if (!table
.ReadU16(&hdmx
->version
) ||
42 !table
.ReadS16(&num_recs
) ||
43 !table
.ReadS32(&hdmx
->size_device_record
)) {
44 return OTS_FAILURE_MSG("Failed to read hdmx header");
46 if (hdmx
->version
!= 0) {
47 DROP_THIS_TABLE("bad version: %u", hdmx
->version
);
51 DROP_THIS_TABLE("bad num_recs: %d", num_recs
);
54 const int32_t actual_size_device_record
= font
->maxp
->num_glyphs
+ 2;
55 if (hdmx
->size_device_record
< actual_size_device_record
) {
56 DROP_THIS_TABLE("bad hdmx->size_device_record: %d", hdmx
->size_device_record
);
60 hdmx
->pad_len
= hdmx
->size_device_record
- actual_size_device_record
;
61 if (hdmx
->pad_len
> 3) {
62 return OTS_FAILURE_MSG("Bad padding %d", hdmx
->pad_len
);
65 uint8_t last_pixel_size
= 0;
66 hdmx
->records
.reserve(num_recs
);
67 for (int i
= 0; i
< num_recs
; ++i
) {
68 OpenTypeHDMXDeviceRecord rec
;
70 if (!table
.ReadU8(&rec
.pixel_size
) ||
71 !table
.ReadU8(&rec
.max_width
)) {
72 return OTS_FAILURE_MSG("Failed to read hdmx record %d", i
);
75 (rec
.pixel_size
<= last_pixel_size
)) {
76 DROP_THIS_TABLE("records are not sorted");
79 last_pixel_size
= rec
.pixel_size
;
81 rec
.widths
.reserve(font
->maxp
->num_glyphs
);
82 for (unsigned j
= 0; j
< font
->maxp
->num_glyphs
; ++j
) {
84 if (!table
.ReadU8(&width
)) {
85 return OTS_FAILURE_MSG("Failed to read glyph width %d in record %d", j
, i
);
87 rec
.widths
.push_back(width
);
90 if ((hdmx
->pad_len
> 0) &&
91 !table
.Skip(hdmx
->pad_len
)) {
92 return OTS_FAILURE_MSG("Failed to skip padding %d", hdmx
->pad_len
);
95 hdmx
->records
.push_back(rec
);
101 bool ots_hdmx_should_serialise(Font
*font
) {
102 if (!font
->hdmx
) return false;
103 if (!font
->glyf
) return false; // this table is not for CFF fonts.
107 bool ots_hdmx_serialise(OTSStream
*out
, Font
*font
) {
108 OpenTypeHDMX
* const hdmx
= font
->hdmx
;
110 const int16_t num_recs
= static_cast<int16_t>(hdmx
->records
.size());
111 if (hdmx
->records
.size() >
112 static_cast<size_t>(std::numeric_limits
<int16_t>::max()) ||
113 !out
->WriteU16(hdmx
->version
) ||
114 !out
->WriteS16(num_recs
) ||
115 !out
->WriteS32(hdmx
->size_device_record
)) {
116 return OTS_FAILURE_MSG("Failed to write hdmx header");
119 for (int16_t i
= 0; i
< num_recs
; ++i
) {
120 const OpenTypeHDMXDeviceRecord
& rec
= hdmx
->records
[i
];
121 if (!out
->Write(&rec
.pixel_size
, 1) ||
122 !out
->Write(&rec
.max_width
, 1) ||
123 !out
->Write(&rec
.widths
[0], rec
.widths
.size())) {
124 return OTS_FAILURE_MSG("Failed to write hdmx record %d", i
);
126 if ((hdmx
->pad_len
> 0) &&
127 !out
->Write((const uint8_t *)"\x00\x00\x00", hdmx
->pad_len
)) {
128 return OTS_FAILURE_MSG("Failed to write hdmx padding of length %d", hdmx
->pad_len
);
135 void ots_hdmx_reuse(Font
*font
, Font
*other
) {
136 font
->hdmx
= other
->hdmx
;
137 font
->hdmx_reused
= true;
140 void ots_hdmx_free(Font
*font
) {
147 #undef DROP_THIS_TABLE