Home | History | Annotate | Download | only in src
      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