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