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