Line data Source code
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.
4 :
5 : #include "hdmx.h"
6 : #include "head.h"
7 : #include "maxp.h"
8 :
9 : // hdmx - Horizontal Device Metrics
10 : // http://www.microsoft.com/typography/otspec/hdmx.htm
11 :
12 : #define TABLE_NAME "hdmx"
13 :
14 : #define DROP_THIS_TABLE(...) \
15 : do { \
16 : OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__); \
17 : OTS_FAILURE_MSG("Table discarded"); \
18 : delete font->hdmx; \
19 : font->hdmx = 0; \
20 : } while (0)
21 :
22 : namespace ots {
23 :
24 0 : bool ots_hdmx_parse(Font *font, const uint8_t *data, size_t length) {
25 0 : Buffer table(data, length);
26 0 : font->hdmx = new OpenTypeHDMX;
27 0 : OpenTypeHDMX * const hdmx = font->hdmx;
28 :
29 0 : if (!font->head || !font->maxp) {
30 0 : return OTS_FAILURE_MSG("Missing maxp or head tables in font, needed by hdmx");
31 : }
32 :
33 0 : if ((font->head->flags & 0x14) == 0) {
34 : // http://www.microsoft.com/typography/otspec/recom.htm
35 0 : DROP_THIS_TABLE("the table should not be present when bit 2 and 4 of the "
36 : "head->flags are not set");
37 0 : return true;
38 : }
39 :
40 : int16_t num_recs;
41 0 : if (!table.ReadU16(&hdmx->version) ||
42 0 : !table.ReadS16(&num_recs) ||
43 0 : !table.ReadS32(&hdmx->size_device_record)) {
44 0 : return OTS_FAILURE_MSG("Failed to read hdmx header");
45 : }
46 0 : if (hdmx->version != 0) {
47 0 : DROP_THIS_TABLE("bad version: %u", hdmx->version);
48 0 : return true;
49 : }
50 0 : if (num_recs <= 0) {
51 0 : DROP_THIS_TABLE("bad num_recs: %d", num_recs);
52 0 : return true;
53 : }
54 0 : const int32_t actual_size_device_record = font->maxp->num_glyphs + 2;
55 0 : if (hdmx->size_device_record < actual_size_device_record) {
56 0 : DROP_THIS_TABLE("bad hdmx->size_device_record: %d", hdmx->size_device_record);
57 0 : return true;
58 : }
59 :
60 0 : hdmx->pad_len = hdmx->size_device_record - actual_size_device_record;
61 0 : if (hdmx->pad_len > 3) {
62 0 : return OTS_FAILURE_MSG("Bad padding %d", hdmx->pad_len);
63 : }
64 :
65 0 : uint8_t last_pixel_size = 0;
66 0 : hdmx->records.reserve(num_recs);
67 0 : for (int i = 0; i < num_recs; ++i) {
68 0 : OpenTypeHDMXDeviceRecord rec;
69 :
70 0 : if (!table.ReadU8(&rec.pixel_size) ||
71 0 : !table.ReadU8(&rec.max_width)) {
72 0 : return OTS_FAILURE_MSG("Failed to read hdmx record %d", i);
73 : }
74 0 : if ((i != 0) &&
75 0 : (rec.pixel_size <= last_pixel_size)) {
76 0 : DROP_THIS_TABLE("records are not sorted");
77 0 : return true;
78 : }
79 0 : last_pixel_size = rec.pixel_size;
80 :
81 0 : rec.widths.reserve(font->maxp->num_glyphs);
82 0 : for (unsigned j = 0; j < font->maxp->num_glyphs; ++j) {
83 : uint8_t width;
84 0 : if (!table.ReadU8(&width)) {
85 0 : return OTS_FAILURE_MSG("Failed to read glyph width %d in record %d", j, i);
86 : }
87 0 : rec.widths.push_back(width);
88 : }
89 :
90 0 : if ((hdmx->pad_len > 0) &&
91 0 : !table.Skip(hdmx->pad_len)) {
92 0 : return OTS_FAILURE_MSG("Failed to skip padding %d", hdmx->pad_len);
93 : }
94 :
95 0 : hdmx->records.push_back(rec);
96 : }
97 :
98 0 : return true;
99 : }
100 :
101 0 : bool ots_hdmx_should_serialise(Font *font) {
102 0 : if (!font->hdmx) return false;
103 0 : if (!font->glyf) return false; // this table is not for CFF fonts.
104 0 : return true;
105 : }
106 :
107 0 : bool ots_hdmx_serialise(OTSStream *out, Font *font) {
108 0 : OpenTypeHDMX * const hdmx = font->hdmx;
109 :
110 0 : const int16_t num_recs = static_cast<int16_t>(hdmx->records.size());
111 0 : if (hdmx->records.size() >
112 0 : static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
113 0 : !out->WriteU16(hdmx->version) ||
114 0 : !out->WriteS16(num_recs) ||
115 0 : !out->WriteS32(hdmx->size_device_record)) {
116 0 : return OTS_FAILURE_MSG("Failed to write hdmx header");
117 : }
118 :
119 0 : for (int16_t i = 0; i < num_recs; ++i) {
120 0 : const OpenTypeHDMXDeviceRecord& rec = hdmx->records[i];
121 0 : if (!out->Write(&rec.pixel_size, 1) ||
122 0 : !out->Write(&rec.max_width, 1) ||
123 0 : !out->Write(&rec.widths[0], rec.widths.size())) {
124 0 : return OTS_FAILURE_MSG("Failed to write hdmx record %d", i);
125 : }
126 0 : if ((hdmx->pad_len > 0) &&
127 0 : !out->Write((const uint8_t *)"\x00\x00\x00", hdmx->pad_len)) {
128 0 : return OTS_FAILURE_MSG("Failed to write hdmx padding of length %d", hdmx->pad_len);
129 : }
130 : }
131 :
132 0 : return true;
133 : }
134 :
135 0 : void ots_hdmx_reuse(Font *font, Font *other) {
136 0 : font->hdmx = other->hdmx;
137 0 : font->hdmx_reused = true;
138 0 : }
139 :
140 0 : void ots_hdmx_free(Font *font) {
141 0 : delete font->hdmx;
142 0 : }
143 :
144 : } // namespace ots
145 :
146 : #undef TABLE_NAME
147 : #undef DROP_THIS_TABLE
|