gfx/ots/src/kern.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #include "kern.h"
michael@0 6
michael@0 7 // kern - Kerning
michael@0 8 // http://www.microsoft.com/typography/otspec/kern.htm
michael@0 9
michael@0 10 #define TABLE_NAME "kern"
michael@0 11
michael@0 12 #define DROP_THIS_TABLE \
michael@0 13 do { \
michael@0 14 delete file->kern; \
michael@0 15 file->kern = 0; \
michael@0 16 OTS_FAILURE_MSG("Table discarded"); \
michael@0 17 } while (0)
michael@0 18
michael@0 19 namespace ots {
michael@0 20
michael@0 21 bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
michael@0 22 Buffer table(data, length);
michael@0 23
michael@0 24 OpenTypeKERN *kern = new OpenTypeKERN;
michael@0 25 file->kern = kern;
michael@0 26
michael@0 27 uint16_t num_tables = 0;
michael@0 28 if (!table.ReadU16(&kern->version) ||
michael@0 29 !table.ReadU16(&num_tables)) {
michael@0 30 return OTS_FAILURE_MSG("Failed to read kern header");
michael@0 31 }
michael@0 32
michael@0 33 if (kern->version > 0) {
michael@0 34 DROP_THIS_TABLE;
michael@0 35 return true;
michael@0 36 }
michael@0 37
michael@0 38 if (num_tables == 0) {
michael@0 39 OTS_WARNING("num_tables is zero");
michael@0 40 DROP_THIS_TABLE;
michael@0 41 return true;
michael@0 42 }
michael@0 43
michael@0 44 kern->subtables.reserve(num_tables);
michael@0 45 for (unsigned i = 0; i < num_tables; ++i) {
michael@0 46 OpenTypeKERNFormat0 subtable;
michael@0 47 uint16_t sub_length = 0;
michael@0 48
michael@0 49 if (!table.ReadU16(&subtable.version) ||
michael@0 50 !table.ReadU16(&sub_length)) {
michael@0 51 return OTS_FAILURE_MSG("Failed to read kern subtable %d header", i);
michael@0 52 }
michael@0 53
michael@0 54 if (subtable.version > 0) {
michael@0 55 OTS_WARNING("Bad subtable version: %d", subtable.version);
michael@0 56 continue;
michael@0 57 }
michael@0 58
michael@0 59 const size_t current_offset = table.offset();
michael@0 60 if (current_offset - 4 + sub_length > length) {
michael@0 61 return OTS_FAILURE_MSG("Bad kern subtable %d offset %ld", i, current_offset);
michael@0 62 }
michael@0 63
michael@0 64 if (!table.ReadU16(&subtable.coverage)) {
michael@0 65 return OTS_FAILURE_MSG("Cailed to read kern subtable %d coverage", i);
michael@0 66 }
michael@0 67
michael@0 68 if (!(subtable.coverage & 0x1)) {
michael@0 69 OTS_WARNING(
michael@0 70 "We don't support vertical data as the renderer doesn't support it.");
michael@0 71 continue;
michael@0 72 }
michael@0 73 if (subtable.coverage & 0xF0) {
michael@0 74 OTS_WARNING("Reserved fields should zero-filled.");
michael@0 75 DROP_THIS_TABLE;
michael@0 76 return true;
michael@0 77 }
michael@0 78 const uint32_t format = (subtable.coverage & 0xFF00) >> 8;
michael@0 79 if (format != 0) {
michael@0 80 OTS_WARNING("Format %d is not supported.", format);
michael@0 81 continue;
michael@0 82 }
michael@0 83
michael@0 84 // Parse the format 0 field.
michael@0 85 uint16_t num_pairs = 0;
michael@0 86 if (!table.ReadU16(&num_pairs) ||
michael@0 87 !table.ReadU16(&subtable.search_range) ||
michael@0 88 !table.ReadU16(&subtable.entry_selector) ||
michael@0 89 !table.ReadU16(&subtable.range_shift)) {
michael@0 90 return OTS_FAILURE_MSG("Failed to read kern subtable %d format 0 fields", i);
michael@0 91 }
michael@0 92
michael@0 93 if (!num_pairs) {
michael@0 94 OTS_WARNING("Zero length subtable is found.");
michael@0 95 DROP_THIS_TABLE;
michael@0 96 return true;
michael@0 97 }
michael@0 98
michael@0 99 // Sanity checks for search_range, entry_selector, and range_shift. See the
michael@0 100 // comment in ots.cc for details.
michael@0 101 const size_t kFormat0PairSize = 6; // left, right, and value. 2 bytes each.
michael@0 102 if (num_pairs > (65536 / kFormat0PairSize)) {
michael@0 103 // Some fonts (e.g. calibri.ttf, pykes_peak_zero.ttf) have pairs >= 10923.
michael@0 104 OTS_WARNING("Too large subtable.");
michael@0 105 DROP_THIS_TABLE;
michael@0 106 return true;
michael@0 107 }
michael@0 108 unsigned max_pow2 = 0;
michael@0 109 while (1u << (max_pow2 + 1) <= num_pairs) {
michael@0 110 ++max_pow2;
michael@0 111 }
michael@0 112 const uint16_t expected_search_range = (1u << max_pow2) * kFormat0PairSize;
michael@0 113 if (subtable.search_range != expected_search_range) {
michael@0 114 OTS_WARNING("bad search range");
michael@0 115 subtable.search_range = expected_search_range;
michael@0 116 }
michael@0 117 if (subtable.entry_selector != max_pow2) {
michael@0 118 return OTS_FAILURE_MSG("Bad subtable %d entry selector %d", i, subtable.entry_selector);
michael@0 119 }
michael@0 120 const uint32_t expected_range_shift
michael@0 121 = kFormat0PairSize * num_pairs - subtable.search_range;
michael@0 122 if (subtable.range_shift != expected_range_shift) {
michael@0 123 OTS_WARNING("bad range shift");
michael@0 124 subtable.range_shift = expected_range_shift;
michael@0 125 }
michael@0 126
michael@0 127 // Read kerning pairs.
michael@0 128 subtable.pairs.reserve(num_pairs);
michael@0 129 uint32_t last_pair = 0;
michael@0 130 for (unsigned j = 0; j < num_pairs; ++j) {
michael@0 131 OpenTypeKERNFormat0Pair kerning_pair;
michael@0 132 if (!table.ReadU16(&kerning_pair.left) ||
michael@0 133 !table.ReadU16(&kerning_pair.right) ||
michael@0 134 !table.ReadS16(&kerning_pair.value)) {
michael@0 135 return OTS_FAILURE_MSG("Failed to read subtable %d kerning pair %d", i, j);
michael@0 136 }
michael@0 137 const uint32_t current_pair
michael@0 138 = (kerning_pair.left << 16) + kerning_pair.right;
michael@0 139 if (j != 0 && current_pair <= last_pair) {
michael@0 140 OTS_WARNING("Kerning pairs are not sorted.");
michael@0 141 // Many free fonts don't follow this rule, so we don't call OTS_FAILURE
michael@0 142 // in order to support these fonts.
michael@0 143 DROP_THIS_TABLE;
michael@0 144 return true;
michael@0 145 }
michael@0 146 last_pair = current_pair;
michael@0 147 subtable.pairs.push_back(kerning_pair);
michael@0 148 }
michael@0 149
michael@0 150 kern->subtables.push_back(subtable);
michael@0 151 }
michael@0 152
michael@0 153 if (!kern->subtables.size()) {
michael@0 154 OTS_WARNING("All subtables are removed.");
michael@0 155 DROP_THIS_TABLE;
michael@0 156 return true;
michael@0 157 }
michael@0 158
michael@0 159 return true;
michael@0 160 }
michael@0 161
michael@0 162 bool ots_kern_should_serialise(OpenTypeFile *file) {
michael@0 163 if (!file->glyf) return false; // this table is not for CFF fonts.
michael@0 164 return file->kern != NULL;
michael@0 165 }
michael@0 166
michael@0 167 bool ots_kern_serialise(OTSStream *out, OpenTypeFile *file) {
michael@0 168 const OpenTypeKERN *kern = file->kern;
michael@0 169
michael@0 170 if (!out->WriteU16(kern->version) ||
michael@0 171 !out->WriteU16(kern->subtables.size())) {
michael@0 172 return OTS_FAILURE_MSG("Can't write kern table header");
michael@0 173 }
michael@0 174
michael@0 175 for (unsigned i = 0; i < kern->subtables.size(); ++i) {
michael@0 176 const uint16_t length = 14 + (6 * kern->subtables[i].pairs.size());
michael@0 177 if (!out->WriteU16(kern->subtables[i].version) ||
michael@0 178 !out->WriteU16(length) ||
michael@0 179 !out->WriteU16(kern->subtables[i].coverage) ||
michael@0 180 !out->WriteU16(kern->subtables[i].pairs.size()) ||
michael@0 181 !out->WriteU16(kern->subtables[i].search_range) ||
michael@0 182 !out->WriteU16(kern->subtables[i].entry_selector) ||
michael@0 183 !out->WriteU16(kern->subtables[i].range_shift)) {
michael@0 184 return OTS_FAILURE_MSG("Failed to write kern subtable %d", i);
michael@0 185 }
michael@0 186 for (unsigned j = 0; j < kern->subtables[i].pairs.size(); ++j) {
michael@0 187 if (!out->WriteU16(kern->subtables[i].pairs[j].left) ||
michael@0 188 !out->WriteU16(kern->subtables[i].pairs[j].right) ||
michael@0 189 !out->WriteS16(kern->subtables[i].pairs[j].value)) {
michael@0 190 return OTS_FAILURE_MSG("Failed to write kern pair %d for subtable %d", j, i);
michael@0 191 }
michael@0 192 }
michael@0 193 }
michael@0 194
michael@0 195 return true;
michael@0 196 }
michael@0 197
michael@0 198 void ots_kern_free(OpenTypeFile *file) {
michael@0 199 delete file->kern;
michael@0 200 }
michael@0 201
michael@0 202 } // namespace ots

mercurial