1 // Copyright (c) 2011 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 // GDEF - The Glyph Definition Table
16 // http://www.microsoft.com/typography/otspec/gdef.htm
18 #define TABLE_NAME "GDEF"
22 // The maximum class value in class definition tables.
23 const uint16_t kMaxClassDefValue
= 0xFFFF;
24 // The maximum class value in the glyph class definision table.
25 const uint16_t kMaxGlyphClassDefValue
= 4;
26 // The maximum format number of caret value tables.
27 // We don't support format 3 for now. See the comment in
28 // ParseLigCaretListTable() for the reason.
29 const uint16_t kMaxCaretValueFormat
= 2;
31 bool ParseGlyphClassDefTable(ots::Font
*font
, const uint8_t *data
,
32 size_t length
, const uint16_t num_glyphs
) {
33 return ots::ParseClassDefTable(font
, data
, length
, num_glyphs
,
34 kMaxGlyphClassDefValue
);
37 bool ParseAttachListTable(ots::Font
*font
, const uint8_t *data
,
38 size_t length
, const uint16_t num_glyphs
) {
39 ots::Buffer
subtable(data
, length
);
41 uint16_t offset_coverage
= 0;
42 uint16_t glyph_count
= 0;
43 if (!subtable
.ReadU16(&offset_coverage
) ||
44 !subtable
.ReadU16(&glyph_count
)) {
45 return OTS_FAILURE_MSG("Failed to read gdef header");
47 const unsigned attach_points_end
=
48 2 * static_cast<unsigned>(glyph_count
) + 4;
49 if (attach_points_end
> std::numeric_limits
<uint16_t>::max()) {
50 return OTS_FAILURE_MSG("Bad glyph count in gdef");
52 if (offset_coverage
== 0 || offset_coverage
>= length
||
53 offset_coverage
< attach_points_end
) {
54 return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage
);
56 if (glyph_count
> num_glyphs
) {
57 return OTS_FAILURE_MSG("Bad glyph count %u", glyph_count
);
60 std::vector
<uint16_t> attach_points
;
61 attach_points
.resize(glyph_count
);
62 for (unsigned i
= 0; i
< glyph_count
; ++i
) {
63 if (!subtable
.ReadU16(&attach_points
[i
])) {
64 return OTS_FAILURE_MSG("Can't read attachment point %d", i
);
66 if (attach_points
[i
] >= length
||
67 attach_points
[i
] < attach_points_end
) {
68 return OTS_FAILURE_MSG("Bad attachment point %d of %d", i
, attach_points
[i
]);
72 // Parse coverage table
73 if (!ots::ParseCoverageTable(font
, data
+ offset_coverage
,
74 length
- offset_coverage
, num_glyphs
)) {
75 return OTS_FAILURE_MSG("Bad coverage table");
78 // Parse attach point table
79 for (unsigned i
= 0; i
< attach_points
.size(); ++i
) {
80 subtable
.set_offset(attach_points
[i
]);
81 uint16_t point_count
= 0;
82 if (!subtable
.ReadU16(&point_count
)) {
83 return OTS_FAILURE_MSG("Can't read point count %d", i
);
85 if (point_count
== 0) {
86 return OTS_FAILURE_MSG("zero point count %d", i
);
88 uint16_t last_point_index
= 0;
89 uint16_t point_index
= 0;
90 for (unsigned j
= 0; j
< point_count
; ++j
) {
91 if (!subtable
.ReadU16(&point_index
)) {
92 return OTS_FAILURE_MSG("Can't read point index %d in point %d", j
, i
);
94 // Contour point indeces are in increasing numerical order
95 if (last_point_index
!= 0 && last_point_index
>= point_index
) {
96 return OTS_FAILURE_MSG("bad contour indeces: %u >= %u",
97 last_point_index
, point_index
);
99 last_point_index
= point_index
;
105 bool ParseLigCaretListTable(ots::Font
*font
, const uint8_t *data
,
106 size_t length
, const uint16_t num_glyphs
) {
107 ots::Buffer
subtable(data
, length
);
108 uint16_t offset_coverage
= 0;
109 uint16_t lig_glyph_count
= 0;
110 if (!subtable
.ReadU16(&offset_coverage
) ||
111 !subtable
.ReadU16(&lig_glyph_count
)) {
112 return OTS_FAILURE_MSG("Can't read caret structure");
114 const unsigned lig_glyphs_end
=
115 2 * static_cast<unsigned>(lig_glyph_count
) + 4;
116 if (lig_glyphs_end
> std::numeric_limits
<uint16_t>::max()) {
117 return OTS_FAILURE_MSG("Bad caret structure");
119 if (offset_coverage
== 0 || offset_coverage
>= length
||
120 offset_coverage
< lig_glyphs_end
) {
121 return OTS_FAILURE_MSG("Bad caret coverate offset %d", offset_coverage
);
123 if (lig_glyph_count
> num_glyphs
) {
124 return OTS_FAILURE_MSG("bad ligature glyph count: %u", lig_glyph_count
);
127 std::vector
<uint16_t> lig_glyphs
;
128 lig_glyphs
.resize(lig_glyph_count
);
129 for (unsigned i
= 0; i
< lig_glyph_count
; ++i
) {
130 if (!subtable
.ReadU16(&lig_glyphs
[i
])) {
131 return OTS_FAILURE_MSG("Can't read ligature glyph location %d", i
);
133 if (lig_glyphs
[i
] >= length
|| lig_glyphs
[i
] < lig_glyphs_end
) {
134 return OTS_FAILURE_MSG("Bad ligature glyph location %d in glyph %d", lig_glyphs
[i
], i
);
138 // Parse coverage table
139 if (!ots::ParseCoverageTable(font
, data
+ offset_coverage
,
140 length
- offset_coverage
, num_glyphs
)) {
141 return OTS_FAILURE_MSG("Can't parse caret coverage table");
144 // Parse ligature glyph table
145 for (unsigned i
= 0; i
< lig_glyphs
.size(); ++i
) {
146 subtable
.set_offset(lig_glyphs
[i
]);
147 uint16_t caret_count
= 0;
148 if (!subtable
.ReadU16(&caret_count
)) {
149 return OTS_FAILURE_MSG("Can't read caret count for glyph %d", i
);
151 if (caret_count
== 0) {
152 return OTS_FAILURE_MSG("bad caret value count: %u", caret_count
);
155 std::vector
<uint16_t> caret_value_offsets
;
156 caret_value_offsets
.resize(caret_count
);
157 unsigned caret_value_offsets_end
= 2 * static_cast<unsigned>(caret_count
) + 2;
158 for (unsigned j
= 0; j
< caret_count
; ++j
) {
159 if (!subtable
.ReadU16(&caret_value_offsets
[j
])) {
160 return OTS_FAILURE_MSG("Can't read caret offset %d for glyph %d", j
, i
);
162 if (caret_value_offsets
[j
] >= length
|| caret_value_offsets
[j
] < caret_value_offsets_end
) {
163 return OTS_FAILURE_MSG("Bad caret offset %d for caret %d glyph %d", caret_value_offsets
[j
], j
, i
);
167 // Parse caret values table
168 for (unsigned j
= 0; j
< caret_count
; ++j
) {
169 subtable
.set_offset(lig_glyphs
[i
] + caret_value_offsets
[j
]);
170 uint16_t caret_format
= 0;
171 if (!subtable
.ReadU16(&caret_format
)) {
172 return OTS_FAILURE_MSG("Can't read caret values table %d in glyph %d", j
, i
);
174 // TODO(bashi): We only support caret value format 1 and 2 for now
175 // because there are no fonts which contain caret value format 3
176 // as far as we investigated.
177 if (caret_format
== 0 || caret_format
> kMaxCaretValueFormat
) {
178 return OTS_FAILURE_MSG("bad caret value format: %u", caret_format
);
180 // CaretValueFormats contain a 2-byte field which could be
182 if (!subtable
.Skip(2)) {
183 return OTS_FAILURE_MSG("Bad caret value table structure %d in glyph %d", j
, i
);
190 bool ParseMarkAttachClassDefTable(ots::Font
*font
, const uint8_t *data
,
191 size_t length
, const uint16_t num_glyphs
) {
192 return ots::ParseClassDefTable(font
, data
, length
, num_glyphs
, kMaxClassDefValue
);
195 bool ParseMarkGlyphSetsDefTable(ots::Font
*font
, const uint8_t *data
,
196 size_t length
, const uint16_t num_glyphs
) {
197 ots::Buffer
subtable(data
, length
);
199 uint16_t mark_set_count
= 0;
200 if (!subtable
.ReadU16(&format
) ||
201 !subtable
.ReadU16(&mark_set_count
)) {
202 return OTS_FAILURE_MSG("Can' read mark glyph table structure");
205 return OTS_FAILURE_MSG("bad mark glyph set table format: %u", format
);
208 const unsigned mark_sets_end
= 2 * static_cast<unsigned>(mark_set_count
) + 4;
209 if (mark_sets_end
> std::numeric_limits
<uint16_t>::max()) {
210 return OTS_FAILURE_MSG("Bad mark_set %d", mark_sets_end
);
212 for (unsigned i
= 0; i
< mark_set_count
; ++i
) {
213 uint32_t offset_coverage
= 0;
214 if (!subtable
.ReadU32(&offset_coverage
)) {
215 return OTS_FAILURE_MSG("Can't read covrage location for mark set %d", i
);
217 if (offset_coverage
>= length
||
218 offset_coverage
< mark_sets_end
) {
219 return OTS_FAILURE_MSG("Bad coverage location %d for mark set %d", offset_coverage
, i
);
221 if (!ots::ParseCoverageTable(font
, data
+ offset_coverage
,
222 length
- offset_coverage
, num_glyphs
)) {
223 return OTS_FAILURE_MSG("Failed to parse coverage table for mark set %d", i
);
226 font
->gdef
->num_mark_glyph_sets
= mark_set_count
;
232 #define DROP_THIS_TABLE(msg_) \
234 OTS_FAILURE_MSG(msg_ ", table discarded"); \
235 font->gdef->data = 0; \
236 font->gdef->length = 0; \
241 bool ots_gdef_parse(Font
*font
, const uint8_t *data
, size_t length
) {
242 // Grab the number of glyphs in the font from the maxp table to check
243 // GlyphIDs in GDEF table.
245 return OTS_FAILURE_MSG("No maxp table in font, needed by GDEF");
247 const uint16_t num_glyphs
= font
->maxp
->num_glyphs
;
249 Buffer
table(data
, length
);
251 OpenTypeGDEF
*gdef
= new OpenTypeGDEF
;
254 uint32_t version
= 0;
255 if (!table
.ReadU32(&version
)) {
256 DROP_THIS_TABLE("Incomplete table");
259 if (version
< 0x00010000 || version
== 0x00010001) {
260 DROP_THIS_TABLE("Bad version");
264 if (version
>= 0x00010002) {
265 gdef
->version_2
= true;
268 uint16_t offset_glyph_class_def
= 0;
269 uint16_t offset_attach_list
= 0;
270 uint16_t offset_lig_caret_list
= 0;
271 uint16_t offset_mark_attach_class_def
= 0;
272 if (!table
.ReadU16(&offset_glyph_class_def
) ||
273 !table
.ReadU16(&offset_attach_list
) ||
274 !table
.ReadU16(&offset_lig_caret_list
) ||
275 !table
.ReadU16(&offset_mark_attach_class_def
)) {
276 DROP_THIS_TABLE("Incomplete table");
279 uint16_t offset_mark_glyph_sets_def
= 0;
280 if (gdef
->version_2
) {
281 if (!table
.ReadU16(&offset_mark_glyph_sets_def
)) {
282 DROP_THIS_TABLE("Incomplete table");
287 unsigned gdef_header_end
= 4 + 4 * 2;
289 gdef_header_end
+= 2;
292 if (offset_glyph_class_def
) {
293 if (offset_glyph_class_def
>= length
||
294 offset_glyph_class_def
< gdef_header_end
) {
295 DROP_THIS_TABLE("Invalid offset to glyph classes");
298 if (!ParseGlyphClassDefTable(font
, data
+ offset_glyph_class_def
,
299 length
- offset_glyph_class_def
,
301 DROP_THIS_TABLE("Invalid glyph classes");
304 gdef
->has_glyph_class_def
= true;
307 if (offset_attach_list
) {
308 if (offset_attach_list
>= length
||
309 offset_attach_list
< gdef_header_end
) {
310 DROP_THIS_TABLE("Invalid offset to attachment list");
313 if (!ParseAttachListTable(font
, data
+ offset_attach_list
,
314 length
- offset_attach_list
,
316 DROP_THIS_TABLE("Invalid attachment list");
321 if (offset_lig_caret_list
) {
322 if (offset_lig_caret_list
>= length
||
323 offset_lig_caret_list
< gdef_header_end
) {
324 DROP_THIS_TABLE("Invalid offset to ligature caret list");
327 if (!ParseLigCaretListTable(font
, data
+ offset_lig_caret_list
,
328 length
- offset_lig_caret_list
,
330 DROP_THIS_TABLE("Invalid ligature caret list");
335 if (offset_mark_attach_class_def
) {
336 if (offset_mark_attach_class_def
>= length
||
337 offset_mark_attach_class_def
< gdef_header_end
) {
338 return OTS_FAILURE_MSG("Invalid offset to mark attachment list");
340 if (!ParseMarkAttachClassDefTable(font
,
341 data
+ offset_mark_attach_class_def
,
342 length
- offset_mark_attach_class_def
,
344 DROP_THIS_TABLE("Invalid mark attachment list");
347 gdef
->has_mark_attachment_class_def
= true;
350 if (offset_mark_glyph_sets_def
) {
351 if (offset_mark_glyph_sets_def
>= length
||
352 offset_mark_glyph_sets_def
< gdef_header_end
) {
353 return OTS_FAILURE_MSG("invalid offset to mark glyph sets");
355 if (!ParseMarkGlyphSetsDefTable(font
,
356 data
+ offset_mark_glyph_sets_def
,
357 length
- offset_mark_glyph_sets_def
,
359 DROP_THIS_TABLE("Invalid mark glyph sets");
362 gdef
->has_mark_glyph_sets_def
= true;
365 gdef
->length
= length
;
369 bool ots_gdef_should_serialise(Font
*font
) {
370 return font
->gdef
!= NULL
&& font
->gdef
->data
!= NULL
;
373 bool ots_gdef_serialise(OTSStream
*out
, Font
*font
) {
374 if (!out
->Write(font
->gdef
->data
, font
->gdef
->length
)) {
375 return OTS_FAILURE_MSG("Failed to write GDEF table");
381 void ots_gdef_reuse(Font
*font
, Font
*other
) {
382 font
->gdef
= other
->gdef
;
383 font
->gdef_reused
= true;
386 void ots_gdef_free(Font
*font
) {
393 #undef DROP_THIS_TABLE