1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/ots/src/gdef.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,386 @@ 1.4 +// Copyright (c) 2011 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "gdef.h" 1.9 + 1.10 +#include <limits> 1.11 +#include <vector> 1.12 + 1.13 +#include "gpos.h" 1.14 +#include "gsub.h" 1.15 +#include "layout.h" 1.16 +#include "maxp.h" 1.17 + 1.18 +// GDEF - The Glyph Definition Table 1.19 +// http://www.microsoft.com/typography/otspec/gdef.htm 1.20 + 1.21 +#define TABLE_NAME "GDEF" 1.22 + 1.23 +namespace { 1.24 + 1.25 +// The maximum class value in class definition tables. 1.26 +const uint16_t kMaxClassDefValue = 0xFFFF; 1.27 +// The maximum class value in the glyph class definision table. 1.28 +const uint16_t kMaxGlyphClassDefValue = 4; 1.29 +// The maximum format number of caret value tables. 1.30 +// We don't support format 3 for now. See the comment in 1.31 +// ParseLigCaretListTable() for the reason. 1.32 +const uint16_t kMaxCaretValueFormat = 2; 1.33 + 1.34 +bool ParseGlyphClassDefTable(ots::OpenTypeFile *file, const uint8_t *data, 1.35 + size_t length, const uint16_t num_glyphs) { 1.36 + return ots::ParseClassDefTable(file, data, length, num_glyphs, 1.37 + kMaxGlyphClassDefValue); 1.38 +} 1.39 + 1.40 +bool ParseAttachListTable(ots::OpenTypeFile *file, const uint8_t *data, 1.41 + size_t length, const uint16_t num_glyphs) { 1.42 + ots::Buffer subtable(data, length); 1.43 + 1.44 + uint16_t offset_coverage = 0; 1.45 + uint16_t glyph_count = 0; 1.46 + if (!subtable.ReadU16(&offset_coverage) || 1.47 + !subtable.ReadU16(&glyph_count)) { 1.48 + return OTS_FAILURE_MSG("Failed to read gdef header"); 1.49 + } 1.50 + const unsigned attach_points_end = 1.51 + 2 * static_cast<unsigned>(glyph_count) + 4; 1.52 + if (attach_points_end > std::numeric_limits<uint16_t>::max()) { 1.53 + return OTS_FAILURE_MSG("Bad glyph count in gdef"); 1.54 + } 1.55 + if (offset_coverage == 0 || offset_coverage >= length || 1.56 + offset_coverage < attach_points_end) { 1.57 + return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage); 1.58 + } 1.59 + if (glyph_count > num_glyphs) { 1.60 + return OTS_FAILURE_MSG("Bad glyph count %u", glyph_count); 1.61 + } 1.62 + 1.63 + std::vector<uint16_t> attach_points; 1.64 + attach_points.resize(glyph_count); 1.65 + for (unsigned i = 0; i < glyph_count; ++i) { 1.66 + if (!subtable.ReadU16(&attach_points[i])) { 1.67 + return OTS_FAILURE_MSG("Can't read attachment point %d", i); 1.68 + } 1.69 + if (attach_points[i] >= length || 1.70 + attach_points[i] < attach_points_end) { 1.71 + return OTS_FAILURE_MSG("Bad attachment point %d of %d", i, attach_points[i]); 1.72 + } 1.73 + } 1.74 + 1.75 + // Parse coverage table 1.76 + if (!ots::ParseCoverageTable(file, data + offset_coverage, 1.77 + length - offset_coverage, num_glyphs)) { 1.78 + return OTS_FAILURE_MSG("Bad coverage table"); 1.79 + } 1.80 + 1.81 + // Parse attach point table 1.82 + for (unsigned i = 0; i < attach_points.size(); ++i) { 1.83 + subtable.set_offset(attach_points[i]); 1.84 + uint16_t point_count = 0; 1.85 + if (!subtable.ReadU16(&point_count)) { 1.86 + return OTS_FAILURE_MSG("Can't read point count %d", i); 1.87 + } 1.88 + if (point_count == 0) { 1.89 + return OTS_FAILURE_MSG("zero point count %d", i); 1.90 + } 1.91 + uint16_t last_point_index = 0; 1.92 + uint16_t point_index = 0; 1.93 + for (unsigned j = 0; j < point_count; ++j) { 1.94 + if (!subtable.ReadU16(&point_index)) { 1.95 + return OTS_FAILURE_MSG("Can't read point index %d in point %d", j, i); 1.96 + } 1.97 + // Contour point indeces are in increasing numerical order 1.98 + if (last_point_index != 0 && last_point_index >= point_index) { 1.99 + return OTS_FAILURE_MSG("bad contour indeces: %u >= %u", 1.100 + last_point_index, point_index); 1.101 + } 1.102 + last_point_index = point_index; 1.103 + } 1.104 + } 1.105 + return true; 1.106 +} 1.107 + 1.108 +bool ParseLigCaretListTable(ots::OpenTypeFile *file, const uint8_t *data, 1.109 + size_t length, const uint16_t num_glyphs) { 1.110 + ots::Buffer subtable(data, length); 1.111 + uint16_t offset_coverage = 0; 1.112 + uint16_t lig_glyph_count = 0; 1.113 + if (!subtable.ReadU16(&offset_coverage) || 1.114 + !subtable.ReadU16(&lig_glyph_count)) { 1.115 + return OTS_FAILURE_MSG("Can't read caret structure"); 1.116 + } 1.117 + const unsigned lig_glyphs_end = 1.118 + 2 * static_cast<unsigned>(lig_glyph_count) + 4; 1.119 + if (lig_glyphs_end > std::numeric_limits<uint16_t>::max()) { 1.120 + return OTS_FAILURE_MSG("Bad caret structure"); 1.121 + } 1.122 + if (offset_coverage == 0 || offset_coverage >= length || 1.123 + offset_coverage < lig_glyphs_end) { 1.124 + return OTS_FAILURE_MSG("Bad caret coverate offset %d", offset_coverage); 1.125 + } 1.126 + if (lig_glyph_count > num_glyphs) { 1.127 + return OTS_FAILURE_MSG("bad ligature glyph count: %u", lig_glyph_count); 1.128 + } 1.129 + 1.130 + std::vector<uint16_t> lig_glyphs; 1.131 + lig_glyphs.resize(lig_glyph_count); 1.132 + for (unsigned i = 0; i < lig_glyph_count; ++i) { 1.133 + if (!subtable.ReadU16(&lig_glyphs[i])) { 1.134 + return OTS_FAILURE_MSG("Can't read ligature glyph location %d", i); 1.135 + } 1.136 + if (lig_glyphs[i] >= length || lig_glyphs[i] < lig_glyphs_end) { 1.137 + return OTS_FAILURE_MSG("Bad ligature glyph location %d in glyph %d", lig_glyphs[i], i); 1.138 + } 1.139 + } 1.140 + 1.141 + // Parse coverage table 1.142 + if (!ots::ParseCoverageTable(file, data + offset_coverage, 1.143 + length - offset_coverage, num_glyphs)) { 1.144 + return OTS_FAILURE_MSG("Can't parse caret coverage table"); 1.145 + } 1.146 + 1.147 + // Parse ligature glyph table 1.148 + for (unsigned i = 0; i < lig_glyphs.size(); ++i) { 1.149 + subtable.set_offset(lig_glyphs[i]); 1.150 + uint16_t caret_count = 0; 1.151 + if (!subtable.ReadU16(&caret_count)) { 1.152 + return OTS_FAILURE_MSG("Can't read caret count for glyph %d", i); 1.153 + } 1.154 + if (caret_count == 0) { 1.155 + return OTS_FAILURE_MSG("bad caret value count: %u", caret_count); 1.156 + } 1.157 + 1.158 + std::vector<uint16_t> caret_value_offsets; 1.159 + caret_value_offsets.resize(caret_count); 1.160 + unsigned caret_value_offsets_end = 2 * static_cast<unsigned>(caret_count) + 2; 1.161 + for (unsigned j = 0; j < caret_count; ++j) { 1.162 + if (!subtable.ReadU16(&caret_value_offsets[j])) { 1.163 + return OTS_FAILURE_MSG("Can't read caret offset %d for glyph %d", j, i); 1.164 + } 1.165 + if (caret_value_offsets[j] >= length || caret_value_offsets[j] < caret_value_offsets_end) { 1.166 + return OTS_FAILURE_MSG("Bad caret offset %d for caret %d glyph %d", caret_value_offsets[j], j, i); 1.167 + } 1.168 + } 1.169 + 1.170 + // Parse caret values table 1.171 + for (unsigned j = 0; j < caret_count; ++j) { 1.172 + subtable.set_offset(lig_glyphs[i] + caret_value_offsets[j]); 1.173 + uint16_t caret_format = 0; 1.174 + if (!subtable.ReadU16(&caret_format)) { 1.175 + return OTS_FAILURE_MSG("Can't read caret values table %d in glyph %d", j, i); 1.176 + } 1.177 + // TODO(bashi): We only support caret value format 1 and 2 for now 1.178 + // because there are no fonts which contain caret value format 3 1.179 + // as far as we investigated. 1.180 + if (caret_format == 0 || caret_format > kMaxCaretValueFormat) { 1.181 + return OTS_FAILURE_MSG("bad caret value format: %u", caret_format); 1.182 + } 1.183 + // CaretValueFormats contain a 2-byte field which could be 1.184 + // arbitrary value. 1.185 + if (!subtable.Skip(2)) { 1.186 + return OTS_FAILURE_MSG("Bad caret value table structure %d in glyph %d", j, i); 1.187 + } 1.188 + } 1.189 + } 1.190 + return true; 1.191 +} 1.192 + 1.193 +bool ParseMarkAttachClassDefTable(ots::OpenTypeFile *file, const uint8_t *data, 1.194 + size_t length, const uint16_t num_glyphs) { 1.195 + return ots::ParseClassDefTable(file, data, length, num_glyphs, kMaxClassDefValue); 1.196 +} 1.197 + 1.198 +bool ParseMarkGlyphSetsDefTable(ots::OpenTypeFile *file, const uint8_t *data, 1.199 + size_t length, const uint16_t num_glyphs) { 1.200 + ots::Buffer subtable(data, length); 1.201 + uint16_t format = 0; 1.202 + uint16_t mark_set_count = 0; 1.203 + if (!subtable.ReadU16(&format) || 1.204 + !subtable.ReadU16(&mark_set_count)) { 1.205 + return OTS_FAILURE_MSG("Can' read mark glyph table structure"); 1.206 + } 1.207 + if (format != 1) { 1.208 + return OTS_FAILURE_MSG("bad mark glyph set table format: %u", format); 1.209 + } 1.210 + 1.211 + const unsigned mark_sets_end = 2 * static_cast<unsigned>(mark_set_count) + 4; 1.212 + if (mark_sets_end > std::numeric_limits<uint16_t>::max()) { 1.213 + return OTS_FAILURE_MSG("Bad mark_set %d", mark_sets_end); 1.214 + } 1.215 + for (unsigned i = 0; i < mark_set_count; ++i) { 1.216 + uint32_t offset_coverage = 0; 1.217 + if (!subtable.ReadU32(&offset_coverage)) { 1.218 + return OTS_FAILURE_MSG("Can't read covrage location for mark set %d", i); 1.219 + } 1.220 + if (offset_coverage >= length || 1.221 + offset_coverage < mark_sets_end) { 1.222 + return OTS_FAILURE_MSG("Bad coverage location %d for mark set %d", offset_coverage, i); 1.223 + } 1.224 + if (!ots::ParseCoverageTable(file, data + offset_coverage, 1.225 + length - offset_coverage, num_glyphs)) { 1.226 + return OTS_FAILURE_MSG("Failed to parse coverage table for mark set %d", i); 1.227 + } 1.228 + } 1.229 + file->gdef->num_mark_glyph_sets = mark_set_count; 1.230 + return true; 1.231 +} 1.232 + 1.233 +} // namespace 1.234 + 1.235 +#define DROP_THIS_TABLE(msg_) \ 1.236 + do { \ 1.237 + file->gdef->data = 0; \ 1.238 + file->gdef->length = 0; \ 1.239 + OTS_FAILURE_MSG(msg_ ", table discarded"); \ 1.240 + } while (0) 1.241 + 1.242 +namespace ots { 1.243 + 1.244 +bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { 1.245 + // Grab the number of glyphs in the file from the maxp table to check 1.246 + // GlyphIDs in GDEF table. 1.247 + if (!file->maxp) { 1.248 + return OTS_FAILURE_MSG("No maxp table in font, needed by GDEF"); 1.249 + } 1.250 + const uint16_t num_glyphs = file->maxp->num_glyphs; 1.251 + 1.252 + Buffer table(data, length); 1.253 + 1.254 + OpenTypeGDEF *gdef = new OpenTypeGDEF; 1.255 + file->gdef = gdef; 1.256 + 1.257 + uint32_t version = 0; 1.258 + if (!table.ReadU32(&version)) { 1.259 + DROP_THIS_TABLE("Incomplete table"); 1.260 + return true; 1.261 + } 1.262 + if (version < 0x00010000 || version == 0x00010001) { 1.263 + DROP_THIS_TABLE("Bad version"); 1.264 + return true; 1.265 + } 1.266 + 1.267 + if (version >= 0x00010002) { 1.268 + gdef->version_2 = true; 1.269 + } 1.270 + 1.271 + uint16_t offset_glyph_class_def = 0; 1.272 + uint16_t offset_attach_list = 0; 1.273 + uint16_t offset_lig_caret_list = 0; 1.274 + uint16_t offset_mark_attach_class_def = 0; 1.275 + if (!table.ReadU16(&offset_glyph_class_def) || 1.276 + !table.ReadU16(&offset_attach_list) || 1.277 + !table.ReadU16(&offset_lig_caret_list) || 1.278 + !table.ReadU16(&offset_mark_attach_class_def)) { 1.279 + DROP_THIS_TABLE("Incomplete table"); 1.280 + return true; 1.281 + } 1.282 + uint16_t offset_mark_glyph_sets_def = 0; 1.283 + if (gdef->version_2) { 1.284 + if (!table.ReadU16(&offset_mark_glyph_sets_def)) { 1.285 + DROP_THIS_TABLE("Incomplete table"); 1.286 + return true; 1.287 + } 1.288 + } 1.289 + 1.290 + unsigned gdef_header_end = 4 + 4 * 2; 1.291 + if (gdef->version_2) 1.292 + gdef_header_end += 2; 1.293 + 1.294 + // Parse subtables 1.295 + if (offset_glyph_class_def) { 1.296 + if (offset_glyph_class_def >= length || 1.297 + offset_glyph_class_def < gdef_header_end) { 1.298 + DROP_THIS_TABLE("Invalid offset to glyph classes"); 1.299 + return true; 1.300 + } 1.301 + if (!ParseGlyphClassDefTable(file, data + offset_glyph_class_def, 1.302 + length - offset_glyph_class_def, 1.303 + num_glyphs)) { 1.304 + DROP_THIS_TABLE("Invalid glyph classes"); 1.305 + return true; 1.306 + } 1.307 + gdef->has_glyph_class_def = true; 1.308 + } 1.309 + 1.310 + if (offset_attach_list) { 1.311 + if (offset_attach_list >= length || 1.312 + offset_attach_list < gdef_header_end) { 1.313 + DROP_THIS_TABLE("Invalid offset to attachment list"); 1.314 + return true; 1.315 + } 1.316 + if (!ParseAttachListTable(file, data + offset_attach_list, 1.317 + length - offset_attach_list, 1.318 + num_glyphs)) { 1.319 + DROP_THIS_TABLE("Invalid attachment list"); 1.320 + return true; 1.321 + } 1.322 + } 1.323 + 1.324 + if (offset_lig_caret_list) { 1.325 + if (offset_lig_caret_list >= length || 1.326 + offset_lig_caret_list < gdef_header_end) { 1.327 + DROP_THIS_TABLE("Invalid offset to ligature caret list"); 1.328 + return true; 1.329 + } 1.330 + if (!ParseLigCaretListTable(file, data + offset_lig_caret_list, 1.331 + length - offset_lig_caret_list, 1.332 + num_glyphs)) { 1.333 + DROP_THIS_TABLE("Invalid ligature caret list"); 1.334 + return true; 1.335 + } 1.336 + } 1.337 + 1.338 + if (offset_mark_attach_class_def) { 1.339 + if (offset_mark_attach_class_def >= length || 1.340 + offset_mark_attach_class_def < gdef_header_end) { 1.341 + return OTS_FAILURE_MSG("Invalid offset to mark attachment list"); 1.342 + } 1.343 + if (!ParseMarkAttachClassDefTable(file, 1.344 + data + offset_mark_attach_class_def, 1.345 + length - offset_mark_attach_class_def, 1.346 + num_glyphs)) { 1.347 + DROP_THIS_TABLE("Invalid mark attachment list"); 1.348 + return true; 1.349 + } 1.350 + gdef->has_mark_attachment_class_def = true; 1.351 + } 1.352 + 1.353 + if (offset_mark_glyph_sets_def) { 1.354 + if (offset_mark_glyph_sets_def >= length || 1.355 + offset_mark_glyph_sets_def < gdef_header_end) { 1.356 + return OTS_FAILURE_MSG("invalid offset to mark glyph sets"); 1.357 + } 1.358 + if (!ParseMarkGlyphSetsDefTable(file, 1.359 + data + offset_mark_glyph_sets_def, 1.360 + length - offset_mark_glyph_sets_def, 1.361 + num_glyphs)) { 1.362 + DROP_THIS_TABLE("Invalid mark glyph sets"); 1.363 + return true; 1.364 + } 1.365 + gdef->has_mark_glyph_sets_def = true; 1.366 + } 1.367 + gdef->data = data; 1.368 + gdef->length = length; 1.369 + return true; 1.370 +} 1.371 + 1.372 +bool ots_gdef_should_serialise(OpenTypeFile *file) { 1.373 + return file->gdef != NULL && file->gdef->data != NULL; 1.374 +} 1.375 + 1.376 +bool ots_gdef_serialise(OTSStream *out, OpenTypeFile *file) { 1.377 + if (!out->Write(file->gdef->data, file->gdef->length)) { 1.378 + return OTS_FAILURE_MSG("Failed to write GDEF table"); 1.379 + } 1.380 + 1.381 + return true; 1.382 +} 1.383 + 1.384 +void ots_gdef_free(OpenTypeFile *file) { 1.385 + delete file->gdef; 1.386 +} 1.387 + 1.388 +} // namespace ots 1.389 +