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 "post.h"
      6 
      7 #include "maxp.h"
      8 
      9 // post - PostScript
     10 // http://www.microsoft.com/opentype/otspec/post.htm
     11 
     12 namespace ots {
     13 
     14 bool ots_post_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
     15   Buffer table(data, length);
     16 
     17   OpenTypePOST *post = new OpenTypePOST;
     18   file->post = post;
     19 
     20   if (!table.ReadU32(&post->version) ||
     21       !table.ReadU32(&post->italic_angle) ||
     22       !table.ReadS16(&post->underline) ||
     23       !table.ReadS16(&post->underline_thickness) ||
     24       !table.ReadU32(&post->is_fixed_pitch)) {
     25     return OTS_FAILURE();
     26   }
     27 
     28   if (post->underline_thickness < 0) {
     29     post->underline_thickness = 1;
     30   }
     31 
     32   if (post->version == 0x00010000) {
     33     return true;
     34   } else if (post->version == 0x00030000) {
     35     return true;
     36   } else if (post->version != 0x00020000) {
     37     // 0x00025000 is deprecated. We don't accept it.
     38     return OTS_FAILURE();
     39   }
     40 
     41   // We have a version 2 table with a list of Pascal strings at the end
     42 
     43   // We don't care about the memory usage fields. We'll set all these to zero
     44   // when serialising
     45   if (!table.Skip(16)) {
     46     return OTS_FAILURE();
     47   }
     48 
     49   uint16_t num_glyphs = 0;
     50   if (!table.ReadU16(&num_glyphs)) {
     51     return OTS_FAILURE();
     52   }
     53 
     54   if (!file->maxp) {
     55     return OTS_FAILURE();
     56   }
     57 
     58   if (num_glyphs == 0) {
     59     if (file->maxp->num_glyphs > 258) {
     60       return OTS_FAILURE();
     61     }
     62     OTS_WARNING("table version is 1, but no glyf names are found");
     63     // workaround for fonts in http://www.fontsquirrel.com/fontface
     64     // (e.g., yataghan.ttf).
     65     post->version = 0x00010000;
     66     return true;
     67   }
     68 
     69   if (num_glyphs != file->maxp->num_glyphs) {
     70     // Note: Fixedsys500c.ttf seems to have inconsistent num_glyphs values.
     71     return OTS_FAILURE();
     72   }
     73 
     74   post->glyph_name_index.resize(num_glyphs);
     75   for (unsigned i = 0; i < num_glyphs; ++i) {
     76     if (!table.ReadU16(&post->glyph_name_index[i])) {
     77       return OTS_FAILURE();
     78     }
     79     // Note: A strict interpretation of the specification requires name indexes
     80     // are less than 32768. This, however, excludes fonts like unifont.ttf
     81     // which cover all of unicode.
     82   }
     83 
     84   // Now we have an array of Pascal strings. We have to check that they are all
     85   // valid and read them in.
     86   const size_t strings_offset = table.offset();
     87   const uint8_t *strings = data + strings_offset;
     88   const uint8_t *strings_end = data + length;
     89 
     90   for (;;) {
     91     if (strings == strings_end) break;
     92     const unsigned string_length = *strings;
     93     if (strings + 1 + string_length > strings_end) {
     94       return OTS_FAILURE();
     95     }
     96     if (std::memchr(strings + 1, '\0', string_length)) {
     97       return OTS_FAILURE();
     98     }
     99     post->names.push_back(
    100         std::string(reinterpret_cast<const char*>(strings + 1), string_length));
    101     strings += 1 + string_length;
    102   }
    103   const unsigned num_strings = post->names.size();
    104 
    105   // check that all the references are within bounds
    106   for (unsigned i = 0; i < num_glyphs; ++i) {
    107     unsigned offset = post->glyph_name_index[i];
    108     if (offset < 258) {
    109       continue;
    110     }
    111 
    112     offset -= 258;
    113     if (offset >= num_strings) {
    114       return OTS_FAILURE();
    115     }
    116   }
    117 
    118   return true;
    119 }
    120 
    121 bool ots_post_should_serialise(OpenTypeFile *file) {
    122   return file->post != NULL;
    123 }
    124 
    125 bool ots_post_serialise(OTSStream *out, OpenTypeFile *file) {
    126   const OpenTypePOST *post = file->post;
    127 
    128   // OpenType with CFF glyphs must have v3 post table.
    129   if (file->post && file->cff && file->post->version != 0x00030000) {
    130     return OTS_FAILURE();
    131   }
    132 
    133   if (!out->WriteU32(post->version) ||
    134       !out->WriteU32(post->italic_angle) ||
    135       !out->WriteS16(post->underline) ||
    136       !out->WriteS16(post->underline_thickness) ||
    137       !out->WriteU32(post->is_fixed_pitch) ||
    138       !out->WriteU32(0) ||
    139       !out->WriteU32(0) ||
    140       !out->WriteU32(0) ||
    141       !out->WriteU32(0)) {
    142     return OTS_FAILURE();
    143   }
    144 
    145   if (post->version != 0x00020000) {
    146     return true;  // v1.0 and v3.0 does not have glyph names.
    147   }
    148 
    149   if (!out->WriteU16(post->glyph_name_index.size())) {
    150     return OTS_FAILURE();
    151   }
    152 
    153   for (unsigned i = 0; i < post->glyph_name_index.size(); ++i) {
    154     if (!out->WriteU16(post->glyph_name_index[i])) {
    155       return OTS_FAILURE();
    156     }
    157   }
    158 
    159   // Now we just have to write out the strings in the correct order
    160   for (unsigned i = 0; i < post->names.size(); ++i) {
    161     const std::string& s = post->names[i];
    162     const uint8_t string_length = s.size();
    163     if (!out->Write(&string_length, 1)) {
    164       return OTS_FAILURE();
    165     }
    166     // Some ttf fonts (e.g., frank.ttf on Windows Vista) have zero-length name.
    167     // We allow them.
    168     if (string_length > 0 && !out->Write(s.data(), string_length)) {
    169       return OTS_FAILURE();
    170     }
    171   }
    172 
    173   return true;
    174 }
    175 
    176 void ots_post_free(OpenTypeFile *file) {
    177   delete file->post;
    178 }
    179 
    180 }  // namespace ots
    181