Line | Count | Source |
1 | | // Copyright (c) 2011-2017 The OTS 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 "metrics.h" |
6 | | |
7 | | #include "head.h" |
8 | | #include "maxp.h" |
9 | | |
10 | | // OpenType horizontal and vertical common header format |
11 | | // http://www.microsoft.com/typography/otspec/hhea.htm |
12 | | // http://www.microsoft.com/typography/otspec/vhea.htm |
13 | | |
14 | | namespace ots { |
15 | | |
16 | 22.2k | bool OpenTypeMetricsHeader::Parse(const uint8_t *data, size_t length) { |
17 | 22.2k | Buffer table(data, length); |
18 | | |
19 | | // Skip already read version. |
20 | 22.2k | if (!table.Skip(4)) { |
21 | 0 | return false; |
22 | 0 | } |
23 | | |
24 | 22.2k | if (!table.ReadS16(&this->ascent) || |
25 | 22.2k | !table.ReadS16(&this->descent) || |
26 | 22.2k | !table.ReadS16(&this->linegap) || |
27 | 22.2k | !table.ReadU16(&this->adv_width_max) || |
28 | 22.2k | !table.ReadS16(&this->min_sb1) || |
29 | 22.2k | !table.ReadS16(&this->min_sb2) || |
30 | 22.1k | !table.ReadS16(&this->max_extent) || |
31 | 22.1k | !table.ReadS16(&this->caret_slope_rise) || |
32 | 22.1k | !table.ReadS16(&this->caret_slope_run) || |
33 | 22.1k | !table.ReadS16(&this->caret_offset)) { |
34 | 94 | return Error("Failed to read table"); |
35 | 94 | } |
36 | | |
37 | 22.1k | if (this->ascent < 0) { |
38 | 6.31k | Warning("Negative ascent, setting to 0: %d", this->ascent); |
39 | 6.31k | this->ascent = 0; |
40 | 6.31k | } |
41 | 22.1k | if (this->linegap < 0) { |
42 | 10.7k | Warning("Negative linegap, setting to: %d", this->linegap); |
43 | 10.7k | this->linegap = 0; |
44 | 10.7k | } |
45 | | |
46 | 22.1k | OpenTypeHEAD *head = static_cast<OpenTypeHEAD*>( |
47 | 22.1k | GetFont()->GetTypedTable(OTS_TAG_HEAD)); |
48 | 22.1k | if (!head) { |
49 | 0 | return Error("Missing head font table"); |
50 | 0 | } |
51 | | |
52 | | // if the font is non-slanted, caret_offset should be zero. |
53 | 22.1k | if (!(head->mac_style & 2) && |
54 | 13.8k | (this->caret_offset != 0)) { |
55 | 7.48k | Warning("Non-zero caretOffset but head.macStyle italic bit is not set, setting to caretOffset to 0: %d", this->caret_offset); |
56 | 7.48k | this->caret_offset = 0; |
57 | 7.48k | } |
58 | | |
59 | | // skip the reserved bytes |
60 | 22.1k | if (!table.Skip(8)) { |
61 | 18 | return Error("Failed to read reserved bytes"); |
62 | 18 | } |
63 | | |
64 | 22.1k | int16_t data_format; |
65 | 22.1k | if (!table.ReadS16(&data_format)) { |
66 | 6 | return Error("Failed to read metricDataFormat"); |
67 | 6 | } |
68 | 22.1k | if (data_format) { |
69 | 10 | return Error("Unsupported metricDataFormat: %d", data_format); |
70 | 10 | } |
71 | | |
72 | 22.1k | if (!table.ReadU16(&this->num_metrics)) { |
73 | 19 | return Error("Failed to read number of metrics"); |
74 | 19 | } |
75 | | |
76 | 22.1k | OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>( |
77 | 22.1k | GetFont()->GetTypedTable(OTS_TAG_MAXP)); |
78 | 22.1k | if (!maxp) { |
79 | 0 | return Error("Missing maxp font table"); |
80 | 0 | } |
81 | | |
82 | 22.1k | if (this->num_metrics > maxp->num_glyphs) { |
83 | 37 | return Error("Bad number of metrics %d", this->num_metrics); |
84 | 37 | } |
85 | | |
86 | 22.0k | return true; |
87 | 22.1k | } |
88 | | |
89 | 11.3k | bool OpenTypeMetricsHeader::Serialize(OTSStream *out) { |
90 | 11.3k | if (!out->WriteU32(this->version) || |
91 | 11.3k | !out->WriteS16(this->ascent) || |
92 | 11.3k | !out->WriteS16(this->descent) || |
93 | 11.3k | !out->WriteS16(this->linegap) || |
94 | 11.3k | !out->WriteU16(this->adv_width_max) || |
95 | 11.3k | !out->WriteS16(this->min_sb1) || |
96 | 11.3k | !out->WriteS16(this->min_sb2) || |
97 | 11.3k | !out->WriteS16(this->max_extent) || |
98 | 11.3k | !out->WriteS16(this->caret_slope_rise) || |
99 | 11.3k | !out->WriteS16(this->caret_slope_run) || |
100 | 11.3k | !out->WriteS16(this->caret_offset) || |
101 | 11.3k | !out->WriteR64(0) || // reserved |
102 | 11.3k | !out->WriteS16(0) || // metric data format |
103 | 11.3k | !out->WriteU16(this->num_metrics)) { |
104 | 6 | return Error("Failed to write metrics"); |
105 | 6 | } |
106 | | |
107 | 11.3k | return true; |
108 | 11.3k | } |
109 | | |
110 | 21.9k | bool OpenTypeMetricsTable::Parse(const uint8_t *data, size_t length) { |
111 | 21.9k | Buffer table(data, length); |
112 | | |
113 | | // OpenTypeMetricsHeader is a superclass of both 'hhea' and 'vhea', |
114 | | // so the cast here is OK, whichever m_header_tag we have. |
115 | 21.9k | OpenTypeMetricsHeader *header = static_cast<OpenTypeMetricsHeader*>( |
116 | 21.9k | GetFont()->GetTypedTable(m_header_tag)); |
117 | 21.9k | if (!header) { |
118 | 2 | return Error("Required %c%c%c%c table missing", OTS_UNTAG(m_header_tag)); |
119 | 2 | } |
120 | | // |num_metrics| is a uint16_t, so it's bounded < 65536. This limits that |
121 | | // amount of memory that we'll allocate for this to a sane amount. |
122 | 21.9k | const unsigned num_metrics = header->num_metrics; |
123 | | |
124 | 21.9k | OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>( |
125 | 21.9k | GetFont()->GetTypedTable(OTS_TAG_MAXP)); |
126 | 21.9k | if (!maxp) { |
127 | 0 | return Error("Required maxp table missing"); |
128 | 0 | } |
129 | 21.9k | if (num_metrics > maxp->num_glyphs) { |
130 | 0 | return Error("Bad number of metrics %d", num_metrics); |
131 | 0 | } |
132 | 21.9k | if (!num_metrics) { |
133 | 29 | return Error("No metrics!"); |
134 | 29 | } |
135 | 21.9k | const unsigned num_sbs = maxp->num_glyphs - num_metrics; |
136 | | |
137 | 21.9k | this->entries.reserve(num_metrics); |
138 | 527k | for (unsigned i = 0; i < num_metrics; ++i) { |
139 | 505k | uint16_t adv = 0; |
140 | 505k | int16_t sb = 0; |
141 | 505k | if (!table.ReadU16(&adv) || !table.ReadS16(&sb)) { |
142 | 42 | return Error("Failed to read metric %d", i); |
143 | 42 | } |
144 | 505k | this->entries.push_back(std::make_pair(adv, sb)); |
145 | 505k | } |
146 | | |
147 | 21.8k | this->sbs.reserve(num_sbs); |
148 | 610k | for (unsigned i = 0; i < num_sbs; ++i) { |
149 | 588k | int16_t sb; |
150 | 588k | if (!table.ReadS16(&sb)) { |
151 | | // Some Japanese fonts (e.g., mona.ttf) fail this test. |
152 | 42 | return Error("Failed to read side bearing %d", i + num_metrics); |
153 | 42 | } |
154 | 588k | this->sbs.push_back(sb); |
155 | 588k | } |
156 | | |
157 | 21.8k | return true; |
158 | 21.8k | } |
159 | | |
160 | 11.6k | bool OpenTypeMetricsTable::Serialize(OTSStream *out) { |
161 | 222k | for (unsigned i = 0; i < this->entries.size(); ++i) { |
162 | 211k | if (!out->WriteU16(this->entries[i].first) || |
163 | 211k | !out->WriteS16(this->entries[i].second)) { |
164 | 0 | return Error("Failed to write metric %d", i); |
165 | 0 | } |
166 | 211k | } |
167 | | |
168 | 46.7k | for (unsigned i = 0; i < this->sbs.size(); ++i) { |
169 | 35.0k | if (!out->WriteS16(this->sbs[i])) { |
170 | 0 | return Error("Failed to write side bearing %ld", i + this->entries.size()); |
171 | 0 | } |
172 | 35.0k | } |
173 | | |
174 | 11.6k | return true; |
175 | 11.6k | } |
176 | | |
177 | | } // namespace ots |