gfx/ots/src/gdef.cc

changeset 0
6474c204b198
     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 +

mercurial