1d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org// Use of this source code is governed by a BSD-style license that can be
3d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org// found in the LICENSE file.
4d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
5d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include "gasp.h"
6d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
7d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org// gasp - Grid-fitting And Scan-conversion Procedure
8d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org// http://www.microsoft.com/opentype/otspec/gasp.htm
9d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
10d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#define DROP_THIS_TABLE \
11d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  do { delete file->gasp; file->gasp = 0; } while (0)
12d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
13d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgnamespace ots {
14d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
15d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgbool ots_gasp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
16d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  Buffer table(data, length);
17d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
18d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  OpenTypeGASP *gasp = new OpenTypeGASP;
19d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  file->gasp = gasp;
20d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
218ad0a175fe440054932dd25ae9b4b1867e66d387yusukes@chromium.org  uint16_t num_ranges = 0;
22d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  if (!table.ReadU16(&gasp->version) ||
23d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      !table.ReadU16(&num_ranges)) {
24d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    return OTS_FAILURE();
25d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  }
26d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
27d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  if (gasp->version > 1) {
28d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    // Lots of Linux fonts have bad version numbers...
29d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    OTS_WARNING("bad version: %u", gasp->version);
30d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    DROP_THIS_TABLE;
31d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    return true;
32d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  }
33d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
34d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  if (num_ranges == 0) {
35d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    OTS_WARNING("num_ranges is zero");
36d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    DROP_THIS_TABLE;
37d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    return true;
38d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  }
39d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
40d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  gasp->gasp_ranges.reserve(num_ranges);
41d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  for (unsigned i = 0; i < num_ranges; ++i) {
428ad0a175fe440054932dd25ae9b4b1867e66d387yusukes@chromium.org    uint16_t max_ppem = 0;
438ad0a175fe440054932dd25ae9b4b1867e66d387yusukes@chromium.org    uint16_t behavior = 0;
44d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    if (!table.ReadU16(&max_ppem) ||
45d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org        !table.ReadU16(&behavior)) {
46d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      return OTS_FAILURE();
47d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    }
48d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    if ((i > 0) && (gasp->gasp_ranges[i - 1].first >= max_ppem)) {
49d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      // The records in the gaspRange[] array must be sorted in order of
50d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      // increasing rangeMaxPPEM value.
51d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      OTS_WARNING("ranges are not sorted");
52d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      DROP_THIS_TABLE;
53d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      return true;
54d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    }
55d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    if ((i == num_ranges - 1u) &&  // never underflow.
56d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org        (max_ppem != 0xffffu)) {
57d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      OTS_WARNING("The last record should be 0xFFFF as a sentinel value "
58d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org                  "for rangeMaxPPEM");
59d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      DROP_THIS_TABLE;
60d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      return true;
61d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    }
62d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
63d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    if (behavior >> 8) {
64d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      OTS_WARNING("undefined bits are used: %x", behavior);
65d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      // mask undefined bits.
66d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      behavior &= 0x000fu;
67d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    }
68d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
69d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    if (gasp->version == 0 && (behavior >> 2) != 0) {
70d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      OTS_WARNING("changed the version number to 1");
71d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      gasp->version = 1;
72d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    }
73d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
74d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    gasp->gasp_ranges.push_back(std::make_pair(max_ppem, behavior));
75d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  }
76d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
77d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  return true;
78d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org}
79d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
80d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgbool ots_gasp_should_serialise(OpenTypeFile *file) {
812beaf1d97c4ba6d953462003db9ddb104b53d196agl@chromium.org  return file->gasp != NULL;
82d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org}
83d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
84d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgbool ots_gasp_serialise(OTSStream *out, OpenTypeFile *file) {
85d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  const OpenTypeGASP *gasp = file->gasp;
86d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
87d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  if (!out->WriteU16(gasp->version) ||
88d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      !out->WriteU16(gasp->gasp_ranges.size())) {
89d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    return OTS_FAILURE();
90d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  }
91d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
92d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  for (unsigned i = 0; i < gasp->gasp_ranges.size(); ++i) {
93d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    if (!out->WriteU16(gasp->gasp_ranges[i].first) ||
94d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org        !out->WriteU16(gasp->gasp_ranges[i].second)) {
95d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      return OTS_FAILURE();
96d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    }
97d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  }
98d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
99d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  return true;
100d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org}
101d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
102d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgvoid ots_gasp_free(OpenTypeFile *file) {
103d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  delete file->gasp;
104d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org}
105d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
106d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org}  // namespace ots
107