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
ots_gasp_parse(OpenTypeFile * file,const uint8_t * data,size_t length)15 bool ots_gasp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
16 Buffer table(data, length);
17
18 OpenTypeGASP *gasp = new OpenTypeGASP;
19 file->gasp = gasp;
20
21 uint16_t num_ranges = 0;
22 if (!table.ReadU16(&gasp->version) ||
23 !table.ReadU16(&num_ranges)) {
24 return OTS_FAILURE();
25 }
26
27 if (gasp->version > 1) {
28 // Lots of Linux fonts have bad version numbers...
29 OTS_WARNING("bad version: %u", gasp->version);
30 DROP_THIS_TABLE;
31 return true;
32 }
33
34 if (num_ranges == 0) {
35 OTS_WARNING("num_ranges is zero");
36 DROP_THIS_TABLE;
37 return true;
38 }
39
40 gasp->gasp_ranges.reserve(num_ranges);
41 for (unsigned i = 0; i < num_ranges; ++i) {
42 uint16_t max_ppem = 0;
43 uint16_t behavior = 0;
44 if (!table.ReadU16(&max_ppem) ||
45 !table.ReadU16(&behavior)) {
46 return OTS_FAILURE();
47 }
48 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 DROP_THIS_TABLE;
53 return true;
54 }
55 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 DROP_THIS_TABLE;
60 return true;
61 }
62
63 if (behavior >> 8) {
64 OTS_WARNING("undefined bits are used: %x", behavior);
65 // mask undefined bits.
66 behavior &= 0x000fu;
67 }
68
69 if (gasp->version == 0 && (behavior >> 2) != 0) {
70 OTS_WARNING("changed the version number to 1");
71 gasp->version = 1;
72 }
73
74 gasp->gasp_ranges.push_back(std::make_pair(max_ppem, behavior));
75 }
76
77 return true;
78 }
79
ots_gasp_should_serialise(OpenTypeFile * file)80 bool ots_gasp_should_serialise(OpenTypeFile *file) {
81 return file->gasp != NULL;
82 }
83
ots_gasp_serialise(OTSStream * out,OpenTypeFile * file)84 bool ots_gasp_serialise(OTSStream *out, OpenTypeFile *file) {
85 const OpenTypeGASP *gasp = file->gasp;
86
87 if (!out->WriteU16(gasp->version) ||
88 !out->WriteU16(gasp->gasp_ranges.size())) {
89 return OTS_FAILURE();
90 }
91
92 for (unsigned i = 0; i < gasp->gasp_ranges.size(); ++i) {
93 if (!out->WriteU16(gasp->gasp_ranges[i].first) ||
94 !out->WriteU16(gasp->gasp_ranges[i].second)) {
95 return OTS_FAILURE();
96 }
97 }
98
99 return true;
100 }
101
ots_gasp_free(OpenTypeFile * file)102 void ots_gasp_free(OpenTypeFile *file) {
103 delete file->gasp;
104 }
105
106 } // namespace ots
107