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. 4 5 #include "gdef.h" 6 7 #include <limits> 8 #include <vector> 9 10 #include "gpos.h" 11 #include "gsub.h" 12 #include "layout.h" 13 #include "maxp.h" 14 15 // GDEF - The Glyph Definition Table 16 // http://www.microsoft.com/typography/otspec/gdef.htm 17 18 namespace { 19 20 // The maximum class value in class definition tables. 21 const uint16_t kMaxClassDefValue = 0xFFFF; 22 // The maximum class value in the glyph class definision table. 23 const uint16_t kMaxGlyphClassDefValue = 4; 24 // The maximum format number of caret value tables. 25 // We don't support format 3 for now. See the comment in 26 // ParseLigCaretListTable() for the reason. 27 const uint16_t kMaxCaretValueFormat = 2; 28 29 bool ParseGlyphClassDefTable(ots::OpenTypeFile *file, const uint8_t *data, 30 size_t length, const uint16_t num_glyphs) { 31 return ots::ParseClassDefTable(data, length, num_glyphs, 32 kMaxGlyphClassDefValue); 33 } 34 35 bool ParseAttachListTable(ots::OpenTypeFile *file, const uint8_t *data, 36 size_t length, const uint16_t num_glyphs) { 37 ots::Buffer subtable(data, length); 38 39 uint16_t offset_coverage = 0; 40 uint16_t glyph_count = 0; 41 if (!subtable.ReadU16(&offset_coverage) || 42 !subtable.ReadU16(&glyph_count)) { 43 return OTS_FAILURE(); 44 } 45 const unsigned attach_points_end = 46 2 * static_cast<unsigned>(glyph_count) + 4; 47 if (attach_points_end > std::numeric_limits<uint16_t>::max()) { 48 return OTS_FAILURE(); 49 } 50 if (offset_coverage == 0 || offset_coverage >= length || 51 offset_coverage < attach_points_end) { 52 return OTS_FAILURE(); 53 } 54 if (glyph_count > num_glyphs) { 55 OTS_WARNING("bad glyph count: %u", glyph_count); 56 return OTS_FAILURE(); 57 } 58 59 std::vector<uint16_t> attach_points; 60 attach_points.resize(glyph_count); 61 for (unsigned i = 0; i < glyph_count; ++i) { 62 if (!subtable.ReadU16(&attach_points[i])) { 63 return OTS_FAILURE(); 64 } 65 if (attach_points[i] >= length || 66 attach_points[i] < attach_points_end) { 67 return OTS_FAILURE(); 68 } 69 } 70 71 // Parse coverage table 72 if (!ots::ParseCoverageTable(data + offset_coverage, 73 length - offset_coverage, num_glyphs)) { 74 return OTS_FAILURE(); 75 } 76 77 // Parse attach point table 78 for (unsigned i = 0; i < attach_points.size(); ++i) { 79 subtable.set_offset(attach_points[i]); 80 uint16_t point_count = 0; 81 if (!subtable.ReadU16(&point_count)) { 82 return OTS_FAILURE(); 83 } 84 if (point_count == 0) { 85 return OTS_FAILURE(); 86 } 87 uint16_t last_point_index = 0; 88 uint16_t point_index = 0; 89 for (unsigned j = 0; j < point_count; ++j) { 90 if (!subtable.ReadU16(&point_index)) { 91 return OTS_FAILURE(); 92 } 93 // Contour point indeces are in increasing numerical order 94 if (last_point_index != 0 && last_point_index >= point_index) { 95 OTS_WARNING("bad contour indeces: %u >= %u", 96 last_point_index, point_index); 97 return OTS_FAILURE(); 98 } 99 last_point_index = point_index; 100 } 101 } 102 return true; 103 } 104 105 bool ParseLigCaretListTable(ots::OpenTypeFile *file, 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(); 113 } 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(); 118 } 119 if (offset_coverage == 0 || offset_coverage >= length || 120 offset_coverage < lig_glyphs_end) { 121 return OTS_FAILURE(); 122 } 123 if (lig_glyph_count > num_glyphs) { 124 OTS_WARNING("bad ligature glyph count: %u", lig_glyph_count); 125 return OTS_FAILURE(); 126 } 127 128 std::vector<uint16_t> lig_glyphs; 129 lig_glyphs.resize(lig_glyph_count); 130 for (unsigned i = 0; i < lig_glyph_count; ++i) { 131 if (!subtable.ReadU16(&lig_glyphs[i])) { 132 return OTS_FAILURE(); 133 } 134 if (lig_glyphs[i] >= length || lig_glyphs[i] < lig_glyphs_end) { 135 return OTS_FAILURE(); 136 } 137 } 138 139 // Parse coverage table 140 if (!ots::ParseCoverageTable(data + offset_coverage, 141 length - offset_coverage, num_glyphs)) { 142 return OTS_FAILURE(); 143 } 144 145 // Parse ligature glyph table 146 for (unsigned i = 0; i < lig_glyphs.size(); ++i) { 147 subtable.set_offset(lig_glyphs[i]); 148 uint16_t caret_count = 0; 149 if (!subtable.ReadU16(&caret_count)) { 150 return OTS_FAILURE(); 151 } 152 if (caret_count == 0) { 153 OTS_WARNING("bad caret value count: %u", caret_count); 154 return OTS_FAILURE(); 155 } 156 157 std::vector<uint16_t> caret_values; 158 caret_values.resize(caret_count); 159 uint16_t last_offset_caret = 0; 160 unsigned caret_values_end = 2 * static_cast<unsigned>(caret_count) + 2; 161 for (unsigned j = 0; j < caret_count; ++j) { 162 if (!subtable.ReadU16(&caret_values[j])) { 163 return OTS_FAILURE(); 164 } 165 if (caret_values[j] >= length || caret_values[j] < caret_values_end) { 166 return OTS_FAILURE(); 167 } 168 // Caret offsets are in increasing coordinate order 169 if (last_offset_caret != 0 && last_offset_caret >= caret_values[j]) { 170 OTS_WARNING("offset isn't in increasing coordinate order: %u >= %u", 171 last_offset_caret, caret_values[j]); 172 return OTS_FAILURE(); 173 } 174 last_offset_caret = caret_values[j]; 175 } 176 177 // Parse caret values table 178 for (unsigned j = 0; j < caret_count; ++j) { 179 subtable.set_offset(lig_glyphs[i] + caret_values[j]); 180 uint16_t caret_format = 0; 181 if (!subtable.ReadU16(&caret_format)) { 182 return OTS_FAILURE(); 183 } 184 // TODO(bashi): We only support caret value format 1 and 2 for now 185 // because there are no fonts which contain caret value format 3 186 // as far as we investigated. 187 if (caret_format == 0 || caret_format > kMaxCaretValueFormat) { 188 OTS_WARNING("bad caret value format: %u", caret_format); 189 return OTS_FAILURE(); 190 } 191 // CaretValueFormats contain a 2-byte field which could be 192 // arbitrary value. 193 if (!subtable.Skip(2)) { 194 return OTS_FAILURE(); 195 } 196 } 197 } 198 return true; 199 } 200 201 bool ParseMarkAttachClassDefTable(ots::OpenTypeFile *file, const uint8_t *data, 202 size_t length, const uint16_t num_glyphs) { 203 return ots::ParseClassDefTable(data, length, num_glyphs, kMaxClassDefValue); 204 } 205 206 bool ParseMarkGlyphSetsDefTable(ots::OpenTypeFile *file, const uint8_t *data, 207 size_t length, const uint16_t num_glyphs) { 208 ots::Buffer subtable(data, length); 209 uint16_t format = 0; 210 uint16_t mark_set_count = 0; 211 if (!subtable.ReadU16(&format) || 212 !subtable.ReadU16(&mark_set_count)) { 213 return OTS_FAILURE(); 214 } 215 if (format != 1) { 216 OTS_WARNING("bad mark glyph set table format: %u", format); 217 return OTS_FAILURE(); 218 } 219 220 const unsigned mark_sets_end = 2 * static_cast<unsigned>(mark_set_count) + 4; 221 if (mark_sets_end > std::numeric_limits<uint16_t>::max()) { 222 return OTS_FAILURE(); 223 } 224 for (unsigned i = 0; i < mark_set_count; ++i) { 225 uint32_t offset_coverage = 0; 226 if (!subtable.ReadU32(&offset_coverage)) { 227 return OTS_FAILURE(); 228 } 229 if (offset_coverage >= length || 230 offset_coverage < mark_sets_end) { 231 return OTS_FAILURE(); 232 } 233 if (!ots::ParseCoverageTable(data + offset_coverage, 234 length - offset_coverage, num_glyphs)) { 235 return OTS_FAILURE(); 236 } 237 } 238 file->gdef->num_mark_glyph_sets = mark_set_count; 239 return true; 240 } 241 242 } // namespace 243 244 #define DROP_THIS_TABLE \ 245 do { file->gdef->data = 0; file->gdef->length = 0; } while (0) 246 247 namespace ots { 248 249 bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { 250 // Grab the number of glyphs in the file from the maxp table to check 251 // GlyphIDs in GDEF table. 252 if (!file->maxp) { 253 return OTS_FAILURE(); 254 } 255 const uint16_t num_glyphs = file->maxp->num_glyphs; 256 257 Buffer table(data, length); 258 259 OpenTypeGDEF *gdef = new OpenTypeGDEF; 260 file->gdef = gdef; 261 262 uint32_t version = 0; 263 if (!table.ReadU32(&version)) { 264 return OTS_FAILURE(); 265 } 266 if (version < 0x00010000 || version == 0x00010001) { 267 OTS_WARNING("bad GDEF version"); 268 DROP_THIS_TABLE; 269 return true; 270 } 271 272 if (version >= 0x00010002) { 273 gdef->version_2 = true; 274 } 275 276 uint16_t offset_glyph_class_def = 0; 277 uint16_t offset_attach_list = 0; 278 uint16_t offset_lig_caret_list = 0; 279 uint16_t offset_mark_attach_class_def = 0; 280 if (!table.ReadU16(&offset_glyph_class_def) || 281 !table.ReadU16(&offset_attach_list) || 282 !table.ReadU16(&offset_lig_caret_list) || 283 !table.ReadU16(&offset_mark_attach_class_def)) { 284 return OTS_FAILURE(); 285 } 286 uint16_t offset_mark_glyph_sets_def = 0; 287 if (gdef->version_2) { 288 if (!table.ReadU16(&offset_mark_glyph_sets_def)) { 289 return OTS_FAILURE(); 290 } 291 } 292 293 unsigned gdef_header_end = 8; 294 if (gdef->version_2) 295 gdef_header_end += 2; 296 297 // Parse subtables 298 if (offset_glyph_class_def) { 299 if (offset_glyph_class_def >= length || 300 offset_glyph_class_def < gdef_header_end) { 301 return OTS_FAILURE(); 302 } 303 if (!ParseGlyphClassDefTable(file, data + offset_glyph_class_def, 304 length - offset_glyph_class_def, 305 num_glyphs)) { 306 DROP_THIS_TABLE; 307 return true; 308 } 309 gdef->has_glyph_class_def = true; 310 } 311 312 if (offset_attach_list) { 313 if (offset_attach_list >= length || 314 offset_attach_list < gdef_header_end) { 315 return OTS_FAILURE(); 316 } 317 if (!ParseAttachListTable(file, data + offset_attach_list, 318 length - offset_attach_list, 319 num_glyphs)) { 320 DROP_THIS_TABLE; 321 return true; 322 } 323 } 324 325 if (offset_lig_caret_list) { 326 if (offset_lig_caret_list >= length || 327 offset_lig_caret_list < gdef_header_end) { 328 return OTS_FAILURE(); 329 } 330 if (!ParseLigCaretListTable(file, data + offset_lig_caret_list, 331 length - offset_lig_caret_list, 332 num_glyphs)) { 333 DROP_THIS_TABLE; 334 return true; 335 } 336 } 337 338 if (offset_mark_attach_class_def) { 339 if (offset_mark_attach_class_def >= length || 340 offset_mark_attach_class_def < gdef_header_end) { 341 return OTS_FAILURE(); 342 } 343 if (!ParseMarkAttachClassDefTable(file, 344 data + offset_mark_attach_class_def, 345 length - offset_mark_attach_class_def, 346 num_glyphs)) { 347 DROP_THIS_TABLE; 348 return true; 349 } 350 gdef->has_mark_attachment_class_def = true; 351 } 352 353 if (offset_mark_glyph_sets_def) { 354 if (offset_mark_glyph_sets_def >= length || 355 offset_mark_glyph_sets_def < gdef_header_end) { 356 return OTS_FAILURE(); 357 } 358 if (!ParseMarkGlyphSetsDefTable(file, 359 data + offset_mark_glyph_sets_def, 360 length - offset_mark_glyph_sets_def, 361 num_glyphs)) { 362 DROP_THIS_TABLE; 363 return true; 364 } 365 gdef->has_mark_glyph_sets_def = true; 366 } 367 gdef->data = data; 368 gdef->length = length; 369 return true; 370 } 371 372 bool ots_gdef_should_serialise(OpenTypeFile *file) { 373 const bool needed_tables_dropped = 374 (file->gsub && file->gsub->data == NULL) || 375 (file->gpos && file->gpos->data == NULL); 376 return file->gdef != NULL && file->gdef->data != NULL && 377 !needed_tables_dropped; 378 } 379 380 bool ots_gdef_serialise(OTSStream *out, OpenTypeFile *file) { 381 if (!out->Write(file->gdef->data, file->gdef->length)) { 382 return OTS_FAILURE(); 383 } 384 385 return true; 386 } 387 388 void ots_gdef_free(OpenTypeFile *file) { 389 delete file->gdef; 390 } 391 392 } // namespace ots 393 394