|
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/typography/otspec/gasp.htm |
|
9 |
|
10 #define TABLE_NAME "gasp" |
|
11 |
|
12 #define DROP_THIS_TABLE \ |
|
13 do { \ |
|
14 delete file->gasp; \ |
|
15 file->gasp = 0; \ |
|
16 OTS_FAILURE_MSG("Table discarded"); \ |
|
17 } while (0) |
|
18 |
|
19 namespace ots { |
|
20 |
|
21 bool ots_gasp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { |
|
22 Buffer table(data, length); |
|
23 |
|
24 OpenTypeGASP *gasp = new OpenTypeGASP; |
|
25 file->gasp = gasp; |
|
26 |
|
27 uint16_t num_ranges = 0; |
|
28 if (!table.ReadU16(&gasp->version) || |
|
29 !table.ReadU16(&num_ranges)) { |
|
30 return OTS_FAILURE_MSG("Failed to read table header"); |
|
31 } |
|
32 |
|
33 if (gasp->version > 1) { |
|
34 // Lots of Linux fonts have bad version numbers... |
|
35 OTS_WARNING("bad version: %u", gasp->version); |
|
36 DROP_THIS_TABLE; |
|
37 return true; |
|
38 } |
|
39 |
|
40 if (num_ranges == 0) { |
|
41 OTS_WARNING("num_ranges is zero"); |
|
42 DROP_THIS_TABLE; |
|
43 return true; |
|
44 } |
|
45 |
|
46 gasp->gasp_ranges.reserve(num_ranges); |
|
47 for (unsigned i = 0; i < num_ranges; ++i) { |
|
48 uint16_t max_ppem = 0; |
|
49 uint16_t behavior = 0; |
|
50 if (!table.ReadU16(&max_ppem) || |
|
51 !table.ReadU16(&behavior)) { |
|
52 return OTS_FAILURE_MSG("Failed to read subrange %d", i); |
|
53 } |
|
54 if ((i > 0) && (gasp->gasp_ranges[i - 1].first >= max_ppem)) { |
|
55 // The records in the gaspRange[] array must be sorted in order of |
|
56 // increasing rangeMaxPPEM value. |
|
57 OTS_WARNING("ranges are not sorted"); |
|
58 DROP_THIS_TABLE; |
|
59 return true; |
|
60 } |
|
61 if ((i == num_ranges - 1u) && // never underflow. |
|
62 (max_ppem != 0xffffu)) { |
|
63 OTS_WARNING("The last record should be 0xFFFF as a sentinel value " |
|
64 "for rangeMaxPPEM"); |
|
65 DROP_THIS_TABLE; |
|
66 return true; |
|
67 } |
|
68 |
|
69 if (behavior >> 8) { |
|
70 OTS_WARNING("undefined bits are used: %x", behavior); |
|
71 // mask undefined bits. |
|
72 behavior &= 0x000fu; |
|
73 } |
|
74 |
|
75 if (gasp->version == 0 && (behavior >> 2) != 0) { |
|
76 OTS_WARNING("changed the version number to 1"); |
|
77 gasp->version = 1; |
|
78 } |
|
79 |
|
80 gasp->gasp_ranges.push_back(std::make_pair(max_ppem, behavior)); |
|
81 } |
|
82 |
|
83 return true; |
|
84 } |
|
85 |
|
86 bool ots_gasp_should_serialise(OpenTypeFile *file) { |
|
87 return file->gasp != NULL; |
|
88 } |
|
89 |
|
90 bool ots_gasp_serialise(OTSStream *out, OpenTypeFile *file) { |
|
91 const OpenTypeGASP *gasp = file->gasp; |
|
92 |
|
93 if (!out->WriteU16(gasp->version) || |
|
94 !out->WriteU16(gasp->gasp_ranges.size())) { |
|
95 return OTS_FAILURE_MSG("failed to write gasp header"); |
|
96 } |
|
97 |
|
98 for (unsigned i = 0; i < gasp->gasp_ranges.size(); ++i) { |
|
99 if (!out->WriteU16(gasp->gasp_ranges[i].first) || |
|
100 !out->WriteU16(gasp->gasp_ranges[i].second)) { |
|
101 return OTS_FAILURE_MSG("Failed to write gasp subtable %d", i); |
|
102 } |
|
103 } |
|
104 |
|
105 return true; |
|
106 } |
|
107 |
|
108 void ots_gasp_free(OpenTypeFile *file) { |
|
109 delete file->gasp; |
|
110 } |
|
111 |
|
112 } // namespace ots |