Line | Count | Source |
1 | | // Copyright (c) 2018 The OTS 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 "avar.h" |
6 | | |
7 | | #include "fvar.h" |
8 | | |
9 | | #include "variations.h" |
10 | | |
11 | | namespace ots { |
12 | | |
13 | | // ----------------------------------------------------------------------------- |
14 | | // OpenTypeAVAR |
15 | | // ----------------------------------------------------------------------------- |
16 | | |
17 | 1.78k | bool OpenTypeAVAR::Parse(const uint8_t* data, size_t length) { |
18 | 1.78k | Buffer table(data, length); |
19 | 1.78k | if (!table.ReadU16(&this->majorVersion) || |
20 | 1.71k | !table.ReadU16(&this->minorVersion) || |
21 | 1.68k | !table.ReadU16(&this->reserved) || |
22 | 1.65k | !table.ReadU16(&this->axisCount)) { |
23 | 224 | return Drop("Failed to read table header"); |
24 | 224 | } |
25 | 1.55k | if (this->majorVersion > 2) { |
26 | 589 | return Drop("Unknown table version"); |
27 | 589 | } |
28 | 967 | if (this->majorVersion == 1) { |
29 | | // We can fix table |
30 | 372 | if (this->minorVersion > 0) { |
31 | | // we only know how to serialize version 1.0 |
32 | 226 | Warning("Downgrading minor version to 0"); |
33 | 226 | this->minorVersion = 0; |
34 | 226 | } |
35 | 372 | if (this->reserved != 0) { |
36 | 62 | Warning("Expected reserved=0"); |
37 | 62 | this->reserved = 0; |
38 | 62 | } |
39 | 595 | } else { |
40 | | // We serialize data unchanged, so drop even for minor errors |
41 | 595 | if (this->minorVersion > 0) { |
42 | 166 | return Drop("Unknown minor table version"); |
43 | 166 | } |
44 | 429 | if (this->reserved != 0) { |
45 | 79 | return Drop("Expected reserved=0"); |
46 | 79 | } |
47 | 429 | } |
48 | | |
49 | 722 | OpenTypeFVAR* fvar = static_cast<OpenTypeFVAR*>( |
50 | 722 | GetFont()->GetTypedTable(OTS_TAG_FVAR)); |
51 | 722 | if (!fvar) { |
52 | 258 | return DropVariations("Required fvar table is missing"); |
53 | 258 | } |
54 | 464 | if (axisCount != fvar->AxisCount()) { |
55 | 22 | return Drop("Axis count mismatch"); |
56 | 22 | } |
57 | | |
58 | 1.00k | for (size_t i = 0; i < this->axisCount; i++) { |
59 | 791 | this->axisSegmentMaps.emplace_back(); |
60 | 791 | uint16_t positionMapCount; |
61 | 791 | if (!table.ReadU16(&positionMapCount)) { |
62 | 7 | return Drop("Failed to read position map count"); |
63 | 7 | } |
64 | 784 | int foundRequiredMappings = 0; |
65 | 1.73k | for (size_t j = 0; j < positionMapCount; j++) { |
66 | 1.14k | AxisValueMap map; |
67 | 1.14k | if (!table.ReadS16(&map.fromCoordinate) || |
68 | 1.12k | !table.ReadS16(&map.toCoordinate)) { |
69 | 29 | return Drop("Failed to read axis value map"); |
70 | 29 | } |
71 | 1.11k | if (map.fromCoordinate < -0x4000 || |
72 | 1.10k | map.fromCoordinate > 0x4000 || |
73 | 1.08k | map.toCoordinate < -0x4000 || |
74 | 1.06k | map.toCoordinate > 0x4000) { |
75 | 68 | return Drop("Axis value map coordinate out of range"); |
76 | 68 | } |
77 | 1.04k | if (j > 0) { |
78 | 790 | if (map.fromCoordinate <= this->axisSegmentMaps[i].back().fromCoordinate || |
79 | 726 | map.toCoordinate < this->axisSegmentMaps[i].back().toCoordinate) { |
80 | 92 | return Drop("Axis value map out of order"); |
81 | 92 | } |
82 | 790 | } |
83 | 954 | if ((map.fromCoordinate == -0x4000 && map.toCoordinate == -0x4000) || |
84 | 852 | (map.fromCoordinate == 0 && map.toCoordinate == 0) || |
85 | 699 | (map.fromCoordinate == 0x4000 && map.toCoordinate == 0x4000)) { |
86 | 343 | ++foundRequiredMappings; |
87 | 343 | } |
88 | 954 | this->axisSegmentMaps[i].push_back(map); |
89 | 954 | } |
90 | 595 | if (positionMapCount > 0 && foundRequiredMappings != 3) { |
91 | 33 | return Drop("A required mapping (for -1, 0 or 1) is missing"); |
92 | 33 | } |
93 | 595 | } |
94 | | |
95 | 213 | if (this->majorVersion < 2) |
96 | 121 | return true; |
97 | | |
98 | 92 | uint32_t axisIndexMapOffset; |
99 | 92 | uint32_t varStoreOffset; |
100 | | |
101 | 92 | if (!table.ReadU32(&axisIndexMapOffset) || |
102 | 91 | !table.ReadU32(&varStoreOffset)) { |
103 | 2 | return Drop("Failed to read version 2 offsets"); |
104 | 2 | } |
105 | | |
106 | 90 | Font *font = GetFont(); |
107 | 90 | uint32_t headerSize = table.offset(); |
108 | | |
109 | 90 | if (axisIndexMapOffset) { |
110 | 87 | if (axisIndexMapOffset < headerSize || axisIndexMapOffset >= length) { |
111 | 15 | return Drop("Bad delta set index offset in table header"); |
112 | 15 | } |
113 | 72 | if (!ParseDeltaSetIndexMap(font, data + axisIndexMapOffset, length - axisIndexMapOffset)) { |
114 | 7 | return Drop("Failed to parse delta set index map"); |
115 | 7 | } |
116 | 72 | } |
117 | | |
118 | 68 | if (varStoreOffset) { |
119 | 65 | if (varStoreOffset < headerSize || varStoreOffset >= length) { |
120 | 23 | return Drop("Bad item variation store offset in table header"); |
121 | 23 | } |
122 | 42 | if (!ParseItemVariationStore(font, data + varStoreOffset, length - varStoreOffset)) { |
123 | 38 | return Drop("Failed to parse item variation store"); |
124 | 38 | } |
125 | 42 | } |
126 | | |
127 | 7 | this->m_data = data; |
128 | 7 | this->m_length = length; |
129 | | |
130 | 7 | return true; |
131 | 68 | } |
132 | | |
133 | 43 | bool OpenTypeAVAR::Serialize(OTSStream* out) { |
134 | 43 | if (this->majorVersion >= 2) { |
135 | 4 | if (!out->Write(this->m_data, this->m_length)) { |
136 | 0 | return Error("Failed to write table"); |
137 | 0 | } |
138 | 4 | return true; |
139 | 4 | } |
140 | | |
141 | 39 | if (!out->WriteU16(this->majorVersion) || |
142 | 39 | !out->WriteU16(this->minorVersion) || |
143 | 39 | !out->WriteU16(this->reserved) || |
144 | 39 | !out->WriteU16(this->axisCount)) { |
145 | 0 | return Error("Failed to write table"); |
146 | 0 | } |
147 | | |
148 | 106 | for (size_t i = 0; i < this->axisCount; i++) { |
149 | 67 | const auto& axisValueMap = this->axisSegmentMaps[i]; |
150 | 67 | if (!out->WriteU16(axisValueMap.size())) { |
151 | 0 | return Error("Failed to write table"); |
152 | 0 | } |
153 | 181 | for (size_t j = 0; j < axisValueMap.size(); j++) { |
154 | 114 | if (!out->WriteS16(axisValueMap[j].fromCoordinate) || |
155 | 114 | !out->WriteS16(axisValueMap[j].toCoordinate)) { |
156 | 0 | return Error("Failed to write table"); |
157 | 0 | } |
158 | 114 | } |
159 | 67 | } |
160 | | |
161 | 39 | return true; |
162 | 39 | } |
163 | | |
164 | | } // namespace ots |