Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(369)

Side by Side Diff: third_party/woff2/src/woff2_dec.cc

Issue 1873123002: Update woff2 to 4e698b8 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: assert.h Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 Google Inc. All Rights Reserved. 1 // Copyright 2014 Google Inc. All Rights Reserved.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License. 4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 12 // See the License for the specific language governing permissions and
13 // limitations under the License. 13 // limitations under the License.
14 // 14 //
15 // Library for converting WOFF2 format font files to their TTF versions. 15 // Library for converting WOFF2 format font files to their TTF versions.
16 16
17 #include "./woff2_dec.h" 17 #include "./woff2_dec.h"
18 18
19 #include <stdlib.h> 19 #include <stdlib.h>
20 #include <algorithm> 20 #include <algorithm>
21 #include <complex> 21 #include <complex>
22 #include <cstring> 22 #include <cstring>
23 #include <limits> 23 #include <limits>
24 #include <string> 24 #include <string>
25 #include <vector> 25 #include <vector>
26 #include <map> 26 #include <map>
27 #include <memory> 27 #include <memory>
28 #include <utility>
28 29
29 #include "./decode.h" 30 #include "./decode.h"
30 #include "./buffer.h" 31 #include "./buffer.h"
31 #include "./port.h" 32 #include "./port.h"
32 #include "./round.h" 33 #include "./round.h"
33 #include "./store_bytes.h" 34 #include "./store_bytes.h"
34 #include "./table_tags.h" 35 #include "./table_tags.h"
35 #include "./variable_length.h" 36 #include "./variable_length.h"
36 #include "./woff2_common.h" 37 #include "./woff2_common.h"
37 38
(...skipping 20 matching lines...) Expand all
58 const int FLAG_MORE_COMPONENTS = 1 << 5; 59 const int FLAG_MORE_COMPONENTS = 1 << 5;
59 const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6; 60 const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
60 const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7; 61 const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
61 const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8; 62 const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
62 63
63 const size_t kCheckSumAdjustmentOffset = 8; 64 const size_t kCheckSumAdjustmentOffset = 8;
64 65
65 const size_t kEndPtsOfContoursOffset = 10; 66 const size_t kEndPtsOfContoursOffset = 10;
66 const size_t kCompositeGlyphBegin = 10; 67 const size_t kCompositeGlyphBegin = 10;
67 68
69 // 98% of Google Fonts have no glyph above 5k bytes
70 // Largest glyph ever observed was 72k bytes
71 const size_t kDefaultGlyphBuf = 5120;
72
68 // metadata for a TTC font entry 73 // metadata for a TTC font entry
69 struct TtcFont { 74 struct TtcFont {
70 uint32_t flavor; 75 uint32_t flavor;
71 uint32_t dst_offset; 76 uint32_t dst_offset;
77 uint32_t header_checksum;
72 std::vector<uint16_t> table_indices; 78 std::vector<uint16_t> table_indices;
73 }; 79 };
74 80
81 struct WOFF2Header {
82 uint32_t flavor;
83 uint32_t header_version;
84 uint16_t num_tables;
85 uint64_t compressed_offset;
86 uint32_t compressed_length;
87 uint32_t uncompressed_size;
88 std::vector<Table> tables; // num_tables unique tables
89 std::vector<TtcFont> ttc_fonts; // metadata to help rebuild font
90 };
91
92 /**
93 * Accumulates data we may need to reconstruct a single font. One per font
94 * created for a TTC.
95 */
96 struct WOFF2FontInfo {
97 uint16_t num_glyphs;
98 uint16_t index_format;
99 uint16_t num_hmetrics;
100 std::vector<int16_t> x_mins;
101 std::map<uint32_t, uint32_t> table_entry_by_tag;
102 };
103
104 // Accumulates metadata as we rebuild the font
105 struct RebuildMetadata {
106 uint32_t header_checksum; // set by WriteHeaders
107 std::vector<WOFF2FontInfo> font_infos;
108 // checksums for tables that have been written.
109 // (tag, src_offset) => checksum. Need both because 0-length loca.
110 std::map<std::pair<uint32_t, uint32_t>, uint32_t> checksums;
111 };
112
75 int WithSign(int flag, int baseval) { 113 int WithSign(int flag, int baseval) {
76 // Precondition: 0 <= baseval < 65536 (to avoid integer overflow) 114 // Precondition: 0 <= baseval < 65536 (to avoid integer overflow)
77 return (flag & 1) ? baseval : -baseval; 115 return (flag & 1) ? baseval : -baseval;
78 } 116 }
79 117
80 bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size, 118 bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size,
81 unsigned int n_points, Point* result, size_t* in_bytes_consumed) { 119 unsigned int n_points, Point* result, size_t* in_bytes_consumed) {
82 int x = 0; 120 int x = 0;
83 int y = 0; 121 int y = 0;
84 122
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 y_offset = Store16(dst, y_offset, dy); 275 y_offset = Store16(dst, y_offset, dy);
238 } 276 }
239 last_y += dy; 277 last_y += dy;
240 } 278 }
241 *glyph_size = y_offset; 279 *glyph_size = y_offset;
242 return true; 280 return true;
243 } 281 }
244 282
245 // Compute the bounding box of the coordinates, and store into a glyf buffer. 283 // Compute the bounding box of the coordinates, and store into a glyf buffer.
246 // A precondition is that there are at least 10 bytes available. 284 // A precondition is that there are at least 10 bytes available.
285 // dst should point to the beginning of a 'glyf' record.
247 void ComputeBbox(unsigned int n_points, const Point* points, uint8_t* dst) { 286 void ComputeBbox(unsigned int n_points, const Point* points, uint8_t* dst) {
248 int x_min = 0; 287 int x_min = 0;
249 int y_min = 0; 288 int y_min = 0;
250 int x_max = 0; 289 int x_max = 0;
251 int y_max = 0; 290 int y_max = 0;
252 291
253 if (n_points > 0) { 292 if (n_points > 0) {
254 x_min = points[0].x; 293 x_min = points[0].x;
255 x_max = points[0].x; 294 x_max = points[0].x;
256 y_min = points[0].y; 295 y_min = points[0].y;
257 y_max = points[0].y; 296 y_max = points[0].y;
258 } 297 }
259 for (unsigned int i = 1; i < n_points; ++i) { 298 for (unsigned int i = 1; i < n_points; ++i) {
260 int x = points[i].x; 299 int x = points[i].x;
261 int y = points[i].y; 300 int y = points[i].y;
262 x_min = std::min(x, x_min); 301 x_min = std::min(x, x_min);
263 x_max = std::max(x, x_max); 302 x_max = std::max(x, x_max);
264 y_min = std::min(y, y_min); 303 y_min = std::min(y, y_min);
265 y_max = std::max(y, y_max); 304 y_max = std::max(y, y_max);
266 } 305 }
267 size_t offset = 2; 306 size_t offset = 2;
268 offset = Store16(dst, offset, x_min); 307 offset = Store16(dst, offset, x_min);
269 offset = Store16(dst, offset, y_min); 308 offset = Store16(dst, offset, y_min);
270 offset = Store16(dst, offset, x_max); 309 offset = Store16(dst, offset, x_max);
271 offset = Store16(dst, offset, y_max); 310 offset = Store16(dst, offset, y_max);
272 } 311 }
273 312
274 bool ProcessComposite(Buffer* composite_stream, uint8_t* dst, 313
275 size_t dst_size, size_t* glyph_size, bool* have_instructions) { 314 bool SizeOfComposite(Buffer composite_stream, size_t* size,
276 size_t start_offset = composite_stream->offset(); 315 bool* have_instructions) {
316 size_t start_offset = composite_stream.offset();
277 bool we_have_instructions = false; 317 bool we_have_instructions = false;
278 318
279 uint16_t flags = FLAG_MORE_COMPONENTS; 319 uint16_t flags = FLAG_MORE_COMPONENTS;
280 while (flags & FLAG_MORE_COMPONENTS) { 320 while (flags & FLAG_MORE_COMPONENTS) {
281 if (PREDICT_FALSE(!composite_stream->ReadU16(&flags))) { 321 if (PREDICT_FALSE(!composite_stream.ReadU16(&flags))) {
282 return FONT_COMPRESSION_FAILURE(); 322 return FONT_COMPRESSION_FAILURE();
283 } 323 }
284 we_have_instructions |= (flags & FLAG_WE_HAVE_INSTRUCTIONS) != 0; 324 we_have_instructions |= (flags & FLAG_WE_HAVE_INSTRUCTIONS) != 0;
285 size_t arg_size = 2; // glyph index 325 size_t arg_size = 2; // glyph index
286 if (flags & FLAG_ARG_1_AND_2_ARE_WORDS) { 326 if (flags & FLAG_ARG_1_AND_2_ARE_WORDS) {
287 arg_size += 4; 327 arg_size += 4;
288 } else { 328 } else {
289 arg_size += 2; 329 arg_size += 2;
290 } 330 }
291 if (flags & FLAG_WE_HAVE_A_SCALE) { 331 if (flags & FLAG_WE_HAVE_A_SCALE) {
292 arg_size += 2; 332 arg_size += 2;
293 } else if (flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE) { 333 } else if (flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE) {
294 arg_size += 4; 334 arg_size += 4;
295 } else if (flags & FLAG_WE_HAVE_A_TWO_BY_TWO) { 335 } else if (flags & FLAG_WE_HAVE_A_TWO_BY_TWO) {
296 arg_size += 8; 336 arg_size += 8;
297 } 337 }
298 if (PREDICT_FALSE(!composite_stream->Skip(arg_size))) { 338 if (PREDICT_FALSE(!composite_stream.Skip(arg_size))) {
299 return FONT_COMPRESSION_FAILURE(); 339 return FONT_COMPRESSION_FAILURE();
300 } 340 }
301 } 341 }
302 size_t composite_glyph_size = composite_stream->offset() - start_offset; 342
303 if (PREDICT_FALSE(composite_glyph_size + kCompositeGlyphBegin > dst_size)) { 343 *size = composite_stream.offset() - start_offset;
344 *have_instructions = we_have_instructions;
345
346 return true;
347 }
348
349 bool Pad4(WOFF2Out* out) {
350 uint8_t zeroes[] = {0, 0, 0};
351 if (PREDICT_FALSE(out->Size() + 3 < out->Size())) {
304 return FONT_COMPRESSION_FAILURE(); 352 return FONT_COMPRESSION_FAILURE();
305 } 353 }
306 Store16(dst, 0, 0xffff); // nContours = -1 for composite glyph 354 uint32_t pad_bytes = Round4(out->Size()) - out->Size();
307 std::memcpy(dst + kCompositeGlyphBegin, 355 if (pad_bytes > 0) {
308 composite_stream->buffer() + start_offset, 356 if (PREDICT_FALSE(!out->Write(&zeroes, pad_bytes))) {
309 composite_glyph_size); 357 return FONT_COMPRESSION_FAILURE();
310 *glyph_size = kCompositeGlyphBegin + composite_glyph_size; 358 }
311 *have_instructions = we_have_instructions; 359 }
312 return true; 360 return true;
313 } 361 }
314 362
315 // Build TrueType loca table 363 // Build TrueType loca table
316 bool StoreLoca(const std::vector<uint32_t>& loca_values, int index_format, 364 bool StoreLoca(const std::vector<uint32_t>& loca_values, int index_format,
317 uint8_t* dst, size_t dst_size) { 365 uint32_t* checksum, WOFF2Out* out) {
366 // TODO(user) figure out what index format to use based on whether max
367 // offset fits into uint16_t or not
318 const uint64_t loca_size = loca_values.size(); 368 const uint64_t loca_size = loca_values.size();
319 const uint64_t offset_size = index_format ? 4 : 2; 369 const uint64_t offset_size = index_format ? 4 : 2;
320 if (PREDICT_FALSE((loca_size << 2) >> 2 != loca_size)) { 370 if (PREDICT_FALSE((loca_size << 2) >> 2 != loca_size)) {
321 return FONT_COMPRESSION_FAILURE(); 371 return FONT_COMPRESSION_FAILURE();
322 } 372 }
323 if (PREDICT_FALSE(offset_size * loca_size > dst_size)) { 373 std::vector<uint8_t> loca_content(loca_size * offset_size);
324 return FONT_COMPRESSION_FAILURE(); 374 uint8_t* dst = &loca_content[0];
325 }
326 size_t offset = 0; 375 size_t offset = 0;
327 for (size_t i = 0; i < loca_values.size(); ++i) { 376 for (size_t i = 0; i < loca_values.size(); ++i) {
328 uint32_t value = loca_values[i]; 377 uint32_t value = loca_values[i];
329 if (index_format) { 378 if (index_format) {
330 offset = StoreU32(dst, offset, value); 379 offset = StoreU32(dst, offset, value);
331 } else { 380 } else {
332 offset = Store16(dst, offset, value >> 1); 381 offset = Store16(dst, offset, value >> 1);
333 } 382 }
334 } 383 }
384 *checksum = ComputeULongSum(&loca_content[0], loca_content.size());
385 if (PREDICT_FALSE(!out->Write(&loca_content[0], loca_content.size()))) {
386 return FONT_COMPRESSION_FAILURE();
387 }
335 return true; 388 return true;
336 } 389 }
337 390
338 // Reconstruct entire glyf table based on transformed original 391 // Reconstruct entire glyf table based on transformed original
339 bool ReconstructGlyf(const uint8_t* data, size_t data_size, 392 bool ReconstructGlyf(const uint8_t* data, Table* glyf_table,
340 uint8_t* dst, size_t dst_size, 393 uint32_t* glyf_checksum, Table * loca_table,
341 uint8_t* loca_buf, size_t loca_size) { 394 uint32_t* loca_checksum, WOFF2FontInfo* info,
395 WOFF2Out* out) {
342 static const int kNumSubStreams = 7; 396 static const int kNumSubStreams = 7;
343 Buffer file(data, data_size); 397 Buffer file(data, glyf_table->transform_length);
344 uint32_t version; 398 uint32_t version;
345 std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams); 399 std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams);
400 const size_t glyf_start = out->Size();
346 401
347 if (PREDICT_FALSE(!file.ReadU32(&version))) { 402 if (PREDICT_FALSE(!file.ReadU32(&version))) {
348 return FONT_COMPRESSION_FAILURE(); 403 return FONT_COMPRESSION_FAILURE();
349 } 404 }
350 uint16_t num_glyphs; 405 if (PREDICT_FALSE(!file.ReadU16(&info->num_glyphs) ||
351 uint16_t index_format; 406 !file.ReadU16(&info->index_format))) {
352 if (PREDICT_FALSE(!file.ReadU16(&num_glyphs) ||
353 !file.ReadU16(&index_format))) {
354 return FONT_COMPRESSION_FAILURE(); 407 return FONT_COMPRESSION_FAILURE();
355 } 408 }
356 409
357 unsigned int offset = (2 + kNumSubStreams) * 4; 410 unsigned int offset = (2 + kNumSubStreams) * 4;
358 if (PREDICT_FALSE(offset > data_size)) { 411 if (PREDICT_FALSE(offset > glyf_table->transform_length)) {
359 return FONT_COMPRESSION_FAILURE(); 412 return FONT_COMPRESSION_FAILURE();
360 } 413 }
361 // Invariant from here on: data_size >= offset 414 // Invariant from here on: data_size >= offset
362 for (int i = 0; i < kNumSubStreams; ++i) { 415 for (int i = 0; i < kNumSubStreams; ++i) {
363 uint32_t substream_size; 416 uint32_t substream_size;
364 if (PREDICT_FALSE(!file.ReadU32(&substream_size))) { 417 if (PREDICT_FALSE(!file.ReadU32(&substream_size))) {
365 return FONT_COMPRESSION_FAILURE(); 418 return FONT_COMPRESSION_FAILURE();
366 } 419 }
367 if (PREDICT_FALSE(substream_size > data_size - offset)) { 420 if (PREDICT_FALSE(substream_size > glyf_table->transform_length - offset)) {
368 return FONT_COMPRESSION_FAILURE(); 421 return FONT_COMPRESSION_FAILURE();
369 } 422 }
370 substreams[i] = std::make_pair(data + offset, substream_size); 423 substreams[i] = std::make_pair(data + offset, substream_size);
371 offset += substream_size; 424 offset += substream_size;
372 } 425 }
373 Buffer n_contour_stream(substreams[0].first, substreams[0].second); 426 Buffer n_contour_stream(substreams[0].first, substreams[0].second);
374 Buffer n_points_stream(substreams[1].first, substreams[1].second); 427 Buffer n_points_stream(substreams[1].first, substreams[1].second);
375 Buffer flag_stream(substreams[2].first, substreams[2].second); 428 Buffer flag_stream(substreams[2].first, substreams[2].second);
376 Buffer glyph_stream(substreams[3].first, substreams[3].second); 429 Buffer glyph_stream(substreams[3].first, substreams[3].second);
377 Buffer composite_stream(substreams[4].first, substreams[4].second); 430 Buffer composite_stream(substreams[4].first, substreams[4].second);
378 Buffer bbox_stream(substreams[5].first, substreams[5].second); 431 Buffer bbox_stream(substreams[5].first, substreams[5].second);
379 Buffer instruction_stream(substreams[6].first, substreams[6].second); 432 Buffer instruction_stream(substreams[6].first, substreams[6].second);
380 433
381 std::vector<uint32_t> loca_values(num_glyphs + 1); 434 std::vector<uint32_t> loca_values(info->num_glyphs + 1);
382 std::vector<unsigned int> n_points_vec; 435 std::vector<unsigned int> n_points_vec;
383 std::unique_ptr<Point[]> points; 436 std::unique_ptr<Point[]> points;
384 size_t points_size = 0; 437 size_t points_size = 0;
385 uint32_t loca_offset = 0;
386 const uint8_t* bbox_bitmap = bbox_stream.buffer(); 438 const uint8_t* bbox_bitmap = bbox_stream.buffer();
387 // Safe because num_glyphs is bounded 439 // Safe because num_glyphs is bounded
388 unsigned int bitmap_length = ((num_glyphs + 31) >> 5) << 2; 440 unsigned int bitmap_length = ((info->num_glyphs + 31) >> 5) << 2;
389 if (!bbox_stream.Skip(bitmap_length)) { 441 if (!bbox_stream.Skip(bitmap_length)) {
390 return FONT_COMPRESSION_FAILURE(); 442 return FONT_COMPRESSION_FAILURE();
391 } 443 }
392 for (unsigned int i = 0; i < num_glyphs; ++i) { 444
445 // Temp buffer for glyph's.
446 size_t glyph_buf_size = kDefaultGlyphBuf;
447 std::unique_ptr<uint8_t[]> glyph_buf(new uint8_t[glyph_buf_size]);
448
449 info->x_mins.resize(info->num_glyphs);
450 for (unsigned int i = 0; i < info->num_glyphs; ++i) {
393 size_t glyph_size = 0; 451 size_t glyph_size = 0;
394 uint16_t n_contours = 0; 452 uint16_t n_contours = 0;
395 bool have_bbox = false; 453 bool have_bbox = false;
396 if (bbox_bitmap[i >> 3] & (0x80 >> (i & 7))) { 454 if (bbox_bitmap[i >> 3] & (0x80 >> (i & 7))) {
397 have_bbox = true; 455 have_bbox = true;
398 } 456 }
399 if (PREDICT_FALSE(!n_contour_stream.ReadU16(&n_contours))) { 457 if (PREDICT_FALSE(!n_contour_stream.ReadU16(&n_contours))) {
400 return FONT_COMPRESSION_FAILURE(); 458 return FONT_COMPRESSION_FAILURE();
401 } 459 }
402 uint8_t* glyf_dst = dst + loca_offset; 460
403 size_t glyf_dst_size = dst_size - loca_offset;
404 if (n_contours == 0xffff) { 461 if (n_contours == 0xffff) {
405 // composite glyph 462 // composite glyph
406 bool have_instructions = false; 463 bool have_instructions = false;
407 unsigned int instruction_size = 0; 464 unsigned int instruction_size = 0;
408 if (PREDICT_FALSE(!have_bbox)) { 465 if (PREDICT_FALSE(!have_bbox)) {
409 // composite glyphs must have an explicit bbox 466 // composite glyphs must have an explicit bbox
410 return FONT_COMPRESSION_FAILURE(); 467 return FONT_COMPRESSION_FAILURE();
411 } 468 }
412 if (PREDICT_FALSE(!ProcessComposite(&composite_stream, glyf_dst, 469
413 glyf_dst_size, &glyph_size, &have_instructions))) { 470 size_t composite_size;
414 return FONT_COMPRESSION_FAILURE(); 471 if (PREDICT_FALSE(!SizeOfComposite(composite_stream, &composite_size,
415 } 472 &have_instructions))) {
416 if (PREDICT_FALSE(!bbox_stream.Read(glyf_dst + 2, 8))) {
417 return FONT_COMPRESSION_FAILURE(); 473 return FONT_COMPRESSION_FAILURE();
418 } 474 }
419 if (have_instructions) { 475 if (have_instructions) {
420 if (PREDICT_FALSE(!Read255UShort(&glyph_stream, &instruction_size))) { 476 if (PREDICT_FALSE(!Read255UShort(&glyph_stream, &instruction_size))) {
421 return FONT_COMPRESSION_FAILURE(); 477 return FONT_COMPRESSION_FAILURE();
422 } 478 }
423 if (PREDICT_FALSE(instruction_size + 2 > glyf_dst_size - glyph_size)) { 479 }
424 return FONT_COMPRESSION_FAILURE(); 480
425 } 481 size_t size_needed = 2 + composite_size + instruction_size;
426 Store16(glyf_dst, glyph_size, instruction_size); 482 if (PREDICT_FALSE(glyph_buf_size < size_needed)) {
427 if (PREDICT_FALSE(!instruction_stream.Read(glyf_dst + glyph_size + 2, 483 glyph_buf.reset(new uint8_t[size_needed]);
484 glyph_buf_size = size_needed;
485 }
486
487 glyph_size = Store16(glyph_buf.get(), glyph_size, n_contours);
488 if (PREDICT_FALSE(!bbox_stream.Read(glyph_buf.get() + glyph_size, 8))) {
489 return FONT_COMPRESSION_FAILURE();
490 }
491 glyph_size += 8;
492
493 if (PREDICT_FALSE(!composite_stream.Read(glyph_buf.get() + glyph_size,
494 composite_size))) {
495 return FONT_COMPRESSION_FAILURE();
496 }
497 glyph_size += composite_size;
498 if (have_instructions) {
499 glyph_size = Store16(glyph_buf.get(), glyph_size, instruction_size);
500 if (PREDICT_FALSE(!instruction_stream.Read(glyph_buf.get() + glyph_size,
428 instruction_size))) { 501 instruction_size))) {
429 return FONT_COMPRESSION_FAILURE(); 502 return FONT_COMPRESSION_FAILURE();
430 } 503 }
431 glyph_size += instruction_size + 2; 504 glyph_size += instruction_size;
432 } 505 }
433 } else if (n_contours > 0) { 506 } else if (n_contours > 0) {
434 // simple glyph 507 // simple glyph
435 n_points_vec.clear(); 508 n_points_vec.clear();
436 unsigned int total_n_points = 0; 509 unsigned int total_n_points = 0;
437 unsigned int n_points_contour; 510 unsigned int n_points_contour;
438 for (unsigned int j = 0; j < n_contours; ++j) { 511 for (unsigned int j = 0; j < n_contours; ++j) {
439 if (PREDICT_FALSE( 512 if (PREDICT_FALSE(
440 !Read255UShort(&n_points_stream, &n_points_contour))) { 513 !Read255UShort(&n_points_stream, &n_points_contour))) {
441 return FONT_COMPRESSION_FAILURE(); 514 return FONT_COMPRESSION_FAILURE();
(...skipping 15 matching lines...) Expand all
457 size_t triplet_size = glyph_stream.length() - glyph_stream.offset(); 530 size_t triplet_size = glyph_stream.length() - glyph_stream.offset();
458 size_t triplet_bytes_consumed = 0; 531 size_t triplet_bytes_consumed = 0;
459 if (points_size < total_n_points) { 532 if (points_size < total_n_points) {
460 points_size = total_n_points; 533 points_size = total_n_points;
461 points.reset(new Point[points_size]); 534 points.reset(new Point[points_size]);
462 } 535 }
463 if (PREDICT_FALSE(!TripletDecode(flags_buf, triplet_buf, triplet_size, 536 if (PREDICT_FALSE(!TripletDecode(flags_buf, triplet_buf, triplet_size,
464 total_n_points, points.get(), &triplet_bytes_consumed))) { 537 total_n_points, points.get(), &triplet_bytes_consumed))) {
465 return FONT_COMPRESSION_FAILURE(); 538 return FONT_COMPRESSION_FAILURE();
466 } 539 }
467 const uint32_t header_and_endpts_contours_size =
468 kEndPtsOfContoursOffset + 2 * n_contours;
469 if (PREDICT_FALSE(glyf_dst_size < header_and_endpts_contours_size)) {
470 return FONT_COMPRESSION_FAILURE();
471 }
472 Store16(glyf_dst, 0, n_contours);
473 if (have_bbox) {
474 if (PREDICT_FALSE(!bbox_stream.Read(glyf_dst + 2, 8))) {
475 return FONT_COMPRESSION_FAILURE();
476 }
477 } else {
478 ComputeBbox(total_n_points, points.get(), glyf_dst);
479 }
480 size_t offset = kEndPtsOfContoursOffset;
481 int end_point = -1;
482 for (unsigned int contour_ix = 0; contour_ix < n_contours; ++contour_ix) {
483 end_point += n_points_vec[contour_ix];
484 if (PREDICT_FALSE(end_point >= 65536)) {
485 return FONT_COMPRESSION_FAILURE();
486 }
487 offset = Store16(glyf_dst, offset, end_point);
488 }
489 if (PREDICT_FALSE(!flag_stream.Skip(flag_size))) { 540 if (PREDICT_FALSE(!flag_stream.Skip(flag_size))) {
490 return FONT_COMPRESSION_FAILURE(); 541 return FONT_COMPRESSION_FAILURE();
491 } 542 }
492 if (PREDICT_FALSE(!glyph_stream.Skip(triplet_bytes_consumed))) { 543 if (PREDICT_FALSE(!glyph_stream.Skip(triplet_bytes_consumed))) {
493 return FONT_COMPRESSION_FAILURE(); 544 return FONT_COMPRESSION_FAILURE();
494 } 545 }
495 unsigned int instruction_size; 546 unsigned int instruction_size;
496 if (PREDICT_FALSE(!Read255UShort(&glyph_stream, &instruction_size))) { 547 if (PREDICT_FALSE(!Read255UShort(&glyph_stream, &instruction_size))) {
497 return FONT_COMPRESSION_FAILURE(); 548 return FONT_COMPRESSION_FAILURE();
498 } 549 }
499 if (PREDICT_FALSE(glyf_dst_size - header_and_endpts_contours_size < 550
500 instruction_size + 2)) { 551 if (PREDICT_FALSE(total_n_points >= (1 << 27)
552 || instruction_size >= (1 << 30))) {
501 return FONT_COMPRESSION_FAILURE(); 553 return FONT_COMPRESSION_FAILURE();
502 } 554 }
503 uint8_t* instruction_dst = glyf_dst + header_and_endpts_contours_size; 555 size_t size_needed = 12 + 2 * n_contours + 5 * total_n_points
504 Store16(instruction_dst, 0, instruction_size); 556 + instruction_size;
505 if (PREDICT_FALSE( 557 if (PREDICT_FALSE(glyph_buf_size < size_needed)) {
506 !instruction_stream.Read(instruction_dst + 2, instruction_size))) { 558 glyph_buf.reset(new uint8_t[size_needed]);
559 glyph_buf_size = size_needed;
560 }
561
562 glyph_size = Store16(glyph_buf.get(), glyph_size, n_contours);
563 if (have_bbox) {
564 if (PREDICT_FALSE(!bbox_stream.Read(glyph_buf.get() + glyph_size, 8))) {
565 return FONT_COMPRESSION_FAILURE();
566 }
567 } else {
568 ComputeBbox(total_n_points, points.get(), glyph_buf.get());
569 }
570 glyph_size = kEndPtsOfContoursOffset;
571 int end_point = -1;
572 for (unsigned int contour_ix = 0; contour_ix < n_contours; ++contour_ix) {
573 end_point += n_points_vec[contour_ix];
574 if (PREDICT_FALSE(end_point >= 65536)) {
575 return FONT_COMPRESSION_FAILURE();
576 }
577 glyph_size = Store16(glyph_buf.get(), glyph_size, end_point);
578 }
579
580 glyph_size = Store16(glyph_buf.get(), glyph_size, instruction_size);
581 if (PREDICT_FALSE(!instruction_stream.Read(glyph_buf.get() + glyph_size,
582 instruction_size))) {
507 return FONT_COMPRESSION_FAILURE(); 583 return FONT_COMPRESSION_FAILURE();
508 } 584 }
585 glyph_size += instruction_size;
586
509 if (PREDICT_FALSE(!StorePoints(total_n_points, points.get(), n_contours, 587 if (PREDICT_FALSE(!StorePoints(total_n_points, points.get(), n_contours,
510 instruction_size, glyf_dst, glyf_dst_size, &glyph_size))) { 588 instruction_size, glyph_buf.get(), glyph_buf_size, &glyph_size))) {
511 return FONT_COMPRESSION_FAILURE(); 589 return FONT_COMPRESSION_FAILURE();
512 } 590 }
513 } else {
514 glyph_size = 0;
515 } 591 }
516 loca_values[i] = loca_offset; 592
517 if (PREDICT_FALSE(glyph_size + 3 < glyph_size)) { 593 loca_values[i] = out->Size() - glyf_start;
594 if (PREDICT_FALSE(!out->Write(glyph_buf.get(), glyph_size))) {
518 return FONT_COMPRESSION_FAILURE(); 595 return FONT_COMPRESSION_FAILURE();
519 } 596 }
520 glyph_size = Round4(glyph_size); 597
521 if (PREDICT_FALSE(glyph_size > dst_size - loca_offset)) { 598 // TODO(user) Old code aligned glyphs ... but do we actually need to?
522 // This shouldn't happen, but this test defensively maintains the 599 if (PREDICT_FALSE(!Pad4(out))) {
523 // invariant that loca_offset <= dst_size.
524 return FONT_COMPRESSION_FAILURE(); 600 return FONT_COMPRESSION_FAILURE();
525 } 601 }
526 loca_offset += glyph_size; 602
603 *glyf_checksum += ComputeULongSum(glyph_buf.get(), glyph_size);
604
605 // We may need x_min to reconstruct 'hmtx'
606 Buffer x_min_buf(glyph_buf.get() + 2, 2);
607 int16_t x_min;
608 if (PREDICT_FALSE(!x_min_buf.ReadS16(&x_min))) {
609 return FONT_COMPRESSION_FAILURE();
610 }
611
612 info->x_mins[i] = n_contours != 0 ? x_min : 0;
527 } 613 }
528 loca_values[num_glyphs] = loca_offset; 614
529 return StoreLoca(loca_values, index_format, loca_buf, loca_size); 615 // glyf_table dst_offset was set by ReconstructFont
616 glyf_table->dst_length = out->Size() - glyf_table->dst_offset;
617 loca_table->dst_offset = out->Size();
618 // loca[n] will be equal the length of the glyph data ('glyf') table
619 loca_values[info->num_glyphs] = glyf_table->dst_length;
620 if (PREDICT_FALSE(!StoreLoca(loca_values, info->index_format, loca_checksum,
621 out))) {
622 return FONT_COMPRESSION_FAILURE();
623 }
624 loca_table->dst_length = out->Size() - loca_table->dst_offset;
625
626 return true;
627 }
628
629 Table* FindTable(std::vector<Table*>* tables, uint32_t tag) {
630 for (Table* table : *tables) {
631 if (table->tag == tag) {
632 return table;
633 }
634 }
635 return NULL;
530 } 636 }
531 637
532 // This is linear search, but could be changed to binary because we 638 // This is linear search, but could be changed to binary because we
533 // do have a guarantee that the tables are sorted by tag. But the total 639 // do have a guarantee that the tables are sorted by tag. But the total
534 // cpu time is expected to be very small in any case. 640 // cpu time is expected to be very small in any case.
535 const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) { 641 const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) {
536 size_t n_tables = tables.size(); 642 size_t n_tables = tables.size();
537 for (size_t i = 0; i < n_tables; ++i) { 643 for (size_t i = 0; i < n_tables; ++i) {
538 if (tables[i].tag == tag) { 644 if (tables[i].tag == tag) {
539 return &tables[i]; 645 return &tables[i];
540 } 646 }
541 } 647 }
542 return NULL; 648 return NULL;
543 } 649 }
544 650
545 bool ReconstructTransformedGlyf(const uint8_t* transformed_buf, 651 // https://www.microsoft.com/typography/otspec/maxp.htm
546 size_t transformed_size, const Table* glyf_table, const Table* loca_table, 652 bool ReadNumGlyphs(const Table* maxp_table,
547 uint8_t* dst, size_t dst_length) { 653 const uint8_t* dst, size_t dst_length,
548 if (PREDICT_FALSE(glyf_table == NULL || loca_table == NULL)) { 654 uint16_t* num_glyphs) {
655 if (PREDICT_FALSE(static_cast<uint64_t>(maxp_table->dst_offset +
656 maxp_table->dst_length) > dst_length)) {
549 return FONT_COMPRESSION_FAILURE(); 657 return FONT_COMPRESSION_FAILURE();
550 } 658 }
551 if (PREDICT_FALSE(static_cast<uint64_t>(glyf_table->dst_offset + 659 Buffer buffer(dst + maxp_table->dst_offset, maxp_table->dst_length);
552 glyf_table->dst_length) > dst_length)) { 660 // Skip 4 to reach 'maxp' numGlyphs
661 if (PREDICT_FALSE(!buffer.Skip(4) || !buffer.ReadU16(num_glyphs))) {
553 return FONT_COMPRESSION_FAILURE(); 662 return FONT_COMPRESSION_FAILURE();
554 } 663 }
555 if (PREDICT_FALSE(static_cast<uint64_t>(loca_table->dst_offset + 664 return true;
556 loca_table->dst_length) > dst_length)) { 665 }
666
667 // Get numberOfHMetrics, https://www.microsoft.com/typography/otspec/hhea.htm
668 bool ReadNumHMetrics(const uint8_t* data, size_t data_size,
669 uint16_t* num_hmetrics) {
670 // Skip 34 to reach 'hhea' numberOfHMetrics
671 Buffer buffer(data, data_size);
672 if (PREDICT_FALSE(!buffer.Skip(34) || !buffer.ReadU16(num_hmetrics))) {
557 return FONT_COMPRESSION_FAILURE(); 673 return FONT_COMPRESSION_FAILURE();
558 } 674 }
559 return ReconstructGlyf(transformed_buf, transformed_size, 675 return true;
560 dst + glyf_table->dst_offset, glyf_table->dst_length,
561 dst + loca_table->dst_offset, loca_table->dst_length);
562 } 676 }
563 677
564 bool ReconstructTransformed(const std::vector<Table>& tables, uint32_t tag, 678 // x_min for glyph; https://www.microsoft.com/typography/otspec/glyf.htm
565 const uint8_t* transformed_buf, size_t transformed_size, 679 bool ReadGlyphXMin(Buffer* glyf_buff, Buffer* loca_buff, int16_t loca_format,
566 uint8_t* dst, size_t dst_length) { 680 uint16_t index, int16_t* x_min) {
567 if (tag == kGlyfTableTag) { 681 uint32_t offset1, offset2;
568 const Table* glyf_table = FindTable(tables, tag); 682 loca_buff->set_offset((loca_format == 0 ? 2 : 4) * index);
569 const Table* loca_table = FindTable(tables, kLocaTableTag); 683 if (loca_format == 0) {
570 return ReconstructTransformedGlyf(transformed_buf, transformed_size, 684 uint16_t tmp1, tmp2;
571 glyf_table, loca_table, dst, dst_length); 685 if (PREDICT_FALSE(!loca_buff->ReadU16(&tmp1) ||
572 } else if (tag == kLocaTableTag) { 686 !loca_buff->ReadU16(&tmp2))) {
573 // processing was already done by glyf table, but validate 687 return FONT_COMPRESSION_FAILURE();
574 if (PREDICT_FALSE(!FindTable(tables, kGlyfTableTag))) { 688 }
689 // https://www.microsoft.com/typography/otspec/loca.htm
690 // "The actual local offset divided by 2 is stored."
691 offset1 = tmp1 * 2;
692 offset2 = tmp2 * 2;
693 } else if (PREDICT_FALSE(!loca_buff->ReadU32(&offset1) ||
694 !loca_buff->ReadU32(&offset2))) {
695 return FONT_COMPRESSION_FAILURE();
696 }
697
698 if (offset1 != offset2) {
699 glyf_buff->set_offset(offset1 + 2);
700 if (!glyf_buff->ReadS16(x_min)) {
575 return FONT_COMPRESSION_FAILURE(); 701 return FONT_COMPRESSION_FAILURE();
576 } 702 }
577 } else { 703 } else {
578 // transform for the tag is not known 704 *x_min = 0;
705 }
706 return true;
707 }
708
709 // http://dev.w3.org/webfonts/WOFF2/spec/Overview.html#hmtx_table_format
710 bool ReconstructTransformedHmtx(const uint8_t* transformed_buf,
711 size_t transformed_size,
712 uint16_t num_glyphs,
713 uint16_t num_hmetrics,
714 const std::vector<int16_t>& x_mins,
715 uint32_t* checksum,
716 WOFF2Out* out) {
717 Buffer hmtx_buff_in(transformed_buf, transformed_size);
718
719 uint8_t hmtx_flags;
720 if (PREDICT_FALSE(!hmtx_buff_in.ReadU8(&hmtx_flags))) {
579 return FONT_COMPRESSION_FAILURE(); 721 return FONT_COMPRESSION_FAILURE();
580 } 722 }
723
724 std::vector<uint16_t> advance_widths;
725 std::vector<int16_t> lsbs;
726 bool has_proportional_lsbs = (hmtx_flags & 1) == 0;
727 bool has_monospace_lsbs = (hmtx_flags & 2) == 0;
728
729 // you say you transformed but there is little evidence of it
730 if (has_proportional_lsbs && has_monospace_lsbs) {
731 return FONT_COMPRESSION_FAILURE();
732 }
733
734 assert(x_mins.size() == num_glyphs);
735
736 for (uint16_t i = 0; i < num_hmetrics; i++) {
737 uint16_t advance_width;
738 if (PREDICT_FALSE(!hmtx_buff_in.ReadU16(&advance_width))) {
739 return FONT_COMPRESSION_FAILURE();
740 }
741 advance_widths.push_back(advance_width);
742 }
743
744 for (uint16_t i = 0; i < num_hmetrics; i++) {
745 int16_t lsb;
746 if (has_proportional_lsbs) {
747 if (PREDICT_FALSE(!hmtx_buff_in.ReadS16(&lsb))) {
748 return FONT_COMPRESSION_FAILURE();
749 }
750 } else {
751 lsb = x_mins[i];
752 }
753 lsbs.push_back(lsb);
754 }
755
756 for (uint16_t i = num_hmetrics; i < num_glyphs; i++) {
757 int16_t lsb;
758 if (has_monospace_lsbs) {
759 if (PREDICT_FALSE(!hmtx_buff_in.ReadS16(&lsb))) {
760 return FONT_COMPRESSION_FAILURE();
761 }
762 } else {
763 lsb = x_mins[i];
764 }
765 lsbs.push_back(lsb);
766 }
767
768 // bake me a shiny new hmtx table
769 uint32_t hmtx_output_size = 2 * num_glyphs + 2 * num_hmetrics;
770 std::vector<uint8_t> hmtx_table(hmtx_output_size);
771 uint8_t* dst = &hmtx_table[0];
772 size_t dst_offset = 0;
773 for (uint32_t i = 0; i < num_glyphs; i++) {
774 if (i < num_hmetrics) {
775 Store16(advance_widths[i], &dst_offset, dst);
776 }
777 Store16(lsbs[i], &dst_offset, dst);
778 }
779
780 *checksum = ComputeULongSum(&hmtx_table[0], hmtx_output_size);
781 if (PREDICT_FALSE(!out->Write(&hmtx_table[0], hmtx_output_size))) {
782 return FONT_COMPRESSION_FAILURE();
783 }
784
581 return true; 785 return true;
582 } 786 }
583 787
584 uint32_t ComputeChecksum(const Table* table, const uint8_t* dst) { 788 uint32_t ComputeChecksum(const Table* table, const uint8_t* dst) {
585 return ComputeULongSum(dst + table->dst_offset, table->dst_length); 789 return ComputeULongSum(dst + table->dst_offset, table->dst_length);
586 } 790 }
587 791
588 const Table* FindTable(TtcFont ttc_font, const std::vector<Table>& tables, 792 const Table* FindTable(TtcFont ttc_font, const std::vector<Table>& tables,
589 uint32_t tag) { 793 uint32_t tag) {
590 for (const auto i : ttc_font.table_indices) { 794 for (const auto i : ttc_font.table_indices) {
591 if (tables[i].tag == tag) return &tables[i]; 795 if (tables[i].tag == tag) return &tables[i];
592 } 796 }
593 return NULL; 797 return NULL;
594 } 798 }
595 799
596 bool FixCollectionChecksums(size_t header_version,
597 const std::vector<Table>& tables, const std::vector<TtcFont>& ttc_fonts,
598 uint8_t* dst) {
599 size_t offset = CollectionHeaderSize(header_version, ttc_fonts.size());
600
601 for (const auto& ttc_font : ttc_fonts) {
602 offset += 12; // move to start of Offset Table
603 const std::vector<uint16_t>& table_indices = ttc_font.table_indices;
604
605 const Table* head_table = FindTable(ttc_font, tables, kHeadTableTag);
606 if (PREDICT_FALSE(head_table == NULL ||
607 head_table->dst_length < kCheckSumAdjustmentOffset + 4)) {
608 return FONT_COMPRESSION_FAILURE();
609 }
610
611 size_t first_table_offset = std::numeric_limits<size_t>::max();
612 for (const auto index : table_indices) {
613 const auto& table = tables[index];
614 if (table.dst_offset < first_table_offset) {
615 first_table_offset = table.dst_offset;
616 }
617 }
618
619 size_t adjustment_offset = head_table->dst_offset
620 + kCheckSumAdjustmentOffset;
621 StoreU32(dst, adjustment_offset, 0);
622
623 uint32_t file_checksum = 0;
624 // compute each tables checksum
625 for (size_t i = 0; i < table_indices.size(); i++) {
626 const Table& table = tables[table_indices[i]];
627 uint32_t table_checksum = ComputeChecksum(&table, dst);
628 size_t checksum_offset = offset + 4; // skip past tag to checkSum
629
630 // write the checksum for the Table Record
631 StoreU32(dst, checksum_offset, table_checksum);
632 file_checksum += table_checksum;
633 // next Table Record
634 offset += 16;
635 }
636
637 size_t header_size = kSfntHeaderSize +
638 kSfntEntrySize * table_indices.size();
639 uint32_t header_checksum = ComputeULongSum(dst + ttc_font.dst_offset,
640 header_size);
641
642 file_checksum += header_checksum;
643 uint32_t checksum_adjustment = 0xb1b0afba - file_checksum;
644 StoreU32(dst, adjustment_offset, checksum_adjustment);
645 }
646
647 return true;
648 }
649
650 bool FixChecksums(const std::vector<Table>& tables, uint8_t* dst) {
651 const Table* head_table = FindTable(tables, kHeadTableTag);
652 if (PREDICT_FALSE(head_table == NULL ||
653 head_table->dst_length < kCheckSumAdjustmentOffset + 4)) {
654 return FONT_COMPRESSION_FAILURE();
655 }
656 size_t adjustment_offset = head_table->dst_offset + kCheckSumAdjustmentOffset;
657 StoreU32(dst, adjustment_offset, 0);
658 size_t n_tables = tables.size();
659 uint32_t file_checksum = 0;
660 for (size_t i = 0; i < n_tables; ++i) {
661 uint32_t checksum = ComputeChecksum(&tables[i], dst);
662 StoreU32(dst, kSfntHeaderSize + i * kSfntEntrySize + 4, checksum);
663 file_checksum += checksum;
664 }
665 file_checksum += ComputeULongSum(dst,
666 kSfntHeaderSize + kSfntEntrySize * n_tables);
667 uint32_t checksum_adjustment = 0xb1b0afba - file_checksum;
668 StoreU32(dst, adjustment_offset, checksum_adjustment);
669 return true;
670 }
671
672 bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size, 800 bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size,
673 const uint8_t* src_buf, size_t src_size) { 801 const uint8_t* src_buf, size_t src_size) {
674 size_t uncompressed_size = dst_size; 802 size_t uncompressed_size = dst_size;
675 int ok = BrotliDecompressBuffer(src_size, src_buf, 803 int ok = BrotliDecompressBuffer(src_size, src_buf,
676 &uncompressed_size, dst_buf); 804 &uncompressed_size, dst_buf);
677 if (PREDICT_FALSE(!ok || uncompressed_size != dst_size)) { 805 if (PREDICT_FALSE(!ok || uncompressed_size != dst_size)) {
678 return FONT_COMPRESSION_FAILURE(); 806 return FONT_COMPRESSION_FAILURE();
679 } 807 }
680 return true; 808 return true;
681 } 809 }
682 810
683 bool ReadTableDirectory(Buffer* file, std::vector<Table>* tables, 811 bool ReadTableDirectory(Buffer* file, std::vector<Table>* tables,
684 size_t num_tables) { 812 size_t num_tables) {
813 uint32_t src_offset = 0;
685 for (size_t i = 0; i < num_tables; ++i) { 814 for (size_t i = 0; i < num_tables; ++i) {
686 Table* table = &(*tables)[i]; 815 Table* table = &(*tables)[i];
687 uint8_t flag_byte; 816 uint8_t flag_byte;
688 if (PREDICT_FALSE(!file->ReadU8(&flag_byte))) { 817 if (PREDICT_FALSE(!file->ReadU8(&flag_byte))) {
689 return FONT_COMPRESSION_FAILURE(); 818 return FONT_COMPRESSION_FAILURE();
690 } 819 }
691 uint32_t tag; 820 uint32_t tag;
692 if ((flag_byte & 0x3f) == 0x3f) { 821 if ((flag_byte & 0x3f) == 0x3f) {
693 if (PREDICT_FALSE(!file->ReadU32(&tag))) { 822 if (PREDICT_FALSE(!file->ReadU32(&tag))) {
694 return FONT_COMPRESSION_FAILURE(); 823 return FONT_COMPRESSION_FAILURE();
695 } 824 }
696 } else { 825 } else {
697 tag = kKnownTags[flag_byte & 0x3f]; 826 tag = kKnownTags[flag_byte & 0x3f];
698 } 827 }
699 // Bits 6 and 7 are reserved and must be 0.
700 if (PREDICT_FALSE((flag_byte & 0xC0)) != 0) {
701 return FONT_COMPRESSION_FAILURE();
702 }
703 uint32_t flags = 0; 828 uint32_t flags = 0;
704 // Always transform the glyf and loca tables 829 uint8_t xform_version = (flag_byte >> 6) & 0x03;
830
831 // 0 means xform for glyph/loca, non-0 for others
705 if (tag == kGlyfTableTag || tag == kLocaTableTag) { 832 if (tag == kGlyfTableTag || tag == kLocaTableTag) {
833 if (xform_version == 0) {
834 flags |= kWoff2FlagsTransform;
835 }
836 } else if (xform_version != 0) {
706 flags |= kWoff2FlagsTransform; 837 flags |= kWoff2FlagsTransform;
707 } 838 }
839 flags |= xform_version;
840
708 uint32_t dst_length; 841 uint32_t dst_length;
709 if (PREDICT_FALSE(!ReadBase128(file, &dst_length))) { 842 if (PREDICT_FALSE(!ReadBase128(file, &dst_length))) {
710 return FONT_COMPRESSION_FAILURE(); 843 return FONT_COMPRESSION_FAILURE();
711 } 844 }
712 uint32_t transform_length = dst_length; 845 uint32_t transform_length = dst_length;
713 if ((flags & kWoff2FlagsTransform) != 0) { 846 if ((flags & kWoff2FlagsTransform) != 0) {
714 if (PREDICT_FALSE(!ReadBase128(file, &transform_length))) { 847 if (PREDICT_FALSE(!ReadBase128(file, &transform_length))) {
715 return FONT_COMPRESSION_FAILURE(); 848 return FONT_COMPRESSION_FAILURE();
716 } 849 }
717 if (PREDICT_FALSE(tag == kLocaTableTag && transform_length)) { 850 if (PREDICT_FALSE(tag == kLocaTableTag && transform_length)) {
718 return FONT_COMPRESSION_FAILURE(); 851 return FONT_COMPRESSION_FAILURE();
719 } 852 }
720 } 853 }
854 if (PREDICT_FALSE(src_offset + transform_length < src_offset)) {
855 return FONT_COMPRESSION_FAILURE();
856 }
857 table->src_offset = src_offset;
858 table->src_length = transform_length;
859 src_offset += transform_length;
860
721 table->tag = tag; 861 table->tag = tag;
722 table->flags = flags; 862 table->flags = flags;
723 table->transform_length = transform_length; 863 table->transform_length = transform_length;
724 table->dst_length = dst_length; 864 table->dst_length = dst_length;
725 } 865 }
726 return true; 866 return true;
727 } 867 }
728 868
729 } // namespace
730
731 size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) {
732 Buffer file(data, length);
733 uint32_t total_length;
734
735 if (!file.Skip(16) ||
736 !file.ReadU32(&total_length)) {
737 return 0;
738 }
739 return total_length;
740 }
741
742 // Writes a single Offset Table entry 869 // Writes a single Offset Table entry
743 size_t StoreOffsetTable(uint8_t* result, size_t offset, uint32_t flavor, 870 size_t StoreOffsetTable(uint8_t* result, size_t offset, uint32_t flavor,
744 uint16_t num_tables) { 871 uint16_t num_tables) {
745 offset = StoreU32(result, offset, flavor); // sfnt version 872 offset = StoreU32(result, offset, flavor); // sfnt version
746 offset = Store16(result, offset, num_tables); // num_tables 873 offset = Store16(result, offset, num_tables); // num_tables
747 unsigned max_pow2 = 0; 874 unsigned max_pow2 = 0;
748 while (1u << (max_pow2 + 1) <= num_tables) { 875 while (1u << (max_pow2 + 1) <= num_tables) {
749 max_pow2++; 876 max_pow2++;
750 } 877 }
751 const uint16_t output_search_range = (1u << max_pow2) << 4; 878 const uint16_t output_search_range = (1u << max_pow2) << 4;
752 offset = Store16(result, offset, output_search_range); // searchRange 879 offset = Store16(result, offset, output_search_range); // searchRange
753 offset = Store16(result, offset, max_pow2); // entrySelector 880 offset = Store16(result, offset, max_pow2); // entrySelector
754 // rangeShift 881 // rangeShift
755 offset = Store16(result, offset, (num_tables << 4) - output_search_range); 882 offset = Store16(result, offset, (num_tables << 4) - output_search_range);
756 return offset; 883 return offset;
757 } 884 }
758 885
759 size_t StoreTableEntry(uint8_t* result, const Table& table, size_t offset) { 886 size_t StoreTableEntry(uint8_t* result, uint32_t offset, uint32_t tag) {
760 offset = StoreU32(result, offset, table.tag); 887 offset = StoreU32(result, offset, tag);
761 offset = StoreU32(result, offset, 0); // checksum, to fill in later 888 offset = StoreU32(result, offset, 0);
762 offset = StoreU32(result, offset, table.dst_offset); 889 offset = StoreU32(result, offset, 0);
763 offset = StoreU32(result, offset, table.dst_length); 890 offset = StoreU32(result, offset, 0);
764 return offset; 891 return offset;
765 } 892 }
766 893
767 // First table goes after all the headers, table directory, etc 894 // First table goes after all the headers, table directory, etc
768 uint64_t ComputeOffsetToFirstTable(const uint32_t header_version, 895 uint64_t ComputeOffsetToFirstTable(const WOFF2Header& hdr) {
769 const uint16_t num_tables,
770 const std::vector<TtcFont>& ttc_fonts) {
771 uint64_t offset = kSfntHeaderSize + 896 uint64_t offset = kSfntHeaderSize +
772 kSfntEntrySize * static_cast<uint64_t>(num_tables); 897 kSfntEntrySize * static_cast<uint64_t>(hdr.num_tables);
773 if (header_version) { 898 if (hdr.header_version) {
774 offset = CollectionHeaderSize(header_version, ttc_fonts.size()) 899 offset = CollectionHeaderSize(hdr.header_version, hdr.ttc_fonts.size())
775 + kSfntHeaderSize * ttc_fonts.size(); 900 + kSfntHeaderSize * hdr.ttc_fonts.size();
776 for (const auto& ttc_font : ttc_fonts) { 901 for (const auto& ttc_font : hdr.ttc_fonts) {
777 offset += 902 offset += kSfntEntrySize * ttc_font.table_indices.size();
778 kSfntEntrySize * ttc_font.table_indices.size();
779 } 903 }
780 } 904 }
781 return offset; 905 return offset;
782 } 906 }
783 907
784 bool ConvertWOFF2ToTTF(uint8_t* result, size_t result_length, 908 std::vector<Table*> Tables(WOFF2Header* hdr, size_t font_index) {
785 const uint8_t* data, size_t length) { 909 std::vector<Table*> tables;
910 if (PREDICT_FALSE(hdr->header_version)) {
911 for (auto index : hdr->ttc_fonts[font_index].table_indices) {
912 tables.push_back(&hdr->tables[index]);
913 }
914 } else {
915 for (auto& table : hdr->tables) {
916 tables.push_back(&table);
917 }
918 }
919 return tables;
920 }
921
922 // Offset tables assumed to have been written in with 0's initially.
923 // WOFF2Header isn't const so we can use [] instead of at() (which upsets FF)
924 bool ReconstructFont(uint8_t* transformed_buf,
925 const uint32_t transformed_buf_size,
926 RebuildMetadata* metadata,
927 WOFF2Header* hdr,
928 size_t font_index,
929 WOFF2Out* out) {
930 size_t dest_offset = out->Size();
931 uint8_t table_entry[12];
932 WOFF2FontInfo* info = &metadata->font_infos[font_index];
933 std::vector<Table*> tables = Tables(hdr, font_index);
934
935 // 'glyf' without 'loca' doesn't make sense
936 if (PREDICT_FALSE(static_cast<bool>(FindTable(&tables, kGlyfTableTag)) !=
937 static_cast<bool>(FindTable(&tables, kLocaTableTag)))) {
938 return FONT_COMPRESSION_FAILURE();
939 }
940
941 uint32_t font_checksum = metadata->header_checksum;
942 if (hdr->header_version) {
943 font_checksum = hdr->ttc_fonts[font_index].header_checksum;
944 }
945
946 uint32_t loca_checksum = 0;
947 for (size_t i = 0; i < tables.size(); i++) {
948 Table& table = *tables[i];
949
950 std::pair<uint32_t, uint32_t> checksum_key = {table.tag, table.src_offset};
951 bool reused = metadata->checksums.find(checksum_key)
952 != metadata->checksums.end();
953 if (PREDICT_FALSE(font_index == 0 && reused)) {
954 return FONT_COMPRESSION_FAILURE();
955 }
956
957 // TODO(user) a collection with optimized hmtx that reused glyf/loca
958 // would fail. We don't optimize hmtx for collections yet.
959 if (PREDICT_FALSE(static_cast<uint64_t>(table.src_offset + table.src_length)
960 > transformed_buf_size)) {
961 return FONT_COMPRESSION_FAILURE();
962 }
963
964 if (table.tag == kHheaTableTag) {
965 if (!ReadNumHMetrics(transformed_buf + table.src_offset,
966 table.src_length, &info->num_hmetrics)) {
967 return FONT_COMPRESSION_FAILURE();
968 }
969 }
970
971 uint32_t checksum = 0;
972 if (!reused) {
973 if ((table.flags & kWoff2FlagsTransform) != kWoff2FlagsTransform) {
974 if (table.tag == kHeadTableTag) {
975 if (PREDICT_FALSE(table.src_length < 12)) {
976 return FONT_COMPRESSION_FAILURE();
977 }
978 // checkSumAdjustment = 0
979 StoreU32(transformed_buf + table.src_offset, 8, 0);
980 }
981 table.dst_offset = dest_offset;
982 checksum = ComputeULongSum(transformed_buf + table.src_offset,
983 table.src_length);
984 out->Write(transformed_buf + table.src_offset, table.src_length);
985 } else {
986 if (table.tag == kGlyfTableTag) {
987 table.dst_offset = dest_offset;
988
989 Table* loca_table = FindTable(&tables, kLocaTableTag);
990 if (PREDICT_FALSE(!ReconstructGlyf(transformed_buf + table.src_offset,
991 &table, &checksum, loca_table, &loca_checksum, info, out))) {
992 return FONT_COMPRESSION_FAILURE();
993 }
994 } else if (table.tag == kLocaTableTag) {
995 // All the work was done by ReconstructGlyf. We already know checksum.
996 checksum = loca_checksum;
997 } else if (table.tag == kHmtxTableTag) {
998 table.dst_offset = dest_offset;
999 // Tables are sorted so all the info we need has been gathered.
1000 if (PREDICT_FALSE(!ReconstructTransformedHmtx(
1001 transformed_buf + table.src_offset, table.src_length,
1002 info->num_glyphs, info->num_hmetrics, info->x_mins, &checksum,
1003 out))) {
1004 return FONT_COMPRESSION_FAILURE();
1005 }
1006 } else {
1007 return FONT_COMPRESSION_FAILURE(); // transform unknown
1008 }
1009 }
1010 metadata->checksums[checksum_key] = checksum;
1011 } else {
1012 checksum = metadata->checksums[checksum_key];
1013 }
1014 font_checksum += checksum;
1015
1016 // update the table entry with real values.
1017 StoreU32(table_entry, 0, checksum);
1018 StoreU32(table_entry, 4, table.dst_offset);
1019 StoreU32(table_entry, 8, table.dst_length);
1020 if (PREDICT_FALSE(!out->Write(table_entry,
1021 info->table_entry_by_tag[table.tag] + 4, 12))) {
1022 return FONT_COMPRESSION_FAILURE();
1023 }
1024
1025 // We replaced 0's. Update overall checksum.
1026 font_checksum += ComputeULongSum(table_entry, 12);
1027
1028 if (PREDICT_FALSE(!Pad4(out))) {
1029 return FONT_COMPRESSION_FAILURE();
1030 }
1031
1032 if (PREDICT_FALSE(static_cast<uint64_t>(table.dst_offset + table.dst_length)
1033 > out->Size())) {
1034 return FONT_COMPRESSION_FAILURE();
1035 }
1036 dest_offset = out->Size();
1037 }
1038
1039 // Update 'head' checkSumAdjustment. We already set it to 0 and summed font.
1040 Table* head_table = FindTable(&tables, kHeadTableTag);
1041 if (head_table) {
1042 if (PREDICT_FALSE(head_table->dst_length < 12)) {
1043 return FONT_COMPRESSION_FAILURE();
1044 }
1045 uint8_t checksum_adjustment[4];
1046 StoreU32(checksum_adjustment, 0, 0xB1B0AFBA - font_checksum);
1047 if (PREDICT_FALSE(!out->Write(checksum_adjustment,
1048 head_table->dst_offset + 8, 4))) {
1049 return FONT_COMPRESSION_FAILURE();
1050 }
1051 }
1052
1053 return true;
1054 }
1055
1056 bool ReadWOFF2Header(const uint8_t* data, size_t length, WOFF2Header* hdr) {
786 Buffer file(data, length); 1057 Buffer file(data, length);
787 1058
788 uint32_t signature; 1059 uint32_t signature;
789 uint32_t flavor;
790 if (PREDICT_FALSE(!file.ReadU32(&signature) || signature != kWoff2Signature || 1060 if (PREDICT_FALSE(!file.ReadU32(&signature) || signature != kWoff2Signature ||
791 !file.ReadU32(&flavor))) { 1061 !file.ReadU32(&hdr->flavor))) {
792 return FONT_COMPRESSION_FAILURE(); 1062 return FONT_COMPRESSION_FAILURE();
793 } 1063 }
794 1064
795 // TODO(user): Should call IsValidVersionTag() here. 1065 // TODO(user): Should call IsValidVersionTag() here.
796 1066
797 uint32_t reported_length; 1067 uint32_t reported_length;
798 if (PREDICT_FALSE( 1068 if (PREDICT_FALSE(
799 !file.ReadU32(&reported_length) || length != reported_length)) { 1069 !file.ReadU32(&reported_length) || length != reported_length)) {
800 return FONT_COMPRESSION_FAILURE(); 1070 return FONT_COMPRESSION_FAILURE();
801 } 1071 }
802 uint16_t num_tables; 1072 if (PREDICT_FALSE(!file.ReadU16(&hdr->num_tables) || !hdr->num_tables)) {
803 if (PREDICT_FALSE(!file.ReadU16(&num_tables) || !num_tables)) { 1073 return FONT_COMPRESSION_FAILURE();
1074 }
1075
1076 // We don't care about these fields of the header:
1077 // uint16_t reserved
1078 // uint32_t total_sfnt_size, we don't believe this, will compute later
1079 if (PREDICT_FALSE(!file.Skip(6))) {
1080 return FONT_COMPRESSION_FAILURE();
1081 }
1082 if (PREDICT_FALSE(!file.ReadU32(&hdr->compressed_length))) {
804 return FONT_COMPRESSION_FAILURE(); 1083 return FONT_COMPRESSION_FAILURE();
805 } 1084 }
806 // We don't care about these fields of the header: 1085 // We don't care about these fields of the header:
807 // uint16_t reserved
808 // uint32_t total_sfnt_size, the caller already passes it as result_length
809 if (PREDICT_FALSE(!file.Skip(6))) {
810 return FONT_COMPRESSION_FAILURE();
811 }
812 uint32_t compressed_length;
813 if (PREDICT_FALSE(!file.ReadU32(&compressed_length))) {
814 return FONT_COMPRESSION_FAILURE();
815 }
816 // We don't care about these fields of the header:
817 // uint16_t major_version, minor_version 1086 // uint16_t major_version, minor_version
818 if (PREDICT_FALSE(!file.Skip(2 * 2))) { 1087 if (PREDICT_FALSE(!file.Skip(2 * 2))) {
819 return FONT_COMPRESSION_FAILURE(); 1088 return FONT_COMPRESSION_FAILURE();
820 } 1089 }
821 uint32_t meta_offset; 1090 uint32_t meta_offset;
822 uint32_t meta_length; 1091 uint32_t meta_length;
823 uint32_t meta_length_orig; 1092 uint32_t meta_length_orig;
824 if (PREDICT_FALSE(!file.ReadU32(&meta_offset) || 1093 if (PREDICT_FALSE(!file.ReadU32(&meta_offset) ||
825 !file.ReadU32(&meta_length) || 1094 !file.ReadU32(&meta_length) ||
826 !file.ReadU32(&meta_length_orig))) { 1095 !file.ReadU32(&meta_length_orig))) {
(...skipping 10 matching lines...) Expand all
837 if (PREDICT_FALSE(!file.ReadU32(&priv_offset) || 1106 if (PREDICT_FALSE(!file.ReadU32(&priv_offset) ||
838 !file.ReadU32(&priv_length))) { 1107 !file.ReadU32(&priv_length))) {
839 return FONT_COMPRESSION_FAILURE(); 1108 return FONT_COMPRESSION_FAILURE();
840 } 1109 }
841 if (priv_offset) { 1110 if (priv_offset) {
842 if (PREDICT_FALSE( 1111 if (PREDICT_FALSE(
843 priv_offset >= length || length - priv_offset < priv_length)) { 1112 priv_offset >= length || length - priv_offset < priv_length)) {
844 return FONT_COMPRESSION_FAILURE(); 1113 return FONT_COMPRESSION_FAILURE();
845 } 1114 }
846 } 1115 }
847 std::vector<Table> tables(num_tables); 1116 hdr->tables.resize(hdr->num_tables);
848 if (PREDICT_FALSE(!ReadTableDirectory(&file, &tables, num_tables))) { 1117 if (PREDICT_FALSE(!ReadTableDirectory(
1118 &file, &hdr->tables, hdr->num_tables))) {
849 return FONT_COMPRESSION_FAILURE(); 1119 return FONT_COMPRESSION_FAILURE();
850 } 1120 }
851 1121
852 uint32_t header_version = 0; 1122 // Before we sort for output the last table end is the uncompressed size.
853 // for each font in a ttc, metadata to use when rebuilding 1123 Table& last_table = hdr->tables.back();
854 std::vector<TtcFont> ttc_fonts; 1124 hdr->uncompressed_size = last_table.src_offset + last_table.src_length;
855 std::map<const Table*, const Table*> loca_by_glyf; 1125 if (PREDICT_FALSE(hdr->uncompressed_size < last_table.src_offset)) {
1126 return FONT_COMPRESSION_FAILURE();
1127 }
856 1128
857 if (flavor == kTtcFontFlavor) { 1129 hdr->header_version = 0;
858 if (PREDICT_FALSE(!file.ReadU32(&header_version))) { 1130
1131 if (hdr->flavor == kTtcFontFlavor) {
1132 if (PREDICT_FALSE(!file.ReadU32(&hdr->header_version))) {
1133 return FONT_COMPRESSION_FAILURE();
1134 }
1135 if (PREDICT_FALSE(hdr->header_version != 0x00010000
1136 && hdr->header_version != 0x00020000)) {
859 return FONT_COMPRESSION_FAILURE(); 1137 return FONT_COMPRESSION_FAILURE();
860 } 1138 }
861 uint32_t num_fonts; 1139 uint32_t num_fonts;
862 if (PREDICT_FALSE(!Read255UShort(&file, &num_fonts) || !num_fonts)) { 1140 if (PREDICT_FALSE(!Read255UShort(&file, &num_fonts) || !num_fonts)) {
863 return FONT_COMPRESSION_FAILURE(); 1141 return FONT_COMPRESSION_FAILURE();
864 } 1142 }
865 ttc_fonts.resize(num_fonts); 1143 hdr->ttc_fonts.resize(num_fonts);
866 1144
867 for (uint32_t i = 0; i < num_fonts; i++) { 1145 for (uint32_t i = 0; i < num_fonts; i++) {
868 TtcFont& ttc_font = ttc_fonts[i]; 1146 TtcFont& ttc_font = hdr->ttc_fonts[i];
869 uint32_t num_tables; 1147 uint32_t num_tables;
870 if (PREDICT_FALSE(!Read255UShort(&file, &num_tables) || !num_tables)) { 1148 if (PREDICT_FALSE(!Read255UShort(&file, &num_tables) || !num_tables)) {
871 return FONT_COMPRESSION_FAILURE(); 1149 return FONT_COMPRESSION_FAILURE();
872 } 1150 }
873 if (PREDICT_FALSE(!file.ReadU32(&ttc_font.flavor))) { 1151 if (PREDICT_FALSE(!file.ReadU32(&ttc_font.flavor))) {
874 return FONT_COMPRESSION_FAILURE(); 1152 return FONT_COMPRESSION_FAILURE();
875 } 1153 }
876 1154
877 ttc_font.table_indices.resize(num_tables); 1155 ttc_font.table_indices.resize(num_tables);
878 1156
879 const Table* glyf_table = NULL; 1157 const Table* glyf_table = NULL;
880 const Table* loca_table = NULL; 1158 const Table* loca_table = NULL;
881 uint16_t glyf_idx;
882 uint16_t loca_idx;
883 1159
884 for (uint32_t j = 0; j < num_tables; j++) { 1160 for (uint32_t j = 0; j < num_tables; j++) {
885 unsigned int table_idx; 1161 unsigned int table_idx;
886 if (PREDICT_FALSE(!Read255UShort(&file, &table_idx)) || 1162 if (PREDICT_FALSE(!Read255UShort(&file, &table_idx)) ||
887 table_idx >= tables.size()) { 1163 table_idx >= hdr->tables.size()) {
888 return FONT_COMPRESSION_FAILURE(); 1164 return FONT_COMPRESSION_FAILURE();
889 } 1165 }
890 ttc_font.table_indices[j] = table_idx; 1166 ttc_font.table_indices[j] = table_idx;
891 1167
892 const Table& table = tables[table_idx]; 1168 const Table& table = hdr->tables[table_idx];
893 if (table.tag == kLocaTableTag) { 1169 if (table.tag == kLocaTableTag) {
894 loca_table = &table; 1170 loca_table = &table;
895 loca_idx = table_idx;
896 } 1171 }
897 if (table.tag == kGlyfTableTag) { 1172 if (table.tag == kGlyfTableTag) {
898 glyf_table = &table; 1173 glyf_table = &table;
899 glyf_idx = table_idx;
900 } 1174 }
901 1175
902 } 1176 }
903 1177
904 if (PREDICT_FALSE((glyf_table == NULL) != (loca_table == NULL))) { 1178 if (PREDICT_FALSE((glyf_table == NULL) != (loca_table == NULL))) {
905 #ifdef FONT_COMPRESSION_BIN 1179 #ifdef FONT_COMPRESSION_BIN
906 fprintf(stderr, "Cannot have just one of glyf/loca\n"); 1180 fprintf(stderr, "Cannot have just one of glyf/loca\n");
907 #endif 1181 #endif
908 return FONT_COMPRESSION_FAILURE(); 1182 return FONT_COMPRESSION_FAILURE();
909 } 1183 }
910
911 if (glyf_table != NULL && loca_table != NULL) {
912 loca_by_glyf[glyf_table] = loca_table;
913 }
914 } 1184 }
915 } 1185 }
916 1186
917 const uint64_t first_table_offset = 1187 const uint64_t first_table_offset = ComputeOffsetToFirstTable(*hdr);
918 ComputeOffsetToFirstTable(header_version, num_tables, ttc_fonts);
919 1188
920 if (PREDICT_FALSE(first_table_offset > result_length)) { 1189 hdr->compressed_offset = file.offset();
1190 if (PREDICT_FALSE(hdr->compressed_offset >
1191 std::numeric_limits<uint32_t>::max())) {
921 return FONT_COMPRESSION_FAILURE(); 1192 return FONT_COMPRESSION_FAILURE();
922 } 1193 }
923 1194 uint64_t src_offset = Round4(hdr->compressed_offset + hdr->compressed_length);
924 uint64_t compressed_offset = file.offset();
925 if (PREDICT_FALSE(compressed_offset > std::numeric_limits<uint32_t>::max())) {
926 return FONT_COMPRESSION_FAILURE();
927 }
928 uint64_t src_offset = Round4(compressed_offset + compressed_length);
929 uint64_t dst_offset = first_table_offset; 1195 uint64_t dst_offset = first_table_offset;
930 1196
931 1197
932 for (uint16_t i = 0; i < num_tables; ++i) { 1198 if (PREDICT_FALSE(src_offset > length)) {
933 Table* table = &tables[i];
934 table->dst_offset = dst_offset;
935 dst_offset += table->dst_length;
936 if (PREDICT_FALSE(dst_offset > std::numeric_limits<uint32_t>::max())) {
937 return FONT_COMPRESSION_FAILURE();
938 }
939 dst_offset = Round4(dst_offset);
940 }
941 if (PREDICT_FALSE(src_offset > length || dst_offset != result_length)) {
942 #ifdef FONT_COMPRESSION_BIN 1199 #ifdef FONT_COMPRESSION_BIN
943 fprintf(stderr, "offset fail; src_offset %" PRIu64 " length %lu " 1200 fprintf(stderr, "offset fail; src_offset %" PRIu64 " length %lu "
944 "dst_offset %" PRIu64 " result_length %lu\n", 1201 "dst_offset %" PRIu64 "\n",
945 src_offset, length, dst_offset, result_length); 1202 src_offset, length, dst_offset);
946 #endif 1203 #endif
947 return FONT_COMPRESSION_FAILURE(); 1204 return FONT_COMPRESSION_FAILURE();
948 } 1205 }
949
950 // Re-order tables in output (OTSpec) order
951 std::vector<Table> sorted_tables(tables);
952 if (header_version) {
953 // collection; we have to sort the table offset vector in each font
954 for (auto& ttc_font : ttc_fonts) {
955 std::map<uint32_t, uint16_t> sorted_index_by_tag;
956 for (auto table_index : ttc_font.table_indices) {
957 sorted_index_by_tag[tables[table_index].tag] = table_index;
958 }
959 uint16_t index = 0;
960 for (auto& i : sorted_index_by_tag) {
961 ttc_font.table_indices[index++] = i.second;
962 }
963 }
964 } else {
965 // non-collection; we can just sort the tables
966 std::sort(sorted_tables.begin(), sorted_tables.end());
967 }
968
969 if (meta_offset) { 1206 if (meta_offset) {
970 if (PREDICT_FALSE(src_offset != meta_offset)) { 1207 if (PREDICT_FALSE(src_offset != meta_offset)) {
971 return FONT_COMPRESSION_FAILURE(); 1208 return FONT_COMPRESSION_FAILURE();
972 } 1209 }
973 src_offset = Round4(meta_offset + meta_length); 1210 src_offset = Round4(meta_offset + meta_length);
974 if (PREDICT_FALSE(src_offset > std::numeric_limits<uint32_t>::max())) { 1211 if (PREDICT_FALSE(src_offset > std::numeric_limits<uint32_t>::max())) {
975 return FONT_COMPRESSION_FAILURE(); 1212 return FONT_COMPRESSION_FAILURE();
976 } 1213 }
977 } 1214 }
978 1215
979 if (priv_offset) { 1216 if (priv_offset) {
980 if (PREDICT_FALSE(src_offset != priv_offset)) { 1217 if (PREDICT_FALSE(src_offset != priv_offset)) {
981 return FONT_COMPRESSION_FAILURE(); 1218 return FONT_COMPRESSION_FAILURE();
982 } 1219 }
983 src_offset = Round4(priv_offset + priv_length); 1220 src_offset = Round4(priv_offset + priv_length);
984 if (PREDICT_FALSE(src_offset > std::numeric_limits<uint32_t>::max())) { 1221 if (PREDICT_FALSE(src_offset > std::numeric_limits<uint32_t>::max())) {
985 return FONT_COMPRESSION_FAILURE(); 1222 return FONT_COMPRESSION_FAILURE();
986 } 1223 }
987 } 1224 }
988 1225
989 if (PREDICT_FALSE(src_offset != Round4(length))) { 1226 if (PREDICT_FALSE(src_offset != Round4(length))) {
990 return FONT_COMPRESSION_FAILURE(); 1227 return FONT_COMPRESSION_FAILURE();
991 } 1228 }
992 1229
1230 return true;
1231 }
1232
1233 // Write everything before the actual table data
1234 bool WriteHeaders(const uint8_t* data, size_t length, RebuildMetadata* metadata,
1235 WOFF2Header* hdr, WOFF2Out* out) {
1236 std::vector<uint8_t> output(ComputeOffsetToFirstTable(*hdr), 0);
1237
1238 // Re-order tables in output (OTSpec) order
1239 std::vector<Table> sorted_tables(hdr->tables);
1240 if (hdr->header_version) {
1241 // collection; we have to sort the table offset vector in each font
1242 for (auto& ttc_font : hdr->ttc_fonts) {
1243 std::map<uint32_t, uint16_t> sorted_index_by_tag;
1244 for (auto table_index : ttc_font.table_indices) {
1245 sorted_index_by_tag[hdr->tables[table_index].tag] = table_index;
1246 }
1247 uint16_t index = 0;
1248 for (auto& i : sorted_index_by_tag) {
1249 ttc_font.table_indices[index++] = i.second;
1250 }
1251 }
1252 } else {
1253 // non-collection; we can just sort the tables
1254 std::sort(sorted_tables.begin(), sorted_tables.end());
1255 }
1256
993 // Start building the font 1257 // Start building the font
1258 uint8_t* result = &output[0];
994 size_t offset = 0; 1259 size_t offset = 0;
995 size_t offset_table = 0; 1260 if (hdr->header_version) {
996 if (header_version) {
997 // TTC header 1261 // TTC header
998 offset = StoreU32(result, offset, flavor); // TAG TTCTag 1262 offset = StoreU32(result, offset, hdr->flavor); // TAG TTCTag
999 offset = StoreU32(result, offset, header_version); // FIXED Version 1263 offset = StoreU32(result, offset, hdr->header_version); // FIXED Version
1000 offset = StoreU32(result, offset, ttc_fonts.size()); // ULONG numFonts 1264 offset = StoreU32(result, offset, hdr->ttc_fonts.size()); // ULONG numFonts
1001 // Space for ULONG OffsetTable[numFonts] (zeroed initially) 1265 // Space for ULONG OffsetTable[numFonts] (zeroed initially)
1002 offset_table = offset; // keep start of offset table for later 1266 size_t offset_table = offset; // keep start of offset table for later
1003 for (size_t i = 0; i < ttc_fonts.size(); i++) { 1267 for (size_t i = 0; i < hdr->ttc_fonts.size(); i++) {
1004 offset = StoreU32(result, offset, 0); // will fill real values in later 1268 offset = StoreU32(result, offset, 0); // will fill real values in later
1005 } 1269 }
1006 // space for DSIG fields for header v2 1270 // space for DSIG fields for header v2
1007 if (header_version == 0x00020000) { 1271 if (hdr->header_version == 0x00020000) {
1008 offset = StoreU32(result, offset, 0); // ULONG ulDsigTag 1272 offset = StoreU32(result, offset, 0); // ULONG ulDsigTag
1009 offset = StoreU32(result, offset, 0); // ULONG ulDsigLength 1273 offset = StoreU32(result, offset, 0); // ULONG ulDsigLength
1010 offset = StoreU32(result, offset, 0); // ULONG ulDsigOffset 1274 offset = StoreU32(result, offset, 0); // ULONG ulDsigOffset
1011 } 1275 }
1012 1276
1013 // write Offset Tables and store the location of each in TTC Header 1277 // write Offset Tables and store the location of each in TTC Header
1014 for (auto& ttc_font : ttc_fonts) { 1278 metadata->font_infos.resize(hdr->ttc_fonts.size());
1279 for (size_t i = 0; i < hdr->ttc_fonts.size(); i++) {
1280 TtcFont& ttc_font = hdr->ttc_fonts[i];
1281
1015 // write Offset Table location into TTC Header 1282 // write Offset Table location into TTC Header
1016 offset_table = StoreU32(result, offset_table, offset); 1283 offset_table = StoreU32(result, offset_table, offset);
1017 1284
1018 // write the actual offset table so our header doesn't lie 1285 // write the actual offset table so our header doesn't lie
1019 ttc_font.dst_offset = offset; 1286 ttc_font.dst_offset = offset;
1020 offset = StoreOffsetTable(result, offset, ttc_font.flavor, 1287 offset = StoreOffsetTable(result, offset, ttc_font.flavor,
1021 ttc_font.table_indices.size()); 1288 ttc_font.table_indices.size());
1022 1289
1023 // write table entries
1024 for (const auto table_index : ttc_font.table_indices) { 1290 for (const auto table_index : ttc_font.table_indices) {
1025 offset = StoreTableEntry(result, tables[table_index], offset); 1291 uint32_t tag = hdr->tables[table_index].tag;
1292 metadata->font_infos[i].table_entry_by_tag[tag] = offset;
1293 offset = StoreTableEntry(result, offset, tag);
1026 } 1294 }
1295
1296 ttc_font.header_checksum = ComputeULongSum(&output[ttc_font.dst_offset],
1297 offset - ttc_font.dst_offset);
1027 } 1298 }
1028 } else { 1299 } else {
1029 offset = StoreOffsetTable(result, offset, flavor, num_tables); 1300 metadata->font_infos.resize(1);
1030 for (uint16_t i = 0; i < num_tables; ++i) { 1301 offset = StoreOffsetTable(result, offset, hdr->flavor, hdr->num_tables);
1031 offset = StoreTableEntry(result, sorted_tables[i], offset); 1302 for (uint16_t i = 0; i < hdr->num_tables; ++i) {
1303 metadata->font_infos[0].table_entry_by_tag[sorted_tables[i].tag] = offset;
1304 offset = StoreTableEntry(result, offset, sorted_tables[i].tag);
1032 } 1305 }
1033 } 1306 }
1034 1307
1035 std::vector<uint8_t> uncompressed_buf; 1308 if (PREDICT_FALSE(!out->Write(&output[0], output.size()))) {
1036 const uint8_t* transform_buf = NULL; 1309 return FONT_COMPRESSION_FAILURE();
1037 uint64_t total_size = 0; 1310 }
1038 for (uint16_t i = 0; i < num_tables; ++i) { 1311 metadata->header_checksum = ComputeULongSum(&output[0], output.size());
1039 total_size += tables[i].transform_length; 1312 return true;
1040 if (PREDICT_FALSE(total_size > std::numeric_limits<uint32_t>::max())) { 1313 }
1314
1315 } // namespace
1316
1317 size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) {
1318 Buffer file(data, length);
1319 uint32_t total_length;
1320
1321 if (!file.Skip(16) ||
1322 !file.ReadU32(&total_length)) {
1323 return 0;
1324 }
1325 return total_length;
1326 }
1327
1328 bool ConvertWOFF2ToTTF(uint8_t *result, size_t result_length,
1329 const uint8_t *data, size_t length) {
1330 WOFF2MemoryOut out(result, result_length);
1331 return ConvertWOFF2ToTTF(data, length, &out);
1332 }
1333
1334 bool ConvertWOFF2ToTTF(const uint8_t* data, size_t length,
1335 WOFF2Out* out) {
1336 RebuildMetadata metadata;
1337 WOFF2Header hdr;
1338 if (!ReadWOFF2Header(data, length, &hdr)) {
1339 return FONT_COMPRESSION_FAILURE();
1340 }
1341
1342 if (!WriteHeaders(data, length, &metadata, &hdr, out)) {
1343 return FONT_COMPRESSION_FAILURE();
1344 }
1345
1346 const uint8_t* src_buf = data + hdr.compressed_offset;
1347 std::vector<uint8_t> uncompressed_buf(hdr.uncompressed_size);
1348 if (PREDICT_FALSE(!Woff2Uncompress(&uncompressed_buf[0],
1349 hdr.uncompressed_size, src_buf,
1350 hdr.compressed_length))) {
1351 return FONT_COMPRESSION_FAILURE();
1352 }
1353
1354 for (size_t i = 0; i < metadata.font_infos.size(); i++) {
1355 if (PREDICT_FALSE(!ReconstructFont(&uncompressed_buf[0],
1356 hdr.uncompressed_size,
1357 &metadata, &hdr, i, out))) {
1041 return FONT_COMPRESSION_FAILURE(); 1358 return FONT_COMPRESSION_FAILURE();
1042 } 1359 }
1043 } 1360 }
1044 uncompressed_buf.resize(total_size);
1045 const uint8_t* src_buf = data + compressed_offset;
1046 if (PREDICT_FALSE(!Woff2Uncompress(&uncompressed_buf[0], total_size,
1047 src_buf, compressed_length))) {
1048 return FONT_COMPRESSION_FAILURE();
1049 }
1050 transform_buf = &uncompressed_buf[0];
1051
1052 for (uint16_t i = 0; i < num_tables; ++i) {
1053 const Table* table = &tables[i];
1054 uint32_t flags = table->flags;
1055 size_t transform_length = table->transform_length;
1056
1057 if ((flags & kWoff2FlagsTransform) == 0) {
1058 if (PREDICT_FALSE(transform_length != table->dst_length)) {
1059 return FONT_COMPRESSION_FAILURE();
1060 }
1061 if (PREDICT_FALSE(static_cast<uint64_t>(table->dst_offset +
1062 transform_length) > result_length)) {
1063 return FONT_COMPRESSION_FAILURE();
1064 }
1065
1066 std::memcpy(result + table->dst_offset, transform_buf,
1067 transform_length);
1068 } else {
1069 if (header_version) {
1070 if (table->tag == kGlyfTableTag) {
1071 const Table* loca_table = loca_by_glyf[table];
1072 if (PREDICT_FALSE(!ReconstructTransformedGlyf(transform_buf,
1073 transform_length, table, loca_table, result, result_length))) {
1074 return FONT_COMPRESSION_FAILURE();
1075 }
1076 } else if (PREDICT_FALSE(table->tag != kLocaTableTag)) {
1077 // transform for this tag not known
1078 return FONT_COMPRESSION_FAILURE();
1079 }
1080 } else {
1081 if (PREDICT_FALSE(!ReconstructTransformed(tables, table->tag,
1082 transform_buf, transform_length, result, result_length))) {
1083 return FONT_COMPRESSION_FAILURE();
1084 }
1085 }
1086 }
1087 transform_buf += transform_length;
1088 if (PREDICT_FALSE(
1089 transform_buf > &uncompressed_buf[0] + uncompressed_buf.size())) {
1090 return FONT_COMPRESSION_FAILURE();
1091 }
1092 }
1093
1094 if (header_version) {
1095 if (PREDICT_FALSE(
1096 !FixCollectionChecksums(header_version, tables, ttc_fonts, result))) {
1097 return FONT_COMPRESSION_FAILURE();
1098 }
1099 } else {
1100 if (PREDICT_FALSE(!FixChecksums(sorted_tables, result))) {
1101 return FONT_COMPRESSION_FAILURE();
1102 }
1103 }
1104 1361
1105 return true; 1362 return true;
1106 } 1363 }
1107 1364
1108 } // namespace woff2 1365 } // namespace woff2
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698