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 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 80 bool ots_gasp_should_serialise(OpenTypeFile *file) { 81 return file->gasp != NULL; 82 } 83 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 102 void ots_gasp_free(OpenTypeFile *file) { 103 delete file->gasp; 104 } 105 106 } // namespace ots 107