Backed out 3 changesets (bug 1918178) for causing reftest failures. a=backout
[gecko.git] / gfx / ots / src / glat.cc
blob626f9b0cdb05b3254fe109ec50c561b12f5298a7
1 // Copyright (c) 2009-2017 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.
5 #include "glat.h"
7 #include "gloc.h"
8 #include "mozilla/Compression.h"
9 #include <list>
10 #include <memory>
12 namespace ots {
14 // -----------------------------------------------------------------------------
15 // OpenTypeGLAT_v1
16 // -----------------------------------------------------------------------------
18 bool OpenTypeGLAT_v1::Parse(const uint8_t* data, size_t length) {
19 Buffer table(data, length);
20 OpenTypeGLOC* gloc = static_cast<OpenTypeGLOC*>(
21 GetFont()->GetTypedTable(OTS_TAG_GLOC));
22 if (!gloc) {
23 return DropGraphite("Required Gloc table is missing");
26 if (!table.ReadU32(&this->version) || this->version >> 16 != 1) {
27 return DropGraphite("Failed to read version");
30 const std::vector<uint32_t>& locations = gloc->GetLocations();
31 if (locations.empty()) {
32 return DropGraphite("No locations from Gloc table");
34 std::list<uint32_t> unverified(locations.begin(), locations.end());
35 while (table.remaining()) {
36 GlatEntry entry(this);
37 if (table.offset() > unverified.front()) {
38 return DropGraphite("Offset check failed for a GlatEntry");
40 if (table.offset() == unverified.front()) {
41 unverified.pop_front();
43 if (unverified.empty()) {
44 return DropGraphite("Expected more locations");
46 if (!entry.ParsePart(table)) {
47 return DropGraphite("Failed to read a GlatEntry");
49 this->entries.push_back(entry);
52 if (unverified.size() != 1 || unverified.front() != table.offset()) {
53 return DropGraphite("%zu location(s) could not be verified", unverified.size());
55 if (table.remaining()) {
56 return Warning("%zu bytes unparsed", table.remaining());
58 return true;
61 bool OpenTypeGLAT_v1::Serialize(OTSStream* out) {
62 assert(ShouldSerialize());
63 if (!out->WriteU32(this->version) ||
64 !SerializeParts(this->entries, out)) {
65 return Error("Failed to write table");
67 return true;
70 bool OpenTypeGLAT_v1::GlatEntry::ParsePart(Buffer& table) {
71 if (!table.ReadU8(&this->attNum)) {
72 return parent->Error("GlatEntry: Failed to read attNum");
74 if (!table.ReadU8(&this->num)) {
75 return parent->Error("GlatEntry: Failed to read num");
78 //this->attributes.resize(this->num);
79 for (int i = 0; i < this->num; ++i) {
80 this->attributes.emplace_back();
81 if (!table.ReadS16(&this->attributes[i])) {
82 return parent->Error("GlatEntry: Failed to read attribute %u", i);
85 return true;
88 bool OpenTypeGLAT_v1::GlatEntry::SerializePart(OTSStream* out) const {
89 if (!out->WriteU8(this->attNum) ||
90 !out->WriteU8(this->num) ||
91 !SerializeParts(this->attributes, out)) {
92 return parent->Error("GlatEntry: Failed to write");
94 return true;
97 // -----------------------------------------------------------------------------
98 // OpenTypeGLAT_v2
99 // -----------------------------------------------------------------------------
101 bool OpenTypeGLAT_v2::Parse(const uint8_t* data, size_t length) {
102 Buffer table(data, length);
103 OpenTypeGLOC* gloc = static_cast<OpenTypeGLOC*>(
104 GetFont()->GetTypedTable(OTS_TAG_GLOC));
105 if (!gloc) {
106 return DropGraphite("Required Gloc table is missing");
109 if (!table.ReadU32(&this->version) || this->version >> 16 != 1) {
110 return DropGraphite("Failed to read version");
113 const std::vector<uint32_t>& locations = gloc->GetLocations();
114 if (locations.empty()) {
115 return DropGraphite("No locations from Gloc table");
117 std::list<uint32_t> unverified(locations.begin(), locations.end());
118 while (table.remaining()) {
119 GlatEntry entry(this);
120 if (table.offset() > unverified.front()) {
121 return DropGraphite("Offset check failed for a GlatEntry");
123 if (table.offset() == unverified.front()) {
124 unverified.pop_front();
126 if (unverified.empty()) {
127 return DropGraphite("Expected more locations");
129 if (!entry.ParsePart(table)) {
130 return DropGraphite("Failed to read a GlatEntry");
132 this->entries.push_back(entry);
135 if (unverified.size() != 1 || unverified.front() != table.offset()) {
136 return DropGraphite("%zu location(s) could not be verified", unverified.size());
138 if (table.remaining()) {
139 return Warning("%zu bytes unparsed", table.remaining());
141 return true;
144 bool OpenTypeGLAT_v2::Serialize(OTSStream* out) {
145 assert(ShouldSerialize());
146 if (!out->WriteU32(this->version) ||
147 !SerializeParts(this->entries, out)) {
148 return Error("Failed to write table");
150 return true;
153 bool OpenTypeGLAT_v2::GlatEntry::ParsePart(Buffer& table) {
154 if (!table.ReadS16(&this->attNum)) {
155 return parent->Error("GlatEntry: Failed to read attNum");
157 if (!table.ReadS16(&this->num) || this->num < 0) {
158 return parent->Error("GlatEntry: Failed to read valid num");
161 //this->attributes.resize(this->num);
162 for (int i = 0; i < this->num; ++i) {
163 this->attributes.emplace_back();
164 if (!table.ReadS16(&this->attributes[i])) {
165 return parent->Error("GlatEntry: Failed to read attribute %u", i);
168 return true;
171 bool OpenTypeGLAT_v2::GlatEntry::SerializePart(OTSStream* out) const {
172 if (!out->WriteS16(this->attNum) ||
173 !out->WriteS16(this->num) ||
174 !SerializeParts(this->attributes, out)) {
175 return parent->Error("GlatEntry: Failed to write");
177 return true;
180 // -----------------------------------------------------------------------------
181 // OpenTypeGLAT_v3
182 // -----------------------------------------------------------------------------
184 bool OpenTypeGLAT_v3::Parse(const uint8_t* data, size_t length,
185 bool prevent_decompression) {
186 Buffer table(data, length);
187 OpenTypeGLOC* gloc = static_cast<OpenTypeGLOC*>(
188 GetFont()->GetTypedTable(OTS_TAG_GLOC));
189 if (!gloc) {
190 return DropGraphite("Required Gloc table is missing");
193 if (!table.ReadU32(&this->version) || this->version >> 16 != 3) {
194 return DropGraphite("Failed to read version");
196 if (!table.ReadU32(&this->compHead)) {
197 return DropGraphite("Failed to read compression header");
199 switch ((this->compHead & SCHEME) >> 27) {
200 case 0: // uncompressed
201 break;
202 case 1: { // lz4
203 if (prevent_decompression) {
204 return DropGraphite("Illegal nested compression");
206 size_t decompressed_size = this->compHead & FULL_SIZE;
207 if (decompressed_size < length) {
208 return DropGraphite("Decompressed size is less than compressed size");
210 if (decompressed_size == 0) {
211 return DropGraphite("Decompressed size is set to 0");
213 // decompressed table must be <= OTS_MAX_DECOMPRESSED_TABLE_SIZE
214 if (decompressed_size > OTS_MAX_DECOMPRESSED_TABLE_SIZE) {
215 return DropGraphite("Decompressed size exceeds %gMB: %gMB",
216 OTS_MAX_DECOMPRESSED_TABLE_SIZE / (1024.0 * 1024.0),
217 decompressed_size / (1024.0 * 1024.0));
219 std::unique_ptr<uint8_t> decompressed(new uint8_t[decompressed_size]());
220 size_t outputSize = 0;
221 bool ret = mozilla::Compression::LZ4::decompressPartial(
222 reinterpret_cast<const char*>(data + table.offset()),
223 table.remaining(), // input buffer size (input size + padding)
224 reinterpret_cast<char*>(decompressed.get()),
225 decompressed_size, // target output size
226 &outputSize); // return output size
227 if (!ret || outputSize != decompressed_size) {
228 return DropGraphite("Decompression failed");
230 return this->Parse(decompressed.get(), decompressed_size, true);
232 default:
233 return DropGraphite("Unknown compression scheme");
235 if (this->compHead & RESERVED) {
236 Warning("Nonzero reserved");
239 const std::vector<uint32_t>& locations = gloc->GetLocations();
240 if (locations.empty()) {
241 return DropGraphite("No locations from Gloc table");
243 std::list<uint32_t> unverified(locations.begin(), locations.end());
244 //this->entries.resize(locations.size() - 1, this);
245 for (size_t i = 0; i < locations.size() - 1; ++i) {
246 this->entries.emplace_back(this);
247 if (table.offset() != unverified.front()) {
248 return DropGraphite("Offset check failed for a GlyphAttrs");
250 unverified.pop_front();
251 if (!this->entries[i].ParsePart(table,
252 unverified.front() - table.offset())) {
253 // unverified.front() is guaranteed to exist because of the number of
254 // iterations of this loop
255 return DropGraphite("Failed to read a GlyphAttrs");
259 if (unverified.size() != 1 || unverified.front() != table.offset()) {
260 return DropGraphite("%zu location(s) could not be verified", unverified.size());
262 if (table.remaining()) {
263 return Warning("%zu bytes unparsed", table.remaining());
265 return true;
268 bool OpenTypeGLAT_v3::Serialize(OTSStream* out) {
269 assert(ShouldSerialize());
270 if (!out->WriteU32(this->version) ||
271 !out->WriteU32(this->compHead) ||
272 !SerializeParts(this->entries, out)) {
273 return Error("Failed to write table");
275 return true;
278 bool OpenTypeGLAT_v3::GlyphAttrs::ParsePart(Buffer& table, const size_t size) {
279 size_t init_offset = table.offset();
280 if (parent->compHead & OCTABOXES && !octabox.ParsePart(table)) {
281 // parent->flags & 0b1: octaboxes are present flag
282 return parent->Error("GlyphAttrs: Failed to read octabox");
285 while (table.offset() < init_offset + size) {
286 GlatEntry entry(parent);
287 if (!entry.ParsePart(table)) {
288 return parent->Error("GlyphAttrs: Failed to read a GlatEntry");
290 this->entries.push_back(entry);
292 return true;
295 bool OpenTypeGLAT_v3::GlyphAttrs::SerializePart(OTSStream* out) const {
296 if ((parent->compHead & OCTABOXES && !octabox.SerializePart(out)) ||
297 !SerializeParts(this->entries, out)) {
298 return parent->Error("GlyphAttrs: Failed to write");
300 return true;
303 bool OpenTypeGLAT_v3::GlyphAttrs::
304 OctaboxMetrics::ParsePart(Buffer& table) {
305 if (!table.ReadU16(&this->subbox_bitmap)) {
306 return parent->Error("OctaboxMetrics: Failed to read subbox_bitmap");
308 if (!table.ReadU8(&this->diag_neg_min)) {
309 return parent->Error("OctaboxMetrics: Failed to read diag_neg_min");
311 if (!table.ReadU8(&this->diag_neg_max) ||
312 this->diag_neg_max < this->diag_neg_min) {
313 return parent->Error("OctaboxMetrics: Failed to read valid diag_neg_max");
315 if (!table.ReadU8(&this->diag_pos_min)) {
316 return parent->Error("OctaboxMetrics: Failed to read diag_pos_min");
318 if (!table.ReadU8(&this->diag_pos_max) ||
319 this->diag_pos_max < this->diag_pos_min) {
320 return parent->Error("OctaboxMetrics: Failed to read valid diag_pos_max");
323 unsigned subboxes_len = 0; // count of 1's in this->subbox_bitmap
324 for (uint16_t i = this->subbox_bitmap; i; i >>= 1) {
325 if (i & 0b1) {
326 ++subboxes_len;
329 //this->subboxes.resize(subboxes_len, parent);
330 for (unsigned i = 0; i < subboxes_len; i++) {
331 this->subboxes.emplace_back(parent);
332 if (!this->subboxes[i].ParsePart(table)) {
333 return parent->Error("OctaboxMetrics: Failed to read subbox[%u]", i);
336 return true;
339 bool OpenTypeGLAT_v3::GlyphAttrs::
340 OctaboxMetrics::SerializePart(OTSStream* out) const {
341 if (!out->WriteU16(this->subbox_bitmap) ||
342 !out->WriteU8(this->diag_neg_min) ||
343 !out->WriteU8(this->diag_neg_max) ||
344 !out->WriteU8(this->diag_pos_min) ||
345 !out->WriteU8(this->diag_pos_max) ||
346 !SerializeParts(this->subboxes, out)) {
347 return parent->Error("OctaboxMetrics: Failed to write");
349 return true;
352 bool OpenTypeGLAT_v3::GlyphAttrs::OctaboxMetrics::
353 SubboxEntry::ParsePart(Buffer& table) {
354 if (!table.ReadU8(&this->left)) {
355 return parent->Error("SubboxEntry: Failed to read left");
357 if (!table.ReadU8(&this->right) || this->right < this->left) {
358 return parent->Error("SubboxEntry: Failed to read valid right");
360 if (!table.ReadU8(&this->bottom)) {
361 return parent->Error("SubboxEntry: Failed to read bottom");
363 if (!table.ReadU8(&this->top) || this->top < this->bottom) {
364 return parent->Error("SubboxEntry: Failed to read valid top");
366 if (!table.ReadU8(&this->diag_pos_min)) {
367 return parent->Error("SubboxEntry: Failed to read diag_pos_min");
369 if (!table.ReadU8(&this->diag_pos_max) ||
370 this->diag_pos_max < this->diag_pos_min) {
371 return parent->Error("SubboxEntry: Failed to read valid diag_pos_max");
373 if (!table.ReadU8(&this->diag_neg_min)) {
374 return parent->Error("SubboxEntry: Failed to read diag_neg_min");
376 if (!table.ReadU8(&this->diag_neg_max) ||
377 this->diag_neg_max < this->diag_neg_min) {
378 return parent->Error("SubboxEntry: Failed to read valid diag_neg_max");
380 return true;
383 bool OpenTypeGLAT_v3::GlyphAttrs::OctaboxMetrics::
384 SubboxEntry::SerializePart(OTSStream* out) const {
385 if (!out->WriteU8(this->left) ||
386 !out->WriteU8(this->right) ||
387 !out->WriteU8(this->bottom) ||
388 !out->WriteU8(this->top) ||
389 !out->WriteU8(this->diag_pos_min) ||
390 !out->WriteU8(this->diag_pos_max) ||
391 !out->WriteU8(this->diag_neg_min) ||
392 !out->WriteU8(this->diag_neg_max)) {
393 return parent->Error("SubboxEntry: Failed to write");
395 return true;
398 bool OpenTypeGLAT_v3::GlyphAttrs::
399 GlatEntry::ParsePart(Buffer& table) {
400 if (!table.ReadS16(&this->attNum)) {
401 return parent->Error("GlatEntry: Failed to read attNum");
403 if (!table.ReadS16(&this->num) || this->num < 0) {
404 return parent->Error("GlatEntry: Failed to read valid num");
407 //this->attributes.resize(this->num);
408 for (int i = 0; i < this->num; ++i) {
409 this->attributes.emplace_back();
410 if (!table.ReadS16(&this->attributes[i])) {
411 return parent->Error("GlatEntry: Failed to read attribute %u", i);
414 return true;
417 bool OpenTypeGLAT_v3::GlyphAttrs::
418 GlatEntry::SerializePart(OTSStream* out) const {
419 if (!out->WriteS16(this->attNum) ||
420 !out->WriteS16(this->num) ||
421 !SerializeParts(this->attributes, out)) {
422 return parent->Error("GlatEntry: Failed to write");
424 return true;
427 // -----------------------------------------------------------------------------
428 // OpenTypeGLAT
429 // -----------------------------------------------------------------------------
431 bool OpenTypeGLAT::Parse(const uint8_t* data, size_t length) {
432 Buffer table(data, length);
433 uint32_t version;
434 if (!table.ReadU32(&version)) {
435 return DropGraphite("Failed to read version");
437 switch (version >> 16) {
438 case 1:
439 this->handler = new OpenTypeGLAT_v1(this->font, this->tag);
440 break;
441 case 2:
442 this->handler = new OpenTypeGLAT_v2(this->font, this->tag);
443 break;
444 case 3: {
445 this->handler = new OpenTypeGLAT_v3(this->font, this->tag);
446 break;
448 default:
449 return DropGraphite("Unsupported table version: %u", version >> 16);
451 return this->handler->Parse(data, length);
454 bool OpenTypeGLAT::Serialize(OTSStream* out) {
455 if (!this->handler) {
456 return Error("No Glat table parsed");
458 return this->handler->Serialize(out);
461 } // namespace ots