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