yusukes@chromium.org | d257d18 | 2009-11-04 04:56:32 +0000 | [diff] [blame] | 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 | |
yusukes@chromium.org | 8ad0a17 | 2009-11-04 06:07:58 +0000 | [diff] [blame] | 21 | uint16_t num_ranges = 0; |
yusukes@chromium.org | d257d18 | 2009-11-04 04:56:32 +0000 | [diff] [blame] | 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) { |
yusukes@chromium.org | 8ad0a17 | 2009-11-04 06:07:58 +0000 | [diff] [blame] | 42 | uint16_t max_ppem = 0; |
| 43 | uint16_t behavior = 0; |
yusukes@chromium.org | d257d18 | 2009-11-04 04:56:32 +0000 | [diff] [blame] | 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) { |
agl@chromium.org | 2beaf1d | 2011-01-21 17:19:34 +0000 | [diff] [blame] | 81 | return file->gasp != NULL; |
yusukes@chromium.org | d257d18 | 2009-11-04 04:56:32 +0000 | [diff] [blame] | 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 |