gfx/ots/src/kern.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/ots/src/kern.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,202 @@
     1.4 +// Copyright (c) 2009 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 "kern.h"
     1.9 +
    1.10 +// kern - Kerning
    1.11 +// http://www.microsoft.com/typography/otspec/kern.htm
    1.12 +
    1.13 +#define TABLE_NAME "kern"
    1.14 +
    1.15 +#define DROP_THIS_TABLE \
    1.16 +  do { \
    1.17 +    delete file->kern; \
    1.18 +    file->kern = 0; \
    1.19 +    OTS_FAILURE_MSG("Table discarded"); \
    1.20 +  } while (0)
    1.21 +
    1.22 +namespace ots {
    1.23 +
    1.24 +bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
    1.25 +  Buffer table(data, length);
    1.26 +
    1.27 +  OpenTypeKERN *kern = new OpenTypeKERN;
    1.28 +  file->kern = kern;
    1.29 +
    1.30 +  uint16_t num_tables = 0;
    1.31 +  if (!table.ReadU16(&kern->version) ||
    1.32 +      !table.ReadU16(&num_tables)) {
    1.33 +    return OTS_FAILURE_MSG("Failed to read kern header");
    1.34 +  }
    1.35 +
    1.36 +  if (kern->version > 0) {
    1.37 +    DROP_THIS_TABLE;
    1.38 +    return true;
    1.39 +  }
    1.40 +
    1.41 +  if (num_tables == 0) {
    1.42 +    OTS_WARNING("num_tables is zero");
    1.43 +    DROP_THIS_TABLE;
    1.44 +    return true;
    1.45 +  }
    1.46 +
    1.47 +  kern->subtables.reserve(num_tables);
    1.48 +  for (unsigned i = 0; i < num_tables; ++i) {
    1.49 +    OpenTypeKERNFormat0 subtable;
    1.50 +    uint16_t sub_length = 0;
    1.51 +
    1.52 +    if (!table.ReadU16(&subtable.version) ||
    1.53 +        !table.ReadU16(&sub_length)) {
    1.54 +      return OTS_FAILURE_MSG("Failed to read kern subtable %d header", i);
    1.55 +    }
    1.56 +
    1.57 +    if (subtable.version > 0) {
    1.58 +      OTS_WARNING("Bad subtable version: %d", subtable.version);
    1.59 +      continue;
    1.60 +    }
    1.61 +
    1.62 +    const size_t current_offset = table.offset();
    1.63 +    if (current_offset - 4 + sub_length > length) {
    1.64 +      return OTS_FAILURE_MSG("Bad kern subtable %d offset %ld", i, current_offset);
    1.65 +    }
    1.66 +
    1.67 +    if (!table.ReadU16(&subtable.coverage)) {
    1.68 +      return OTS_FAILURE_MSG("Cailed to read kern subtable %d coverage", i);
    1.69 +    }
    1.70 +
    1.71 +    if (!(subtable.coverage & 0x1)) {
    1.72 +      OTS_WARNING(
    1.73 +          "We don't support vertical data as the renderer doesn't support it.");
    1.74 +      continue;
    1.75 +    }
    1.76 +    if (subtable.coverage & 0xF0) {
    1.77 +      OTS_WARNING("Reserved fields should zero-filled.");
    1.78 +      DROP_THIS_TABLE;
    1.79 +      return true;
    1.80 +    }
    1.81 +    const uint32_t format = (subtable.coverage & 0xFF00) >> 8;
    1.82 +    if (format != 0) {
    1.83 +      OTS_WARNING("Format %d is not supported.", format);
    1.84 +      continue;
    1.85 +    }
    1.86 +
    1.87 +    // Parse the format 0 field.
    1.88 +    uint16_t num_pairs = 0;
    1.89 +    if (!table.ReadU16(&num_pairs) ||
    1.90 +        !table.ReadU16(&subtable.search_range) ||
    1.91 +        !table.ReadU16(&subtable.entry_selector) ||
    1.92 +        !table.ReadU16(&subtable.range_shift)) {
    1.93 +      return OTS_FAILURE_MSG("Failed to read kern subtable %d format 0 fields", i);
    1.94 +    }
    1.95 +
    1.96 +    if (!num_pairs) {
    1.97 +      OTS_WARNING("Zero length subtable is found.");
    1.98 +      DROP_THIS_TABLE;
    1.99 +      return true;
   1.100 +    }
   1.101 +
   1.102 +    // Sanity checks for search_range, entry_selector, and range_shift. See the
   1.103 +    // comment in ots.cc for details.
   1.104 +    const size_t kFormat0PairSize = 6;  // left, right, and value. 2 bytes each.
   1.105 +    if (num_pairs > (65536 / kFormat0PairSize)) {
   1.106 +      // Some fonts (e.g. calibri.ttf, pykes_peak_zero.ttf) have pairs >= 10923.
   1.107 +      OTS_WARNING("Too large subtable.");
   1.108 +      DROP_THIS_TABLE;
   1.109 +      return true;
   1.110 +    }
   1.111 +    unsigned max_pow2 = 0;
   1.112 +    while (1u << (max_pow2 + 1) <= num_pairs) {
   1.113 +      ++max_pow2;
   1.114 +    }
   1.115 +    const uint16_t expected_search_range = (1u << max_pow2) * kFormat0PairSize;
   1.116 +    if (subtable.search_range != expected_search_range) {
   1.117 +      OTS_WARNING("bad search range");
   1.118 +      subtable.search_range = expected_search_range;
   1.119 +    }
   1.120 +    if (subtable.entry_selector != max_pow2) {
   1.121 +      return OTS_FAILURE_MSG("Bad subtable %d entry selector %d", i, subtable.entry_selector);
   1.122 +    }
   1.123 +    const uint32_t expected_range_shift
   1.124 +        = kFormat0PairSize * num_pairs - subtable.search_range;
   1.125 +    if (subtable.range_shift != expected_range_shift) {
   1.126 +      OTS_WARNING("bad range shift");
   1.127 +      subtable.range_shift = expected_range_shift;
   1.128 +    }
   1.129 +
   1.130 +    // Read kerning pairs.
   1.131 +    subtable.pairs.reserve(num_pairs);
   1.132 +    uint32_t last_pair = 0;
   1.133 +    for (unsigned j = 0; j < num_pairs; ++j) {
   1.134 +      OpenTypeKERNFormat0Pair kerning_pair;
   1.135 +      if (!table.ReadU16(&kerning_pair.left) ||
   1.136 +          !table.ReadU16(&kerning_pair.right) ||
   1.137 +          !table.ReadS16(&kerning_pair.value)) {
   1.138 +        return OTS_FAILURE_MSG("Failed to read subtable %d kerning pair %d", i, j);
   1.139 +      }
   1.140 +      const uint32_t current_pair
   1.141 +          = (kerning_pair.left << 16) + kerning_pair.right;
   1.142 +      if (j != 0 && current_pair <= last_pair) {
   1.143 +        OTS_WARNING("Kerning pairs are not sorted.");
   1.144 +        // Many free fonts don't follow this rule, so we don't call OTS_FAILURE
   1.145 +        // in order to support these fonts.
   1.146 +        DROP_THIS_TABLE;
   1.147 +        return true;
   1.148 +      }
   1.149 +      last_pair = current_pair;
   1.150 +      subtable.pairs.push_back(kerning_pair);
   1.151 +    }
   1.152 +
   1.153 +    kern->subtables.push_back(subtable);
   1.154 +  }
   1.155 +
   1.156 +  if (!kern->subtables.size()) {
   1.157 +    OTS_WARNING("All subtables are removed.");
   1.158 +    DROP_THIS_TABLE;
   1.159 +    return true;
   1.160 +  }
   1.161 +
   1.162 +  return true;
   1.163 +}
   1.164 +
   1.165 +bool ots_kern_should_serialise(OpenTypeFile *file) {
   1.166 +  if (!file->glyf) return false;  // this table is not for CFF fonts.
   1.167 +  return file->kern != NULL;
   1.168 +}
   1.169 +
   1.170 +bool ots_kern_serialise(OTSStream *out, OpenTypeFile *file) {
   1.171 +  const OpenTypeKERN *kern = file->kern;
   1.172 +
   1.173 +  if (!out->WriteU16(kern->version) ||
   1.174 +      !out->WriteU16(kern->subtables.size())) {
   1.175 +    return OTS_FAILURE_MSG("Can't write kern table header");
   1.176 +  }
   1.177 +
   1.178 +  for (unsigned i = 0; i < kern->subtables.size(); ++i) {
   1.179 +    const uint16_t length = 14 + (6 * kern->subtables[i].pairs.size());
   1.180 +    if (!out->WriteU16(kern->subtables[i].version) ||
   1.181 +        !out->WriteU16(length) ||
   1.182 +        !out->WriteU16(kern->subtables[i].coverage) ||
   1.183 +        !out->WriteU16(kern->subtables[i].pairs.size()) ||
   1.184 +        !out->WriteU16(kern->subtables[i].search_range) ||
   1.185 +        !out->WriteU16(kern->subtables[i].entry_selector) ||
   1.186 +        !out->WriteU16(kern->subtables[i].range_shift)) {
   1.187 +      return OTS_FAILURE_MSG("Failed to write kern subtable %d", i);
   1.188 +    }
   1.189 +    for (unsigned j = 0; j < kern->subtables[i].pairs.size(); ++j) {
   1.190 +      if (!out->WriteU16(kern->subtables[i].pairs[j].left) ||
   1.191 +          !out->WriteU16(kern->subtables[i].pairs[j].right) ||
   1.192 +          !out->WriteS16(kern->subtables[i].pairs[j].value)) {
   1.193 +        return OTS_FAILURE_MSG("Failed to write kern pair %d for subtable %d", j, i);
   1.194 +      }
   1.195 +    }
   1.196 +  }
   1.197 +
   1.198 +  return true;
   1.199 +}
   1.200 +
   1.201 +void ots_kern_free(OpenTypeFile *file) {
   1.202 +  delete file->kern;
   1.203 +}
   1.204 +
   1.205 +}  // namespace ots

mercurial