gfx/ots/src/vdmx.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/ots/src/vdmx.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,183 @@
     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 "vdmx.h"
     1.9 +
    1.10 +// VDMX - Vertical Device Metrics
    1.11 +// http://www.microsoft.com/typography/otspec/vdmx.htm
    1.12 +
    1.13 +#define TABLE_NAME "VDMX"
    1.14 +
    1.15 +#define DROP_THIS_TABLE \
    1.16 +  do { \
    1.17 +    delete file->vdmx; \
    1.18 +    file->vdmx = 0; \
    1.19 +    OTS_FAILURE_MSG("Table discarded"); \
    1.20 +  } while (0)
    1.21 +
    1.22 +namespace ots {
    1.23 +
    1.24 +bool ots_vdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
    1.25 +  Buffer table(data, length);
    1.26 +  file->vdmx = new OpenTypeVDMX;
    1.27 +  OpenTypeVDMX * const vdmx = file->vdmx;
    1.28 +
    1.29 +  if (!table.ReadU16(&vdmx->version) ||
    1.30 +      !table.ReadU16(&vdmx->num_recs) ||
    1.31 +      !table.ReadU16(&vdmx->num_ratios)) {
    1.32 +    return OTS_FAILURE_MSG("Failed to read table header");
    1.33 +  }
    1.34 +
    1.35 +  if (vdmx->version > 1) {
    1.36 +    OTS_WARNING("bad version: %u", vdmx->version);
    1.37 +    DROP_THIS_TABLE;
    1.38 +    return true;  // continue transcoding
    1.39 +  }
    1.40 +
    1.41 +  vdmx->rat_ranges.reserve(vdmx->num_ratios);
    1.42 +  for (unsigned i = 0; i < vdmx->num_ratios; ++i) {
    1.43 +    OpenTypeVDMXRatioRecord rec;
    1.44 +
    1.45 +    if (!table.ReadU8(&rec.charset) ||
    1.46 +        !table.ReadU8(&rec.x_ratio) ||
    1.47 +        !table.ReadU8(&rec.y_start_ratio) ||
    1.48 +        !table.ReadU8(&rec.y_end_ratio)) {
    1.49 +      return OTS_FAILURE_MSG("Failed to read ratio header %d", i);
    1.50 +    }
    1.51 +
    1.52 +    if (rec.charset > 1) {
    1.53 +      OTS_WARNING("bad charset: %u", rec.charset);
    1.54 +      DROP_THIS_TABLE;
    1.55 +      return true;
    1.56 +    }
    1.57 +
    1.58 +    if (rec.y_start_ratio > rec.y_end_ratio) {
    1.59 +      OTS_WARNING("bad y ratio");
    1.60 +      DROP_THIS_TABLE;
    1.61 +      return true;
    1.62 +    }
    1.63 +
    1.64 +    // All values set to zero signal the default grouping to use;
    1.65 +    // if present, this must be the last Ratio group in the table.
    1.66 +    if ((i < vdmx->num_ratios - 1u) &&
    1.67 +        (rec.x_ratio == 0) &&
    1.68 +        (rec.y_start_ratio == 0) &&
    1.69 +        (rec.y_end_ratio == 0)) {
    1.70 +      // workaround for fonts which have 2 or more {0, 0, 0} terminators.
    1.71 +      OTS_WARNING("superfluous terminator found");
    1.72 +      DROP_THIS_TABLE;
    1.73 +      return true;
    1.74 +    }
    1.75 +
    1.76 +    vdmx->rat_ranges.push_back(rec);
    1.77 +  }
    1.78 +
    1.79 +  vdmx->offsets.reserve(vdmx->num_ratios);
    1.80 +  const size_t current_offset = table.offset();
    1.81 +  // current_offset is less than (2 bytes * 3) + (4 bytes * USHRT_MAX) = 256k.
    1.82 +  for (unsigned i = 0; i < vdmx->num_ratios; ++i) {
    1.83 +    uint16_t offset;
    1.84 +    if (!table.ReadU16(&offset)) {
    1.85 +      return OTS_FAILURE_MSG("Failed to read ratio offset %d", i);
    1.86 +    }
    1.87 +    if (current_offset + offset >= length) {  // thus doesn't overflow.
    1.88 +      return OTS_FAILURE_MSG("Bad ratio offset %d for ration %d", offset, i);
    1.89 +    }
    1.90 +
    1.91 +    vdmx->offsets.push_back(offset);
    1.92 +  }
    1.93 +
    1.94 +  vdmx->groups.reserve(vdmx->num_recs);
    1.95 +  for (unsigned i = 0; i < vdmx->num_recs; ++i) {
    1.96 +    OpenTypeVDMXGroup group;
    1.97 +    if (!table.ReadU16(&group.recs) ||
    1.98 +        !table.ReadU8(&group.startsz) ||
    1.99 +        !table.ReadU8(&group.endsz)) {
   1.100 +      return OTS_FAILURE_MSG("Failed to read record header %d", i);
   1.101 +    }
   1.102 +    group.entries.reserve(group.recs);
   1.103 +    for (unsigned j = 0; j < group.recs; ++j) {
   1.104 +      OpenTypeVDMXVTable vt;
   1.105 +      if (!table.ReadU16(&vt.y_pel_height) ||
   1.106 +          !table.ReadS16(&vt.y_max) ||
   1.107 +          !table.ReadS16(&vt.y_min)) {
   1.108 +        return OTS_FAILURE_MSG("Failed to read reacord %d group %d", i, j);
   1.109 +      }
   1.110 +      if (vt.y_max < vt.y_min) {
   1.111 +        OTS_WARNING("bad y min/max");
   1.112 +        DROP_THIS_TABLE;
   1.113 +        return true;
   1.114 +      }
   1.115 +
   1.116 +      // This table must appear in sorted order (sorted by yPelHeight),
   1.117 +      // but need not be continuous.
   1.118 +      if ((j != 0) && (group.entries[j - 1].y_pel_height >= vt.y_pel_height)) {
   1.119 +        OTS_WARNING("the table is not sorted");
   1.120 +        DROP_THIS_TABLE;
   1.121 +        return true;
   1.122 +      }
   1.123 +
   1.124 +      group.entries.push_back(vt);
   1.125 +    }
   1.126 +    vdmx->groups.push_back(group);
   1.127 +  }
   1.128 +
   1.129 +  return true;
   1.130 +}
   1.131 +
   1.132 +bool ots_vdmx_should_serialise(OpenTypeFile *file) {
   1.133 +  if (!file->glyf) return false;  // this table is not for CFF fonts.
   1.134 +  return file->vdmx != NULL;
   1.135 +}
   1.136 +
   1.137 +bool ots_vdmx_serialise(OTSStream *out, OpenTypeFile *file) {
   1.138 +  OpenTypeVDMX * const vdmx = file->vdmx;
   1.139 +
   1.140 +  if (!out->WriteU16(vdmx->version) ||
   1.141 +      !out->WriteU16(vdmx->num_recs) ||
   1.142 +      !out->WriteU16(vdmx->num_ratios)) {
   1.143 +    return OTS_FAILURE_MSG("Failed to write table header");
   1.144 +  }
   1.145 +
   1.146 +  for (unsigned i = 0; i < vdmx->rat_ranges.size(); ++i) {
   1.147 +    const OpenTypeVDMXRatioRecord& rec = vdmx->rat_ranges[i];
   1.148 +    if (!out->Write(&rec.charset, 1) ||
   1.149 +        !out->Write(&rec.x_ratio, 1) ||
   1.150 +        !out->Write(&rec.y_start_ratio, 1) ||
   1.151 +        !out->Write(&rec.y_end_ratio, 1)) {
   1.152 +      return OTS_FAILURE_MSG("Failed to write ratio %d", i);
   1.153 +    }
   1.154 +  }
   1.155 +
   1.156 +  for (unsigned i = 0; i < vdmx->offsets.size(); ++i) {
   1.157 +    if (!out->WriteU16(vdmx->offsets[i])) {
   1.158 +      return OTS_FAILURE_MSG("Failed to write ratio offset %d", i);
   1.159 +    }
   1.160 +  }
   1.161 +
   1.162 +  for (unsigned i = 0; i < vdmx->groups.size(); ++i) {
   1.163 +    const OpenTypeVDMXGroup& group = vdmx->groups[i];
   1.164 +    if (!out->WriteU16(group.recs) ||
   1.165 +        !out->Write(&group.startsz, 1) ||
   1.166 +        !out->Write(&group.endsz, 1)) {
   1.167 +      return OTS_FAILURE_MSG("Failed to write group %d", i);
   1.168 +    }
   1.169 +    for (unsigned j = 0; j < group.entries.size(); ++j) {
   1.170 +      const OpenTypeVDMXVTable& vt = group.entries[j];
   1.171 +      if (!out->WriteU16(vt.y_pel_height) ||
   1.172 +          !out->WriteS16(vt.y_max) ||
   1.173 +          !out->WriteS16(vt.y_min)) {
   1.174 +        return OTS_FAILURE_MSG("Failed to write group %d entry %d", i, j);
   1.175 +      }
   1.176 +    }
   1.177 +  }
   1.178 +
   1.179 +  return true;
   1.180 +}
   1.181 +
   1.182 +void ots_vdmx_free(OpenTypeFile *file) {
   1.183 +  delete file->vdmx;
   1.184 +}
   1.185 +
   1.186 +}  // namespace ots

mercurial