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