Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2011 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 "metrics.h"
      6 
      7 #include "head.h"
      8 #include "maxp.h"
      9 
     10 // OpenType horizontal and vertical common header format
     11 // http://www.microsoft.com/opentype/otspec/hhea.htm
     12 // http://www.microsoft.com/opentype/otspec/vhea.htm
     13 
     14 namespace ots {
     15 
     16 bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table,
     17                         OpenTypeMetricsHeader *header) {
     18   if (!table->ReadS16(&header->ascent) ||
     19       !table->ReadS16(&header->descent) ||
     20       !table->ReadS16(&header->linegap) ||
     21       !table->ReadU16(&header->adv_width_max) ||
     22       !table->ReadS16(&header->min_sb1) ||
     23       !table->ReadS16(&header->min_sb2) ||
     24       !table->ReadS16(&header->max_extent) ||
     25       !table->ReadS16(&header->caret_slope_rise) ||
     26       !table->ReadS16(&header->caret_slope_run) ||
     27       !table->ReadS16(&header->caret_offset)) {
     28     return OTS_FAILURE();
     29   }
     30 
     31   if (header->ascent < 0) {
     32     OTS_WARNING("bad ascent: %d", header->ascent);
     33     header->ascent = 0;
     34   }
     35   if (header->linegap < 0) {
     36     OTS_WARNING("bad linegap: %d", header->linegap);
     37     header->linegap = 0;
     38   }
     39 
     40   if (!file->head) {
     41     return OTS_FAILURE();
     42   }
     43 
     44   // if the font is non-slanted, caret_offset should be zero.
     45   if (!(file->head->mac_style & 2) &&
     46       (header->caret_offset != 0)) {
     47     OTS_WARNING("bad caret offset: %d", header->caret_offset);
     48     header->caret_offset = 0;
     49   }
     50 
     51   // skip the reserved bytes
     52   if (!table->Skip(8)) {
     53     return OTS_FAILURE();
     54   }
     55 
     56   int16_t data_format;
     57   if (!table->ReadS16(&data_format)) {
     58     return OTS_FAILURE();
     59   }
     60   if (data_format) {
     61     return OTS_FAILURE();
     62   }
     63 
     64   if (!table->ReadU16(&header->num_metrics)) {
     65     return OTS_FAILURE();
     66   }
     67 
     68   if (!file->maxp) {
     69     return OTS_FAILURE();
     70   }
     71 
     72   if (header->num_metrics > file->maxp->num_glyphs) {
     73     return OTS_FAILURE();
     74   }
     75 
     76   return true;
     77 }
     78 
     79 bool SerialiseMetricsHeader(OTSStream *out,
     80                             const OpenTypeMetricsHeader *header) {
     81   if (!out->WriteU32(header->version) ||
     82       !out->WriteS16(header->ascent) ||
     83       !out->WriteS16(header->descent) ||
     84       !out->WriteS16(header->linegap) ||
     85       !out->WriteU16(header->adv_width_max) ||
     86       !out->WriteS16(header->min_sb1) ||
     87       !out->WriteS16(header->min_sb2) ||
     88       !out->WriteS16(header->max_extent) ||
     89       !out->WriteS16(header->caret_slope_rise) ||
     90       !out->WriteS16(header->caret_slope_run) ||
     91       !out->WriteS16(header->caret_offset) ||
     92       !out->WriteR64(0) ||  // reserved
     93       !out->WriteS16(0) ||  // metric data format
     94       !out->WriteU16(header->num_metrics)) {
     95     return OTS_FAILURE();
     96   }
     97 
     98   return true;
     99 }
    100 
    101 bool ParseMetricsTable(Buffer *table,
    102                        const uint16_t num_glyphs,
    103                        const OpenTypeMetricsHeader *header,
    104                        OpenTypeMetricsTable *metrics) {
    105   // |num_metrics| is a uint16_t, so it's bounded < 65536. This limits that
    106   // amount of memory that we'll allocate for this to a sane amount.
    107   const unsigned num_metrics = header->num_metrics;
    108 
    109   if (num_metrics > num_glyphs) {
    110     return OTS_FAILURE();
    111   }
    112   if (!num_metrics) {
    113     return OTS_FAILURE();
    114   }
    115   const unsigned num_sbs = num_glyphs - num_metrics;
    116 
    117   metrics->entries.reserve(num_metrics);
    118   for (unsigned i = 0; i < num_metrics; ++i) {
    119     uint16_t adv = 0;
    120     int16_t sb = 0;
    121     if (!table->ReadU16(&adv) || !table->ReadS16(&sb)) {
    122       return OTS_FAILURE();
    123     }
    124 
    125     // Since so many fonts don't have proper value on |adv| and |sb|,
    126     // we should not call ots_failure() here. For example, about 20% of fonts
    127     // in http://www.princexml.com/fonts/ (200+ fonts) fails these tests.
    128     if (adv > header->adv_width_max) {
    129       OTS_WARNING("bad adv: %u > %u", adv, header->adv_width_max);
    130       adv = header->adv_width_max;
    131     }
    132 
    133     if (sb < header->min_sb1) {
    134       OTS_WARNING("bad sb: %d < %d", sb, header->min_sb1);
    135       sb = header->min_sb1;
    136     }
    137 
    138     metrics->entries.push_back(std::make_pair(adv, sb));
    139   }
    140 
    141   metrics->sbs.reserve(num_sbs);
    142   for (unsigned i = 0; i < num_sbs; ++i) {
    143     int16_t sb;
    144     if (!table->ReadS16(&sb)) {
    145       // Some Japanese fonts (e.g., mona.ttf) fail this test.
    146       return OTS_FAILURE();
    147     }
    148 
    149     if (sb < header->min_sb1) {
    150       // The same as above. Three fonts in http://www.fontsquirrel.com/fontface
    151       // (e.g., Notice2Std.otf) have weird lsb values.
    152       OTS_WARNING("bad lsb: %d < %d", sb, header->min_sb1);
    153       sb = header->min_sb1;
    154     }
    155 
    156     metrics->sbs.push_back(sb);
    157   }
    158 
    159   return true;
    160 }
    161 
    162 bool SerialiseMetricsTable(OTSStream *out,
    163                            const OpenTypeMetricsTable *metrics) {
    164   for (unsigned i = 0; i < metrics->entries.size(); ++i) {
    165     if (!out->WriteU16(metrics->entries[i].first) ||
    166         !out->WriteS16(metrics->entries[i].second)) {
    167       return OTS_FAILURE();
    168     }
    169   }
    170 
    171   for (unsigned i = 0; i < metrics->sbs.size(); ++i) {
    172     if (!out->WriteS16(metrics->sbs[i])) {
    173       return OTS_FAILURE();
    174     }
    175   }
    176 
    177   return true;
    178 }
    179 
    180 }  // namespace ots
    181 
    182