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.
15 // http://www.microsoft.com/typography/otspec/glyf.htm
17 #define TABLE_NAME "glyf"
21 bool ParseFlagsForSimpleGlyph(ots::OpenTypeFile
*file
,
25 uint32_t *flags_count_logical
,
26 uint32_t *flags_count_physical
,
27 uint32_t *xy_coordinates_length
) {
29 if (!table
->ReadU8(&flag
)) {
30 return OTS_FAILURE_MSG("Can't read flag");
34 if (flag
& (1u << 1)) { // x-Short
36 } else if (!(flag
& (1u << 4))) {
40 if (flag
& (1u << 2)) { // y-Short
42 } else if (!(flag
& (1u << 5))) {
46 if (flag
& (1u << 3)) { // repeat
47 if (*flags_count_logical
+ 1 >= num_flags
) {
48 return OTS_FAILURE_MSG("Count too high (%d + 1 >= %d)", *flags_count_logical
, num_flags
);
51 if (!table
->ReadU8(&repeat
)) {
52 return OTS_FAILURE_MSG("Can't read repeat value");
55 return OTS_FAILURE_MSG("Zero repeat");
57 delta
+= (delta
* repeat
);
59 *flags_count_logical
+= repeat
;
60 if (*flags_count_logical
>= num_flags
) {
61 return OTS_FAILURE_MSG("Count too high (%d >= %d)", *flags_count_logical
, num_flags
);
63 ++(*flags_count_physical
);
66 if ((flag
& (1u << 6)) || (flag
& (1u << 7))) { // reserved flags
67 return OTS_FAILURE_MSG("Bad glyph flag value (%d), reserved flags must be set to zero", flag
);
70 *xy_coordinates_length
+= delta
;
71 if (gly_length
< *xy_coordinates_length
) {
72 return OTS_FAILURE_MSG("Glyph coordinates length too low (%d < %d)", gly_length
, *xy_coordinates_length
);
78 bool ParseSimpleGlyph(ots::OpenTypeFile
*file
, const uint8_t *data
,
79 ots::Buffer
*table
, int16_t num_contours
,
80 uint32_t gly_offset
, uint32_t gly_length
,
82 ots::OpenTypeGLYF
*glyf
= file
->glyf
;
84 // read the end-points array
85 uint16_t num_flags
= 0;
86 for (int i
= 0; i
< num_contours
; ++i
) {
87 uint16_t tmp_index
= 0;
88 if (!table
->ReadU16(&tmp_index
)) {
89 return OTS_FAILURE_MSG("Can't read contour index %d", i
);
91 if (tmp_index
== 0xffffu
) {
92 return OTS_FAILURE_MSG("Bad contour index %d", i
);
94 // check if the indices are monotonically increasing
95 if (i
&& (tmp_index
+ 1 <= num_flags
)) {
96 return OTS_FAILURE_MSG("Decreasing contour index %d + 1 <= %d", tmp_index
, num_flags
);
98 num_flags
= tmp_index
+ 1;
101 uint16_t bytecode_length
= 0;
102 if (!table
->ReadU16(&bytecode_length
)) {
103 return OTS_FAILURE_MSG("Can't read bytecode length");
105 if ((file
->maxp
->version_1
) &&
106 (file
->maxp
->max_size_glyf_instructions
< bytecode_length
)) {
107 return OTS_FAILURE_MSG("Bytecode length too high %d", bytecode_length
);
110 const uint32_t gly_header_length
= 10 + num_contours
* 2 + 2;
111 if (gly_length
< (gly_header_length
+ bytecode_length
)) {
112 return OTS_FAILURE_MSG("Glyph header length too high %d", gly_header_length
);
115 glyf
->iov
.push_back(std::make_pair(
117 static_cast<size_t>(gly_header_length
+ bytecode_length
)));
119 if (!table
->Skip(bytecode_length
)) {
120 return OTS_FAILURE_MSG("Can't skip bytecode of length %d", bytecode_length
);
123 uint32_t flags_count_physical
= 0; // on memory
124 uint32_t xy_coordinates_length
= 0;
125 for (uint32_t flags_count_logical
= 0;
126 flags_count_logical
< num_flags
;
127 ++flags_count_logical
, ++flags_count_physical
) {
128 if (!ParseFlagsForSimpleGlyph(file
,
132 &flags_count_logical
,
133 &flags_count_physical
,
134 &xy_coordinates_length
)) {
135 return OTS_FAILURE_MSG("Failed to parse glyph flags %d", flags_count_logical
);
139 if (gly_length
< (gly_header_length
+ bytecode_length
+
140 flags_count_physical
+ xy_coordinates_length
)) {
141 return OTS_FAILURE_MSG("Glyph too short %d", gly_length
);
144 if (gly_length
- (gly_header_length
+ bytecode_length
+
145 flags_count_physical
+ xy_coordinates_length
) > 3) {
146 // We allow 0-3 bytes difference since gly_length is 4-bytes aligned,
147 // zero-padded length.
148 return OTS_FAILURE_MSG("Invalid glyph length %d", gly_length
);
151 glyf
->iov
.push_back(std::make_pair(
152 data
+ gly_offset
+ gly_header_length
+ bytecode_length
,
153 static_cast<size_t>(flags_count_physical
+ xy_coordinates_length
)));
156 = gly_header_length
+ flags_count_physical
+ xy_coordinates_length
+ bytecode_length
;
165 bool ots_glyf_parse(OpenTypeFile
*file
, const uint8_t *data
, size_t length
) {
166 Buffer
table(data
, length
);
168 if (!file
->maxp
|| !file
->loca
|| !file
->head
) {
169 return OTS_FAILURE_MSG("Missing maxp or loca or head table needed by glyf table");
172 OpenTypeGLYF
*glyf
= new OpenTypeGLYF
;
175 const unsigned num_glyphs
= file
->maxp
->num_glyphs
;
176 std::vector
<uint32_t> &offsets
= file
->loca
->offsets
;
178 if (offsets
.size() != num_glyphs
+ 1) {
179 return OTS_FAILURE_MSG("Invalide glyph offsets size %ld != %d", offsets
.size(), num_glyphs
+ 1);
182 std::vector
<uint32_t> resulting_offsets(num_glyphs
+ 1);
183 uint32_t current_offset
= 0;
185 for (unsigned i
= 0; i
< num_glyphs
; ++i
) {
186 const unsigned gly_offset
= offsets
[i
];
187 // The LOCA parser checks that these values are monotonic
188 const unsigned gly_length
= offsets
[i
+ 1] - offsets
[i
];
190 // this glyph has no outline (e.g. the space charactor)
191 resulting_offsets
[i
] = current_offset
;
195 if (gly_offset
>= length
) {
196 return OTS_FAILURE_MSG("Glyph %d offset %d too high %ld", i
, gly_offset
, length
);
198 // Since these are unsigned types, the compiler is not allowed to assume
199 // that they never overflow.
200 if (gly_offset
+ gly_length
< gly_offset
) {
201 return OTS_FAILURE_MSG("Glyph %d length (%d < 0)!", i
, gly_length
);
203 if (gly_offset
+ gly_length
> length
) {
204 return OTS_FAILURE_MSG("Glyph %d length %d too high", i
, gly_length
);
207 table
.set_offset(gly_offset
);
208 int16_t num_contours
, xmin
, ymin
, xmax
, ymax
;
209 if (!table
.ReadS16(&num_contours
) ||
210 !table
.ReadS16(&xmin
) ||
211 !table
.ReadS16(&ymin
) ||
212 !table
.ReadS16(&xmax
) ||
213 !table
.ReadS16(&ymax
)) {
214 return OTS_FAILURE_MSG("Can't read glyph %d header", i
);
217 if (num_contours
<= -2) {
218 // -2, -3, -4, ... are reserved for future use.
219 return OTS_FAILURE_MSG("Bad number of contours %d in glyph %d", num_contours
, i
);
222 // workaround for fonts in http://www.princexml.com/fonts/
223 if ((xmin
== 32767) &&
227 OTS_WARNING("bad xmin/xmax/ymin/ymax values");
228 xmin
= xmax
= ymin
= ymax
= 0;
231 if (xmin
> xmax
|| ymin
> ymax
) {
232 return OTS_FAILURE_MSG("Bad bounding box values bl=(%d, %d), tr=(%d, %d) in glyph %d", xmin
, ymin
, xmax
, ymax
, i
);
235 unsigned new_size
= 0;
236 if (num_contours
>= 0) {
237 // this is a simple glyph and might contain bytecode
238 if (!ParseSimpleGlyph(file
, data
, &table
,
239 num_contours
, gly_offset
, gly_length
, &new_size
)) {
240 return OTS_FAILURE_MSG("Failed to parse glyph %d", i
);
243 // it's a composite glyph without any bytecode. Enqueue the whole thing
244 glyf
->iov
.push_back(std::make_pair(data
+ gly_offset
,
245 static_cast<size_t>(gly_length
)));
246 new_size
= gly_length
;
249 resulting_offsets
[i
] = current_offset
;
250 // glyphs must be four byte aligned
251 // TODO(yusukes): investigate whether this padding is really necessary.
252 // Which part of the spec requires this?
253 const unsigned padding
= (4 - (new_size
& 3)) % 4;
255 glyf
->iov
.push_back(std::make_pair(
256 reinterpret_cast<const uint8_t*>("\x00\x00\x00\x00"),
257 static_cast<size_t>(padding
)));
260 current_offset
+= new_size
;
262 resulting_offsets
[num_glyphs
] = current_offset
;
264 const uint16_t max16
= std::numeric_limits
<uint16_t>::max();
265 if ((*std::max_element(resulting_offsets
.begin(),
266 resulting_offsets
.end()) >= (max16
* 2u)) &&
267 (file
->head
->index_to_loc_format
!= 1)) {
268 OTS_WARNING("2-bytes indexing is not possible (due to the padding above)");
269 file
->head
->index_to_loc_format
= 1;
272 file
->loca
->offsets
= resulting_offsets
;
276 bool ots_glyf_should_serialise(OpenTypeFile
*file
) {
277 return file
->glyf
!= NULL
;
280 bool ots_glyf_serialise(OTSStream
*out
, OpenTypeFile
*file
) {
281 const OpenTypeGLYF
*glyf
= file
->glyf
;
283 for (unsigned i
= 0; i
< glyf
->iov
.size(); ++i
) {
284 if (!out
->Write(glyf
->iov
[i
].first
, glyf
->iov
[i
].second
)) {
285 return OTS_FAILURE_MSG("Falied to write glyph %d", i
);
292 void ots_glyf_free(OpenTypeFile
*file
) {