Update mojo sdk to rev 1dc8a9a5db73d3718d99917fadf31f5fb2ebad4f
[chromium-blink-merge.git] / third_party / woff2 / src / woff2_dec.cc
blobe2bf6fbd8adc7307a0db1a9cf095c70fbee6aff5
1 // Copyright 2014 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 // Library for converting WOFF2 format font files to their TTF versions.
17 #include "./woff2_dec.h"
19 #include <stdlib.h>
20 #include <complex>
21 #include <cstring>
22 #include <limits>
23 #include <string>
24 #include <algorithm>
25 #include <vector>
27 #include "./buffer.h"
28 #include "./decode.h"
29 #include "./round.h"
30 #include "./store_bytes.h"
31 #include "./table_tags.h"
32 #include "./woff2_common.h"
34 namespace woff2 {
36 namespace {
38 using std::string;
39 using std::vector;
42 // simple glyph flags
43 const int kGlyfOnCurve = 1 << 0;
44 const int kGlyfXShort = 1 << 1;
45 const int kGlyfYShort = 1 << 2;
46 const int kGlyfRepeat = 1 << 3;
47 const int kGlyfThisXIsSame = 1 << 4;
48 const int kGlyfThisYIsSame = 1 << 5;
50 // composite glyph flags
51 // See CompositeGlyph.java in sfntly for full definitions
52 const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
53 const int FLAG_WE_HAVE_A_SCALE = 1 << 3;
54 const int FLAG_MORE_COMPONENTS = 1 << 5;
55 const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
56 const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
57 const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
59 const size_t kSfntHeaderSize = 12;
60 const size_t kSfntEntrySize = 16;
61 const size_t kCheckSumAdjustmentOffset = 8;
63 const size_t kEndPtsOfContoursOffset = 10;
64 const size_t kCompositeGlyphBegin = 10;
66 // Based on section 6.1.1 of MicroType Express draft spec
67 bool Read255UShort(Buffer* buf, unsigned int* value) {
68 static const int kWordCode = 253;
69 static const int kOneMoreByteCode2 = 254;
70 static const int kOneMoreByteCode1 = 255;
71 static const int kLowestUCode = 253;
72 uint8_t code = 0;
73 if (!buf->ReadU8(&code)) {
74 return FONT_COMPRESSION_FAILURE();
76 if (code == kWordCode) {
77 uint16_t result = 0;
78 if (!buf->ReadU16(&result)) {
79 return FONT_COMPRESSION_FAILURE();
81 *value = result;
82 return true;
83 } else if (code == kOneMoreByteCode1) {
84 uint8_t result = 0;
85 if (!buf->ReadU8(&result)) {
86 return FONT_COMPRESSION_FAILURE();
88 *value = result + kLowestUCode;
89 return true;
90 } else if (code == kOneMoreByteCode2) {
91 uint8_t result = 0;
92 if (!buf->ReadU8(&result)) {
93 return FONT_COMPRESSION_FAILURE();
95 *value = result + kLowestUCode * 2;
96 return true;
97 } else {
98 *value = code;
99 return true;
103 bool ReadBase128(Buffer* buf, uint32_t* value) {
104 uint32_t result = 0;
105 for (size_t i = 0; i < 5; ++i) {
106 uint8_t code = 0;
107 if (!buf->ReadU8(&code)) {
108 return FONT_COMPRESSION_FAILURE();
110 // If any of the top seven bits are set then we're about to overflow.
111 if (result & 0xfe000000) {
112 return FONT_COMPRESSION_FAILURE();
114 result = (result << 7) | (code & 0x7f);
115 if ((code & 0x80) == 0) {
116 *value = result;
117 return true;
120 // Make sure not to exceed the size bound
121 return FONT_COMPRESSION_FAILURE();
124 int WithSign(int flag, int baseval) {
125 // Precondition: 0 <= baseval < 65536 (to avoid integer overflow)
126 return (flag & 1) ? baseval : -baseval;
129 bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size,
130 unsigned int n_points, std::vector<Point>* result,
131 size_t* in_bytes_consumed) {
132 int x = 0;
133 int y = 0;
135 if (n_points > in_size) {
136 return FONT_COMPRESSION_FAILURE();
138 unsigned int triplet_index = 0;
140 for (unsigned int i = 0; i < n_points; ++i) {
141 uint8_t flag = flags_in[i];
142 bool on_curve = !(flag >> 7);
143 flag &= 0x7f;
144 unsigned int n_data_bytes;
145 if (flag < 84) {
146 n_data_bytes = 1;
147 } else if (flag < 120) {
148 n_data_bytes = 2;
149 } else if (flag < 124) {
150 n_data_bytes = 3;
151 } else {
152 n_data_bytes = 4;
154 if (triplet_index + n_data_bytes > in_size ||
155 triplet_index + n_data_bytes < triplet_index) {
156 return FONT_COMPRESSION_FAILURE();
158 int dx, dy;
159 if (flag < 10) {
160 dx = 0;
161 dy = WithSign(flag, ((flag & 14) << 7) + in[triplet_index]);
162 } else if (flag < 20) {
163 dx = WithSign(flag, (((flag - 10) & 14) << 7) + in[triplet_index]);
164 dy = 0;
165 } else if (flag < 84) {
166 int b0 = flag - 20;
167 int b1 = in[triplet_index];
168 dx = WithSign(flag, 1 + (b0 & 0x30) + (b1 >> 4));
169 dy = WithSign(flag >> 1, 1 + ((b0 & 0x0c) << 2) + (b1 & 0x0f));
170 } else if (flag < 120) {
171 int b0 = flag - 84;
172 dx = WithSign(flag, 1 + ((b0 / 12) << 8) + in[triplet_index]);
173 dy = WithSign(flag >> 1,
174 1 + (((b0 % 12) >> 2) << 8) + in[triplet_index + 1]);
175 } else if (flag < 124) {
176 int b2 = in[triplet_index + 1];
177 dx = WithSign(flag, (in[triplet_index] << 4) + (b2 >> 4));
178 dy = WithSign(flag >> 1, ((b2 & 0x0f) << 8) + in[triplet_index + 2]);
179 } else {
180 dx = WithSign(flag, (in[triplet_index] << 8) + in[triplet_index + 1]);
181 dy = WithSign(flag >> 1,
182 (in[triplet_index + 2] << 8) + in[triplet_index + 3]);
184 triplet_index += n_data_bytes;
185 // Possible overflow but coordinate values are not security sensitive
186 x += dx;
187 y += dy;
188 result->push_back(Point());
189 Point& back = result->back();
190 back.x = x;
191 back.y = y;
192 back.on_curve = on_curve;
194 *in_bytes_consumed = triplet_index;
195 return true;
198 // This function stores just the point data. On entry, dst points to the
199 // beginning of a simple glyph. Returns true on success.
200 bool StorePoints(const std::vector<Point>& points,
201 unsigned int n_contours, unsigned int instruction_length,
202 uint8_t* dst, size_t dst_size, size_t* glyph_size) {
203 // I believe that n_contours < 65536, in which case this is safe. However, a
204 // comment and/or an assert would be good.
205 unsigned int flag_offset = kEndPtsOfContoursOffset + 2 * n_contours + 2 +
206 instruction_length;
207 int last_flag = -1;
208 int repeat_count = 0;
209 int last_x = 0;
210 int last_y = 0;
211 unsigned int x_bytes = 0;
212 unsigned int y_bytes = 0;
214 for (unsigned int i = 0; i < points.size(); ++i) {
215 const Point& point = points[i];
216 int flag = point.on_curve ? kGlyfOnCurve : 0;
217 int dx = point.x - last_x;
218 int dy = point.y - last_y;
219 if (dx == 0) {
220 flag |= kGlyfThisXIsSame;
221 } else if (dx > -256 && dx < 256) {
222 flag |= kGlyfXShort | (dx > 0 ? kGlyfThisXIsSame : 0);
223 x_bytes += 1;
224 } else {
225 x_bytes += 2;
227 if (dy == 0) {
228 flag |= kGlyfThisYIsSame;
229 } else if (dy > -256 && dy < 256) {
230 flag |= kGlyfYShort | (dy > 0 ? kGlyfThisYIsSame : 0);
231 y_bytes += 1;
232 } else {
233 y_bytes += 2;
236 if (flag == last_flag && repeat_count != 255) {
237 dst[flag_offset - 1] |= kGlyfRepeat;
238 repeat_count++;
239 } else {
240 if (repeat_count != 0) {
241 if (flag_offset >= dst_size) {
242 return FONT_COMPRESSION_FAILURE();
244 dst[flag_offset++] = repeat_count;
246 if (flag_offset >= dst_size) {
247 return FONT_COMPRESSION_FAILURE();
249 dst[flag_offset++] = flag;
250 repeat_count = 0;
252 last_x = point.x;
253 last_y = point.y;
254 last_flag = flag;
257 if (repeat_count != 0) {
258 if (flag_offset >= dst_size) {
259 return FONT_COMPRESSION_FAILURE();
261 dst[flag_offset++] = repeat_count;
263 unsigned int xy_bytes = x_bytes + y_bytes;
264 if (xy_bytes < x_bytes ||
265 flag_offset + xy_bytes < flag_offset ||
266 flag_offset + xy_bytes > dst_size) {
267 return FONT_COMPRESSION_FAILURE();
270 int x_offset = flag_offset;
271 int y_offset = flag_offset + x_bytes;
272 last_x = 0;
273 last_y = 0;
274 for (unsigned int i = 0; i < points.size(); ++i) {
275 int dx = points[i].x - last_x;
276 if (dx == 0) {
277 // pass
278 } else if (dx > -256 && dx < 256) {
279 dst[x_offset++] = std::abs(dx);
280 } else {
281 // will always fit for valid input, but overflow is harmless
282 x_offset = Store16(dst, x_offset, dx);
284 last_x += dx;
285 int dy = points[i].y - last_y;
286 if (dy == 0) {
287 // pass
288 } else if (dy > -256 && dy < 256) {
289 dst[y_offset++] = std::abs(dy);
290 } else {
291 y_offset = Store16(dst, y_offset, dy);
293 last_y += dy;
295 *glyph_size = y_offset;
296 return true;
299 // Compute the bounding box of the coordinates, and store into a glyf buffer.
300 // A precondition is that there are at least 10 bytes available.
301 void ComputeBbox(const std::vector<Point>& points, uint8_t* dst) {
302 int x_min = 0;
303 int y_min = 0;
304 int x_max = 0;
305 int y_max = 0;
307 for (unsigned int i = 0; i < points.size(); ++i) {
308 int x = points[i].x;
309 int y = points[i].y;
310 if (i == 0 || x < x_min) x_min = x;
311 if (i == 0 || x > x_max) x_max = x;
312 if (i == 0 || y < y_min) y_min = y;
313 if (i == 0 || y > y_max) y_max = y;
315 size_t offset = 2;
316 offset = Store16(dst, offset, x_min);
317 offset = Store16(dst, offset, y_min);
318 offset = Store16(dst, offset, x_max);
319 offset = Store16(dst, offset, y_max);
322 // Process entire bbox stream. This is done as a separate pass to allow for
323 // composite bbox computations (an optional more aggressive transform).
324 bool ProcessBboxStream(Buffer* bbox_stream, unsigned int n_glyphs,
325 const std::vector<uint32_t>& loca_values, uint8_t* glyf_buf,
326 size_t glyf_buf_length) {
327 const uint8_t* buf = bbox_stream->buffer();
328 if (n_glyphs >= 65536 || loca_values.size() != n_glyphs + 1) {
329 return FONT_COMPRESSION_FAILURE();
331 // Safe because n_glyphs is bounded
332 unsigned int bitmap_length = ((n_glyphs + 31) >> 5) << 2;
333 if (!bbox_stream->Skip(bitmap_length)) {
334 return FONT_COMPRESSION_FAILURE();
336 for (unsigned int i = 0; i < n_glyphs; ++i) {
337 if (buf[i >> 3] & (0x80 >> (i & 7))) {
338 uint32_t loca_offset = loca_values[i];
339 if (loca_values[i + 1] - loca_offset < kEndPtsOfContoursOffset) {
340 return FONT_COMPRESSION_FAILURE();
342 if (glyf_buf_length < 2 + 10 ||
343 loca_offset > glyf_buf_length - 2 - 10) {
344 return FONT_COMPRESSION_FAILURE();
346 if (!bbox_stream->Read(glyf_buf + loca_offset + 2, 8)) {
347 return FONT_COMPRESSION_FAILURE();
351 return true;
354 bool ProcessComposite(Buffer* composite_stream, uint8_t* dst,
355 size_t dst_size, size_t* glyph_size, bool* have_instructions) {
356 size_t start_offset = composite_stream->offset();
357 bool we_have_instructions = false;
359 uint16_t flags = FLAG_MORE_COMPONENTS;
360 while (flags & FLAG_MORE_COMPONENTS) {
361 if (!composite_stream->ReadU16(&flags)) {
362 return FONT_COMPRESSION_FAILURE();
364 we_have_instructions |= (flags & FLAG_WE_HAVE_INSTRUCTIONS) != 0;
365 size_t arg_size = 2; // glyph index
366 if (flags & FLAG_ARG_1_AND_2_ARE_WORDS) {
367 arg_size += 4;
368 } else {
369 arg_size += 2;
371 if (flags & FLAG_WE_HAVE_A_SCALE) {
372 arg_size += 2;
373 } else if (flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE) {
374 arg_size += 4;
375 } else if (flags & FLAG_WE_HAVE_A_TWO_BY_TWO) {
376 arg_size += 8;
378 if (!composite_stream->Skip(arg_size)) {
379 return FONT_COMPRESSION_FAILURE();
382 size_t composite_glyph_size = composite_stream->offset() - start_offset;
383 if (composite_glyph_size + kCompositeGlyphBegin > dst_size) {
384 return FONT_COMPRESSION_FAILURE();
386 Store16(dst, 0, 0xffff); // nContours = -1 for composite glyph
387 std::memcpy(dst + kCompositeGlyphBegin,
388 composite_stream->buffer() + start_offset,
389 composite_glyph_size);
390 *glyph_size = kCompositeGlyphBegin + composite_glyph_size;
391 *have_instructions = we_have_instructions;
392 return true;
395 // Build TrueType loca table
396 bool StoreLoca(const std::vector<uint32_t>& loca_values, int index_format,
397 uint8_t* dst, size_t dst_size) {
398 const uint64_t loca_size = loca_values.size();
399 const uint64_t offset_size = index_format ? 4 : 2;
400 if ((loca_size << 2) >> 2 != loca_size) {
401 return FONT_COMPRESSION_FAILURE();
403 if (offset_size * loca_size > dst_size) {
404 return FONT_COMPRESSION_FAILURE();
406 size_t offset = 0;
407 for (size_t i = 0; i < loca_values.size(); ++i) {
408 uint32_t value = loca_values[i];
409 if (index_format) {
410 offset = StoreU32(dst, offset, value);
411 } else {
412 offset = Store16(dst, offset, value >> 1);
415 return true;
418 // Reconstruct entire glyf table based on transformed original
419 bool ReconstructGlyf(const uint8_t* data, size_t data_size,
420 uint8_t* dst, size_t dst_size,
421 uint8_t* loca_buf, size_t loca_size) {
422 static const int kNumSubStreams = 7;
423 Buffer file(data, data_size);
424 uint32_t version;
425 std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams);
427 if (!file.ReadU32(&version)) {
428 return FONT_COMPRESSION_FAILURE();
430 uint16_t num_glyphs;
431 uint16_t index_format;
432 if (!file.ReadU16(&num_glyphs) ||
433 !file.ReadU16(&index_format)) {
434 return FONT_COMPRESSION_FAILURE();
436 unsigned int offset = (2 + kNumSubStreams) * 4;
437 if (offset > data_size) {
438 return FONT_COMPRESSION_FAILURE();
440 // Invariant from here on: data_size >= offset
441 for (int i = 0; i < kNumSubStreams; ++i) {
442 uint32_t substream_size;
443 if (!file.ReadU32(&substream_size)) {
444 return FONT_COMPRESSION_FAILURE();
446 if (substream_size > data_size - offset) {
447 return FONT_COMPRESSION_FAILURE();
449 substreams[i] = std::make_pair(data + offset, substream_size);
450 offset += substream_size;
452 Buffer n_contour_stream(substreams[0].first, substreams[0].second);
453 Buffer n_points_stream(substreams[1].first, substreams[1].second);
454 Buffer flag_stream(substreams[2].first, substreams[2].second);
455 Buffer glyph_stream(substreams[3].first, substreams[3].second);
456 Buffer composite_stream(substreams[4].first, substreams[4].second);
457 Buffer bbox_stream(substreams[5].first, substreams[5].second);
458 Buffer instruction_stream(substreams[6].first, substreams[6].second);
460 std::vector<uint32_t> loca_values(num_glyphs + 1);
461 std::vector<unsigned int> n_points_vec;
462 std::vector<Point> points;
463 uint32_t loca_offset = 0;
464 for (unsigned int i = 0; i < num_glyphs; ++i) {
465 size_t glyph_size = 0;
466 uint16_t n_contours = 0;
467 if (!n_contour_stream.ReadU16(&n_contours)) {
468 return FONT_COMPRESSION_FAILURE();
470 uint8_t* glyf_dst = dst + loca_offset;
471 size_t glyf_dst_size = dst_size - loca_offset;
472 if (n_contours == 0xffff) {
473 // composite glyph
474 bool have_instructions = false;
475 unsigned int instruction_size = 0;
476 if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size,
477 &glyph_size, &have_instructions)) {
478 return FONT_COMPRESSION_FAILURE();
480 if (have_instructions) {
481 if (!Read255UShort(&glyph_stream, &instruction_size)) {
482 return FONT_COMPRESSION_FAILURE();
484 if (instruction_size + 2 > glyf_dst_size - glyph_size) {
485 return FONT_COMPRESSION_FAILURE();
487 Store16(glyf_dst, glyph_size, instruction_size);
488 if (!instruction_stream.Read(glyf_dst + glyph_size + 2,
489 instruction_size)) {
490 return FONT_COMPRESSION_FAILURE();
492 glyph_size += instruction_size + 2;
494 } else if (n_contours > 0) {
495 // simple glyph
496 n_points_vec.clear();
497 points.clear();
498 unsigned int total_n_points = 0;
499 unsigned int n_points_contour;
500 for (unsigned int j = 0; j < n_contours; ++j) {
501 if (!Read255UShort(&n_points_stream, &n_points_contour)) {
502 return FONT_COMPRESSION_FAILURE();
504 n_points_vec.push_back(n_points_contour);
505 if (total_n_points + n_points_contour < total_n_points) {
506 return FONT_COMPRESSION_FAILURE();
508 total_n_points += n_points_contour;
510 unsigned int flag_size = total_n_points;
511 if (flag_size > flag_stream.length() - flag_stream.offset()) {
512 return FONT_COMPRESSION_FAILURE();
514 const uint8_t* flags_buf = flag_stream.buffer() + flag_stream.offset();
515 const uint8_t* triplet_buf = glyph_stream.buffer() +
516 glyph_stream.offset();
517 size_t triplet_size = glyph_stream.length() - glyph_stream.offset();
518 size_t triplet_bytes_consumed = 0;
519 if (!TripletDecode(flags_buf, triplet_buf, triplet_size, total_n_points,
520 &points, &triplet_bytes_consumed)) {
521 return FONT_COMPRESSION_FAILURE();
523 const uint32_t header_and_endpts_contours_size =
524 kEndPtsOfContoursOffset + 2 * n_contours;
525 if (glyf_dst_size < header_and_endpts_contours_size) {
526 return FONT_COMPRESSION_FAILURE();
528 Store16(glyf_dst, 0, n_contours);
529 ComputeBbox(points, glyf_dst);
530 size_t offset = kEndPtsOfContoursOffset;
531 int end_point = -1;
532 for (unsigned int contour_ix = 0; contour_ix < n_contours; ++contour_ix) {
533 end_point += n_points_vec[contour_ix];
534 if (end_point >= 65536) {
535 return FONT_COMPRESSION_FAILURE();
537 offset = Store16(glyf_dst, offset, end_point);
539 if (!flag_stream.Skip(flag_size)) {
540 return FONT_COMPRESSION_FAILURE();
542 if (!glyph_stream.Skip(triplet_bytes_consumed)) {
543 return FONT_COMPRESSION_FAILURE();
545 unsigned int instruction_size;
546 if (!Read255UShort(&glyph_stream, &instruction_size)) {
547 return FONT_COMPRESSION_FAILURE();
549 if (glyf_dst_size - header_and_endpts_contours_size <
550 instruction_size + 2) {
551 return FONT_COMPRESSION_FAILURE();
553 uint8_t* instruction_dst = glyf_dst + header_and_endpts_contours_size;
554 Store16(instruction_dst, 0, instruction_size);
555 if (!instruction_stream.Read(instruction_dst + 2, instruction_size)) {
556 return FONT_COMPRESSION_FAILURE();
558 if (!StorePoints(points, n_contours, instruction_size,
559 glyf_dst, glyf_dst_size, &glyph_size)) {
560 return FONT_COMPRESSION_FAILURE();
562 } else {
563 glyph_size = 0;
565 loca_values[i] = loca_offset;
566 if (glyph_size + 3 < glyph_size) {
567 return FONT_COMPRESSION_FAILURE();
569 glyph_size = Round4(glyph_size);
570 if (glyph_size > dst_size - loca_offset) {
571 // This shouldn't happen, but this test defensively maintains the
572 // invariant that loca_offset <= dst_size.
573 return FONT_COMPRESSION_FAILURE();
575 loca_offset += glyph_size;
577 loca_values[num_glyphs] = loca_offset;
578 if (!ProcessBboxStream(&bbox_stream, num_glyphs, loca_values,
579 dst, dst_size)) {
580 return FONT_COMPRESSION_FAILURE();
582 return StoreLoca(loca_values, index_format, loca_buf, loca_size);
585 // This is linear search, but could be changed to binary because we
586 // do have a guarantee that the tables are sorted by tag. But the total
587 // cpu time is expected to be very small in any case.
588 const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) {
589 size_t n_tables = tables.size();
590 for (size_t i = 0; i < n_tables; ++i) {
591 if (tables[i].tag == tag) {
592 return &tables[i];
595 return NULL;
598 bool ReconstructTransformed(const std::vector<Table>& tables, uint32_t tag,
599 const uint8_t* transformed_buf, size_t transformed_size,
600 uint8_t* dst, size_t dst_length) {
601 if (tag == kGlyfTableTag) {
602 const Table* glyf_table = FindTable(tables, tag);
603 const Table* loca_table = FindTable(tables, kLocaTableTag);
604 if (glyf_table == NULL || loca_table == NULL) {
605 return FONT_COMPRESSION_FAILURE();
607 if (static_cast<uint64_t>(glyf_table->dst_offset + glyf_table->dst_length) >
608 dst_length) {
609 return FONT_COMPRESSION_FAILURE();
611 if (static_cast<uint64_t>(loca_table->dst_offset + loca_table->dst_length) >
612 dst_length) {
613 return FONT_COMPRESSION_FAILURE();
615 return ReconstructGlyf(transformed_buf, transformed_size,
616 dst + glyf_table->dst_offset, glyf_table->dst_length,
617 dst + loca_table->dst_offset, loca_table->dst_length);
618 } else if (tag == kLocaTableTag) {
619 // processing was already done by glyf table, but validate
620 if (!FindTable(tables, kGlyfTableTag)) {
621 return FONT_COMPRESSION_FAILURE();
623 } else {
624 // transform for the tag is not known
625 return FONT_COMPRESSION_FAILURE();
627 return true;
630 uint32_t ComputeChecksum(const uint8_t* buf, size_t size) {
631 uint32_t checksum = 0;
632 for (size_t i = 0; i < size; i += 4) {
633 // We assume the addition is mod 2^32, which is valid because unsigned
634 checksum += (buf[i] << 24) | (buf[i + 1] << 16) |
635 (buf[i + 2] << 8) | buf[i + 3];
637 return checksum;
640 bool FixChecksums(const std::vector<Table>& tables, uint8_t* dst) {
641 const Table* head_table = FindTable(tables, kHeadTableTag);
642 if (head_table == NULL ||
643 head_table->dst_length < kCheckSumAdjustmentOffset + 4) {
644 return FONT_COMPRESSION_FAILURE();
646 size_t adjustment_offset = head_table->dst_offset + kCheckSumAdjustmentOffset;
647 StoreU32(dst, adjustment_offset, 0);
648 size_t n_tables = tables.size();
649 uint32_t file_checksum = 0;
650 for (size_t i = 0; i < n_tables; ++i) {
651 const Table* table = &tables[i];
652 size_t table_length = table->dst_length;
653 uint8_t* table_data = dst + table->dst_offset;
654 uint32_t checksum = ComputeChecksum(table_data, table_length);
655 StoreU32(dst, kSfntHeaderSize + i * kSfntEntrySize + 4, checksum);
656 file_checksum += checksum;
658 file_checksum += ComputeChecksum(dst,
659 kSfntHeaderSize + kSfntEntrySize * n_tables);
660 uint32_t checksum_adjustment = 0xb1b0afba - file_checksum;
661 StoreU32(dst, adjustment_offset, checksum_adjustment);
662 return true;
665 bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size,
666 const uint8_t* src_buf, size_t src_size) {
667 size_t uncompressed_size = dst_size;
668 int ok = BrotliDecompressBuffer(src_size, src_buf,
669 &uncompressed_size, dst_buf);
670 if (!ok || uncompressed_size != dst_size) {
671 return FONT_COMPRESSION_FAILURE();
673 return true;
676 bool ReadShortDirectory(Buffer* file, std::vector<Table>* tables,
677 size_t num_tables) {
678 for (size_t i = 0; i < num_tables; ++i) {
679 Table* table = &(*tables)[i];
680 uint8_t flag_byte;
681 if (!file->ReadU8(&flag_byte)) {
682 return FONT_COMPRESSION_FAILURE();
684 uint32_t tag;
685 if ((flag_byte & 0x3f) == 0x3f) {
686 if (!file->ReadU32(&tag)) {
687 return FONT_COMPRESSION_FAILURE();
689 } else {
690 tag = kKnownTags[flag_byte & 0x3f];
692 // Bits 6 and 7 are reserved and must be 0.
693 if ((flag_byte & 0xC0) != 0) {
694 return FONT_COMPRESSION_FAILURE();
696 uint32_t flags = 0;
697 if (i > 0) {
698 flags |= kWoff2FlagsContinueStream;
700 // Always transform the glyf and loca tables
701 if (tag == kGlyfTableTag || tag == kLocaTableTag) {
702 flags |= kWoff2FlagsTransform;
704 uint32_t dst_length;
705 if (!ReadBase128(file, &dst_length)) {
706 return FONT_COMPRESSION_FAILURE();
708 uint32_t transform_length = dst_length;
709 if ((flags & kWoff2FlagsTransform) != 0) {
710 if (!ReadBase128(file, &transform_length)) {
711 return FONT_COMPRESSION_FAILURE();
714 table->tag = tag;
715 table->flags = flags;
716 table->transform_length = transform_length;
717 table->dst_length = dst_length;
719 return true;
722 } // namespace
724 size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) {
725 Buffer file(data, length);
726 uint32_t total_length;
728 if (!file.Skip(16) ||
729 !file.ReadU32(&total_length)) {
730 return 0;
732 return total_length;
735 bool ConvertWOFF2ToTTF(uint8_t* result, size_t result_length,
736 const uint8_t* data, size_t length) {
737 Buffer file(data, length);
739 uint32_t signature;
740 uint32_t flavor;
741 if (!file.ReadU32(&signature) || signature != kWoff2Signature ||
742 !file.ReadU32(&flavor)) {
743 return FONT_COMPRESSION_FAILURE();
746 // TODO(user): Should call IsValidVersionTag() here.
748 uint32_t reported_length;
749 if (!file.ReadU32(&reported_length) || length != reported_length) {
750 return FONT_COMPRESSION_FAILURE();
752 uint16_t num_tables;
753 if (!file.ReadU16(&num_tables) || !num_tables) {
754 return FONT_COMPRESSION_FAILURE();
756 // We don't care about these fields of the header:
757 // uint16_t reserved
758 // uint32_t total_sfnt_size
759 if (!file.Skip(6)) {
760 return FONT_COMPRESSION_FAILURE();
762 uint32_t compressed_length;
763 if (!file.ReadU32(&compressed_length)) {
764 return FONT_COMPRESSION_FAILURE();
766 // We don't care about these fields of the header:
767 // uint16_t major_version, minor_version
768 // uint32_t meta_offset, meta_length, meta_orig_length
769 // uint32_t priv_offset, priv_length
770 if (!file.Skip(24)) {
771 return FONT_COMPRESSION_FAILURE();
773 std::vector<Table> tables(num_tables);
774 // Note: change below to ReadLongDirectory to enable long format.
775 if (!ReadShortDirectory(&file, &tables, num_tables)) {
776 return FONT_COMPRESSION_FAILURE();
778 uint64_t src_offset = file.offset();
779 uint64_t dst_offset = kSfntHeaderSize +
780 kSfntEntrySize * static_cast<uint64_t>(num_tables);
781 uint64_t uncompressed_sum = 0;
782 for (uint16_t i = 0; i < num_tables; ++i) {
783 Table* table = &tables[i];
784 table->src_offset = src_offset;
785 table->src_length = (i == 0 ? compressed_length : 0);
786 src_offset += table->src_length;
787 if (src_offset > std::numeric_limits<uint32_t>::max()) {
788 return FONT_COMPRESSION_FAILURE();
790 src_offset = Round4(src_offset); // TODO: reconsider
791 table->dst_offset = dst_offset;
792 dst_offset += table->dst_length;
793 if (dst_offset > std::numeric_limits<uint32_t>::max()) {
794 return FONT_COMPRESSION_FAILURE();
796 dst_offset = Round4(dst_offset);
798 uncompressed_sum += table->src_length;
799 if (uncompressed_sum > std::numeric_limits<uint32_t>::max()) {
800 return FONT_COMPRESSION_FAILURE();
803 // Enforce same 30M limit on uncompressed tables as OTS
804 if (uncompressed_sum > 30 * 1024 * 1024) {
805 return FONT_COMPRESSION_FAILURE();
807 if (src_offset > length || dst_offset > result_length) {
808 return FONT_COMPRESSION_FAILURE();
811 const uint32_t sfnt_header_and_table_directory_size = 12 + 16 * num_tables;
812 if (sfnt_header_and_table_directory_size > result_length) {
813 return FONT_COMPRESSION_FAILURE();
816 // Start building the font
817 size_t offset = 0;
818 offset = StoreU32(result, offset, flavor);
819 offset = Store16(result, offset, num_tables);
820 unsigned max_pow2 = 0;
821 while (1u << (max_pow2 + 1) <= num_tables) {
822 max_pow2++;
824 const uint16_t output_search_range = (1u << max_pow2) << 4;
825 offset = Store16(result, offset, output_search_range);
826 offset = Store16(result, offset, max_pow2);
827 offset = Store16(result, offset, (num_tables << 4) - output_search_range);
829 // sort tags in the table directory in ascending alphabetical order
830 std::vector<Table> sorted_tables(tables);
831 std::sort(sorted_tables.begin(), sorted_tables.end());
833 for (uint16_t i = 0; i < num_tables; ++i) {
834 const Table* table = &sorted_tables[i];
835 offset = StoreU32(result, offset, table->tag);
836 offset = StoreU32(result, offset, 0); // checksum, to fill in later
837 offset = StoreU32(result, offset, table->dst_offset);
838 offset = StoreU32(result, offset, table->dst_length);
840 std::vector<uint8_t> uncompressed_buf;
841 bool continue_valid = false;
842 const uint8_t* transform_buf = NULL;
843 for (uint16_t i = 0; i < num_tables; ++i) {
844 const Table* table = &tables[i];
845 uint32_t flags = table->flags;
846 const uint8_t* src_buf = data + table->src_offset;
847 size_t transform_length = table->transform_length;
848 if ((flags & kWoff2FlagsContinueStream) != 0) {
849 if (!continue_valid) {
850 return FONT_COMPRESSION_FAILURE();
852 } else if ((flags & kWoff2FlagsContinueStream) == 0) {
853 uint64_t total_size = transform_length;
854 for (uint16_t j = i + 1; j < num_tables; ++j) {
855 if ((tables[j].flags & kWoff2FlagsContinueStream) == 0) {
856 break;
858 total_size += tables[j].transform_length;
859 if (total_size > std::numeric_limits<uint32_t>::max()) {
860 return FONT_COMPRESSION_FAILURE();
863 uncompressed_buf.resize(total_size);
864 if (!Woff2Uncompress(&uncompressed_buf[0], total_size,
865 src_buf, compressed_length)) {
866 return FONT_COMPRESSION_FAILURE();
868 transform_buf = &uncompressed_buf[0];
869 continue_valid = true;
870 } else {
871 return FONT_COMPRESSION_FAILURE();
874 if ((flags & kWoff2FlagsTransform) == 0) {
875 if (transform_length != table->dst_length) {
876 return FONT_COMPRESSION_FAILURE();
878 if (static_cast<uint64_t>(table->dst_offset + transform_length) >
879 result_length) {
880 return FONT_COMPRESSION_FAILURE();
882 std::memcpy(result + table->dst_offset, transform_buf,
883 transform_length);
884 } else {
885 if (!ReconstructTransformed(tables, table->tag,
886 transform_buf, transform_length, result, result_length)) {
887 return FONT_COMPRESSION_FAILURE();
890 if (continue_valid) {
891 transform_buf += transform_length;
892 if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) {
893 return FONT_COMPRESSION_FAILURE();
898 return FixChecksums(sorted_tables, result);
901 } // namespace woff2