gfx/ots/src/glyf.cc

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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 "glyf.h"
michael@0 6
michael@0 7 #include <algorithm>
michael@0 8 #include <limits>
michael@0 9
michael@0 10 #include "head.h"
michael@0 11 #include "loca.h"
michael@0 12 #include "maxp.h"
michael@0 13
michael@0 14 // glyf - Glyph Data
michael@0 15 // http://www.microsoft.com/typography/otspec/glyf.htm
michael@0 16
michael@0 17 #define TABLE_NAME "glyf"
michael@0 18
michael@0 19 namespace {
michael@0 20
michael@0 21 bool ParseFlagsForSimpleGlyph(ots::OpenTypeFile *file,
michael@0 22 ots::Buffer *table,
michael@0 23 uint32_t gly_length,
michael@0 24 uint32_t num_flags,
michael@0 25 uint32_t *flags_count_logical,
michael@0 26 uint32_t *flags_count_physical,
michael@0 27 uint32_t *xy_coordinates_length) {
michael@0 28 uint8_t flag = 0;
michael@0 29 if (!table->ReadU8(&flag)) {
michael@0 30 return OTS_FAILURE_MSG("Can't read flag");
michael@0 31 }
michael@0 32
michael@0 33 uint32_t delta = 0;
michael@0 34 if (flag & (1u << 1)) { // x-Short
michael@0 35 ++delta;
michael@0 36 } else if (!(flag & (1u << 4))) {
michael@0 37 delta += 2;
michael@0 38 }
michael@0 39
michael@0 40 if (flag & (1u << 2)) { // y-Short
michael@0 41 ++delta;
michael@0 42 } else if (!(flag & (1u << 5))) {
michael@0 43 delta += 2;
michael@0 44 }
michael@0 45
michael@0 46 if (flag & (1u << 3)) { // repeat
michael@0 47 if (*flags_count_logical + 1 >= num_flags) {
michael@0 48 return OTS_FAILURE_MSG("Count too high (%d + 1 >= %d)", *flags_count_logical, num_flags);
michael@0 49 }
michael@0 50 uint8_t repeat = 0;
michael@0 51 if (!table->ReadU8(&repeat)) {
michael@0 52 return OTS_FAILURE_MSG("Can't read repeat value");
michael@0 53 }
michael@0 54 if (repeat == 0) {
michael@0 55 return OTS_FAILURE_MSG("Zero repeat");
michael@0 56 }
michael@0 57 delta += (delta * repeat);
michael@0 58
michael@0 59 *flags_count_logical += repeat;
michael@0 60 if (*flags_count_logical >= num_flags) {
michael@0 61 return OTS_FAILURE_MSG("Count too high (%d >= %d)", *flags_count_logical, num_flags);
michael@0 62 }
michael@0 63 ++(*flags_count_physical);
michael@0 64 }
michael@0 65
michael@0 66 if ((flag & (1u << 6)) || (flag & (1u << 7))) { // reserved flags
michael@0 67 return OTS_FAILURE_MSG("Bad flag value (%d)", flag);
michael@0 68 }
michael@0 69
michael@0 70 *xy_coordinates_length += delta;
michael@0 71 if (gly_length < *xy_coordinates_length) {
michael@0 72 return OTS_FAILURE_MSG("Glyph coordinates length too low (%d < %d)", gly_length, *xy_coordinates_length);
michael@0 73 }
michael@0 74
michael@0 75 return true;
michael@0 76 }
michael@0 77
michael@0 78 bool ParseSimpleGlyph(ots::OpenTypeFile *file, const uint8_t *data,
michael@0 79 ots::Buffer *table, int16_t num_contours,
michael@0 80 uint32_t gly_offset, uint32_t gly_length,
michael@0 81 uint32_t *new_size) {
michael@0 82 ots::OpenTypeGLYF *glyf = file->glyf;
michael@0 83
michael@0 84 // read the end-points array
michael@0 85 uint16_t num_flags = 0;
michael@0 86 for (int i = 0; i < num_contours; ++i) {
michael@0 87 uint16_t tmp_index = 0;
michael@0 88 if (!table->ReadU16(&tmp_index)) {
michael@0 89 return OTS_FAILURE_MSG("Can't read contour index %d", i);
michael@0 90 }
michael@0 91 if (tmp_index == 0xffffu) {
michael@0 92 return OTS_FAILURE_MSG("Bad contour index %d", i);
michael@0 93 }
michael@0 94 // check if the indices are monotonically increasing
michael@0 95 if (i && (tmp_index + 1 <= num_flags)) {
michael@0 96 return OTS_FAILURE_MSG("Decreasing contour index %d + 1 <= %d", tmp_index, num_flags);
michael@0 97 }
michael@0 98 num_flags = tmp_index + 1;
michael@0 99 }
michael@0 100
michael@0 101 uint16_t bytecode_length = 0;
michael@0 102 if (!table->ReadU16(&bytecode_length)) {
michael@0 103 return OTS_FAILURE_MSG("Can't read bytecode length");
michael@0 104 }
michael@0 105 if ((file->maxp->version_1) &&
michael@0 106 (file->maxp->max_size_glyf_instructions < bytecode_length)) {
michael@0 107 return OTS_FAILURE_MSG("Bytecode length too high %d", bytecode_length);
michael@0 108 }
michael@0 109
michael@0 110 const uint32_t gly_header_length = 10 + num_contours * 2 + 2;
michael@0 111 if (gly_length < (gly_header_length + bytecode_length)) {
michael@0 112 return OTS_FAILURE_MSG("Glyph header length too high %d", gly_header_length);
michael@0 113 }
michael@0 114
michael@0 115 if (ots::g_transcode_hints) {
michael@0 116 glyf->iov.push_back(std::make_pair(
michael@0 117 data + gly_offset,
michael@0 118 static_cast<size_t>(gly_header_length + bytecode_length)));
michael@0 119 } else {
michael@0 120 // enqueue two vectors: the glyph data up to the bytecode length, then
michael@0 121 // a pointer to a static uint16_t 0 to overwrite the length.
michael@0 122 glyf->iov.push_back(std::make_pair(
michael@0 123 data + gly_offset,
michael@0 124 static_cast<size_t>(gly_header_length - 2)));
michael@0 125 glyf->iov.push_back(std::make_pair((const uint8_t*) "\x00\x00",
michael@0 126 static_cast<size_t>(2)));
michael@0 127 }
michael@0 128
michael@0 129 if (!table->Skip(bytecode_length)) {
michael@0 130 return OTS_FAILURE_MSG("Can't skip bytecode of length %d", bytecode_length);
michael@0 131 }
michael@0 132
michael@0 133 uint32_t flags_count_physical = 0; // on memory
michael@0 134 uint32_t xy_coordinates_length = 0;
michael@0 135 for (uint32_t flags_count_logical = 0;
michael@0 136 flags_count_logical < num_flags;
michael@0 137 ++flags_count_logical, ++flags_count_physical) {
michael@0 138 if (!ParseFlagsForSimpleGlyph(file,
michael@0 139 table,
michael@0 140 gly_length,
michael@0 141 num_flags,
michael@0 142 &flags_count_logical,
michael@0 143 &flags_count_physical,
michael@0 144 &xy_coordinates_length)) {
michael@0 145 return OTS_FAILURE_MSG("Failed to parse glyph flags %d", flags_count_logical);
michael@0 146 }
michael@0 147 }
michael@0 148
michael@0 149 if (gly_length < (gly_header_length + bytecode_length +
michael@0 150 flags_count_physical + xy_coordinates_length)) {
michael@0 151 return OTS_FAILURE_MSG("Glyph too short %d", gly_length);
michael@0 152 }
michael@0 153
michael@0 154 if (gly_length - (gly_header_length + bytecode_length +
michael@0 155 flags_count_physical + xy_coordinates_length) > 3) {
michael@0 156 // We allow 0-3 bytes difference since gly_length is 4-bytes aligned,
michael@0 157 // zero-padded length.
michael@0 158 return OTS_FAILURE_MSG("Invalid glyph length %d", gly_length);
michael@0 159 }
michael@0 160
michael@0 161 glyf->iov.push_back(std::make_pair(
michael@0 162 data + gly_offset + gly_header_length + bytecode_length,
michael@0 163 static_cast<size_t>(flags_count_physical + xy_coordinates_length)));
michael@0 164
michael@0 165 *new_size
michael@0 166 = gly_header_length + flags_count_physical + xy_coordinates_length;
michael@0 167 if (ots::g_transcode_hints) {
michael@0 168 *new_size += bytecode_length;
michael@0 169 }
michael@0 170
michael@0 171 return true;
michael@0 172 }
michael@0 173
michael@0 174 } // namespace
michael@0 175
michael@0 176 namespace ots {
michael@0 177
michael@0 178 bool ots_glyf_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
michael@0 179 Buffer table(data, length);
michael@0 180
michael@0 181 if (!file->maxp || !file->loca || !file->head) {
michael@0 182 return OTS_FAILURE_MSG("Missing maxp or loca or head table needed by glyf table");
michael@0 183 }
michael@0 184
michael@0 185 OpenTypeGLYF *glyf = new OpenTypeGLYF;
michael@0 186 file->glyf = glyf;
michael@0 187
michael@0 188 const unsigned num_glyphs = file->maxp->num_glyphs;
michael@0 189 std::vector<uint32_t> &offsets = file->loca->offsets;
michael@0 190
michael@0 191 if (offsets.size() != num_glyphs + 1) {
michael@0 192 return OTS_FAILURE_MSG("Invalide glyph offsets size %ld != %d", offsets.size(), num_glyphs + 1);
michael@0 193 }
michael@0 194
michael@0 195 std::vector<uint32_t> resulting_offsets(num_glyphs + 1);
michael@0 196 uint32_t current_offset = 0;
michael@0 197
michael@0 198 for (unsigned i = 0; i < num_glyphs; ++i) {
michael@0 199 const unsigned gly_offset = offsets[i];
michael@0 200 // The LOCA parser checks that these values are monotonic
michael@0 201 const unsigned gly_length = offsets[i + 1] - offsets[i];
michael@0 202 if (!gly_length) {
michael@0 203 // this glyph has no outline (e.g. the space charactor)
michael@0 204 resulting_offsets[i] = current_offset;
michael@0 205 continue;
michael@0 206 }
michael@0 207
michael@0 208 if (gly_offset >= length) {
michael@0 209 return OTS_FAILURE_MSG("Glyph %d offset %d too high %ld", i, gly_offset, length);
michael@0 210 }
michael@0 211 // Since these are unsigned types, the compiler is not allowed to assume
michael@0 212 // that they never overflow.
michael@0 213 if (gly_offset + gly_length < gly_offset) {
michael@0 214 return OTS_FAILURE_MSG("Glyph %d length (%d < 0)!", i, gly_length);
michael@0 215 }
michael@0 216 if (gly_offset + gly_length > length) {
michael@0 217 return OTS_FAILURE_MSG("Glyph %d length %d too high", i, gly_length);
michael@0 218 }
michael@0 219
michael@0 220 table.set_offset(gly_offset);
michael@0 221 int16_t num_contours, xmin, ymin, xmax, ymax;
michael@0 222 if (!table.ReadS16(&num_contours) ||
michael@0 223 !table.ReadS16(&xmin) ||
michael@0 224 !table.ReadS16(&ymin) ||
michael@0 225 !table.ReadS16(&xmax) ||
michael@0 226 !table.ReadS16(&ymax)) {
michael@0 227 return OTS_FAILURE_MSG("Can't read glyph %d header", i);
michael@0 228 }
michael@0 229
michael@0 230 if (num_contours <= -2) {
michael@0 231 // -2, -3, -4, ... are reserved for future use.
michael@0 232 return OTS_FAILURE_MSG("Bad number of contours %d in glyph %d", num_contours, i);
michael@0 233 }
michael@0 234
michael@0 235 // workaround for fonts in http://www.princexml.com/fonts/
michael@0 236 if ((xmin == 32767) &&
michael@0 237 (xmax == -32767) &&
michael@0 238 (ymin == 32767) &&
michael@0 239 (ymax == -32767)) {
michael@0 240 OTS_WARNING("bad xmin/xmax/ymin/ymax values");
michael@0 241 xmin = xmax = ymin = ymax = 0;
michael@0 242 }
michael@0 243
michael@0 244 if (xmin > xmax || ymin > ymax) {
michael@0 245 return OTS_FAILURE_MSG("Bad bounding box values bl=(%d, %d), tr=(%d, %d) in glyph %d", xmin, ymin, xmax, ymax, i);
michael@0 246 }
michael@0 247
michael@0 248 unsigned new_size = 0;
michael@0 249 if (num_contours >= 0) {
michael@0 250 // this is a simple glyph and might contain bytecode
michael@0 251 if (!ParseSimpleGlyph(file, data, &table,
michael@0 252 num_contours, gly_offset, gly_length, &new_size)) {
michael@0 253 return OTS_FAILURE_MSG("Failed to parse glyph %d", i);
michael@0 254 }
michael@0 255 } else {
michael@0 256 // it's a composite glyph without any bytecode. Enqueue the whole thing
michael@0 257 glyf->iov.push_back(std::make_pair(data + gly_offset,
michael@0 258 static_cast<size_t>(gly_length)));
michael@0 259 new_size = gly_length;
michael@0 260 }
michael@0 261
michael@0 262 resulting_offsets[i] = current_offset;
michael@0 263 // glyphs must be four byte aligned
michael@0 264 // TODO(yusukes): investigate whether this padding is really necessary.
michael@0 265 // Which part of the spec requires this?
michael@0 266 const unsigned padding = (4 - (new_size & 3)) % 4;
michael@0 267 if (padding) {
michael@0 268 glyf->iov.push_back(std::make_pair(
michael@0 269 reinterpret_cast<const uint8_t*>("\x00\x00\x00\x00"),
michael@0 270 static_cast<size_t>(padding)));
michael@0 271 new_size += padding;
michael@0 272 }
michael@0 273 current_offset += new_size;
michael@0 274 }
michael@0 275 resulting_offsets[num_glyphs] = current_offset;
michael@0 276
michael@0 277 const uint16_t max16 = std::numeric_limits<uint16_t>::max();
michael@0 278 if ((*std::max_element(resulting_offsets.begin(),
michael@0 279 resulting_offsets.end()) >= (max16 * 2u)) &&
michael@0 280 (file->head->index_to_loc_format != 1)) {
michael@0 281 OTS_WARNING("2-bytes indexing is not possible (due to the padding above)");
michael@0 282 file->head->index_to_loc_format = 1;
michael@0 283 }
michael@0 284
michael@0 285 file->loca->offsets = resulting_offsets;
michael@0 286 return true;
michael@0 287 }
michael@0 288
michael@0 289 bool ots_glyf_should_serialise(OpenTypeFile *file) {
michael@0 290 return file->glyf != NULL;
michael@0 291 }
michael@0 292
michael@0 293 bool ots_glyf_serialise(OTSStream *out, OpenTypeFile *file) {
michael@0 294 const OpenTypeGLYF *glyf = file->glyf;
michael@0 295
michael@0 296 for (unsigned i = 0; i < glyf->iov.size(); ++i) {
michael@0 297 if (!out->Write(glyf->iov[i].first, glyf->iov[i].second)) {
michael@0 298 return OTS_FAILURE_MSG("Falied to write glyph %d", i);
michael@0 299 }
michael@0 300 }
michael@0 301
michael@0 302 return true;
michael@0 303 }
michael@0 304
michael@0 305 void ots_glyf_free(OpenTypeFile *file) {
michael@0 306 delete file->glyf;
michael@0 307 }
michael@0 308
michael@0 309 } // namespace ots

mercurial