blob: 0812b00de640ae1f4711b70481f5bc629732a5c1 [file] [log] [blame]
Roderick Sheeter437bbad2013-11-19 14:32:56 -08001// Copyright 2013 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.
14//
15// Glyph normalization
16
17#include "./normalize.h"
18
19#include <inttypes.h>
20#include <stddef.h>
21
Kenichi Ishibashi142d8882014-05-30 09:06:32 +090022#include "./buffer.h"
Roderick Sheeter437bbad2013-11-19 14:32:56 -080023#include "./port.h"
24#include "./font.h"
25#include "./glyph.h"
26#include "./round.h"
27#include "./store_bytes.h"
Kenichi Ishibashi142d8882014-05-30 09:06:32 +090028#include "./table_tags.h"
Roderick Sheeter437bbad2013-11-19 14:32:56 -080029
30namespace woff2 {
31
32namespace {
33
34void StoreLoca(int index_fmt, uint32_t value, size_t* offset, uint8_t* dst) {
35 if (index_fmt == 0) {
36 Store16(value >> 1, offset, dst);
37 } else {
38 StoreU32(value, offset, dst);
39 }
40}
41
42void NormalizeSimpleGlyphBoundingBox(Glyph* glyph) {
43 if (glyph->contours.empty() || glyph->contours[0].empty()) {
44 return;
45 }
46 int16_t x_min = glyph->contours[0][0].x;
47 int16_t y_min = glyph->contours[0][0].y;
48 int16_t x_max = x_min;
49 int16_t y_max = y_min;
50 for (const auto& contour : glyph->contours) {
51 for (const auto& point : contour) {
52 if (point.x < x_min) x_min = point.x;
53 if (point.x > x_max) x_max = point.x;
54 if (point.y < y_min) y_min = point.y;
55 if (point.y > y_max) y_max = point.y;
56 }
57 }
58 glyph->x_min = x_min;
59 glyph->y_min = y_min;
60 glyph->x_max = x_max;
61 glyph->y_max = y_max;
62}
63
64} // namespace
65
66bool NormalizeGlyphs(Font* font) {
67 Font::Table* head_table = font->FindTable(kHeadTableTag);
68 Font::Table* glyf_table = font->FindTable(kGlyfTableTag);
69 Font::Table* loca_table = font->FindTable(kLocaTableTag);
70 if (head_table == NULL || loca_table == NULL || glyf_table == NULL) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +090071 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -080072 }
73 int index_fmt = head_table->data[51];
74 int num_glyphs = NumGlyphs(*font);
75
76 // We need to allocate a bit more than its original length for the normalized
77 // glyf table, since it can happen that the glyphs in the original table are
78 // 2-byte aligned, while in the normalized table they are 4-byte aligned.
79 // That gives a maximum of 2 bytes increase per glyph. However, there is no
80 // theoretical guarantee that the total size of the flags plus the coordinates
81 // is the smallest possible in the normalized version, so we have to allow
82 // some general overhead.
83 // TODO(user) Figure out some more precise upper bound on the size of
84 // the overhead.
85 size_t max_normalized_glyf_size = 1.1 * glyf_table->length + 2 * num_glyphs;
86
87 glyf_table->buffer.resize(max_normalized_glyf_size);
88 loca_table->buffer.resize(Round4(loca_table->length));
89 uint8_t* glyf_dst = &glyf_table->buffer[0];
90 uint8_t* loca_dst = &loca_table->buffer[0];
91 uint32_t glyf_offset = 0;
92 size_t loca_offset = 0;
93
94 for (int i = 0; i < num_glyphs; ++i) {
95 StoreLoca(index_fmt, glyf_offset, &loca_offset, loca_dst);
96 Glyph glyph;
97 const uint8_t* glyph_data;
98 size_t glyph_size;
99 if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) ||
100 (glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900101 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800102 }
103 NormalizeSimpleGlyphBoundingBox(&glyph);
104 size_t glyf_dst_size = glyf_table->buffer.size() - glyf_offset;
105 if (!StoreGlyph(glyph, glyf_dst + glyf_offset, &glyf_dst_size)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900106 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800107 }
108 glyf_dst_size = Round4(glyf_dst_size);
109 if (glyf_dst_size > std::numeric_limits<uint32_t>::max() ||
110 glyf_offset + static_cast<uint32_t>(glyf_dst_size) < glyf_offset ||
111 (index_fmt == 0 && glyf_offset + glyf_dst_size >= (1UL << 17))) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900112 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800113 }
114 glyf_offset += glyf_dst_size;
115 }
116 StoreLoca(index_fmt, glyf_offset, &loca_offset, loca_dst);
117
118 glyf_table->buffer.resize(glyf_offset);
119 glyf_table->data = &glyf_table->buffer[0];
120 glyf_table->length = glyf_offset;
121 loca_table->data = &loca_table->buffer[0];
122
123 return true;
124}
125
126bool NormalizeOffsets(Font* font) {
127 uint32_t offset = 12 + 16 * font->num_tables;
128 for (auto& i : font->tables) {
129 i.second.offset = offset;
130 offset += Round4(i.second.length);
131 }
132 return true;
133}
134
135namespace {
136
137uint32_t ComputeChecksum(const uint8_t* buf, size_t size) {
138 uint32_t checksum = 0;
139 for (size_t i = 0; i < size; i += 4) {
140 checksum += ((buf[i] << 24) |
141 (buf[i + 1] << 16) |
142 (buf[i + 2] << 8) |
143 buf[i + 3]);
144 }
145 return checksum;
146}
147
148uint32_t ComputeHeaderChecksum(const Font& font) {
149 uint32_t checksum = font.flavor;
150 uint16_t max_pow2 = font.num_tables ? Log2Floor(font.num_tables) : 0;
151 uint16_t search_range = max_pow2 ? 1 << (max_pow2 + 4) : 0;
152 uint16_t range_shift = (font.num_tables << 4) - search_range;
153 checksum += (font.num_tables << 16 | search_range);
154 checksum += (max_pow2 << 16 | range_shift);
155 for (const auto& i : font.tables) {
156 checksum += i.second.tag;
157 checksum += i.second.checksum;
158 checksum += i.second.offset;
159 checksum += i.second.length;
160 }
161 return checksum;
162}
163
164} // namespace
165
166bool FixChecksums(Font* font) {
167 Font::Table* head_table = font->FindTable(kHeadTableTag);
168 if (head_table == NULL || head_table->length < 12) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900169 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800170 }
171 head_table->buffer.resize(Round4(head_table->length));
172 uint8_t* head_buf = &head_table->buffer[0];
173 memcpy(head_buf, head_table->data, Round4(head_table->length));
174 head_table->data = head_buf;
175 size_t offset = 8;
176 StoreU32(0, &offset, head_buf);
177 uint32_t file_checksum = 0;
178 for (auto& i : font->tables) {
179 Font::Table* table = &i.second;
180 table->checksum = ComputeChecksum(table->data, table->length);
181 file_checksum += table->checksum;
182 }
183 file_checksum += ComputeHeaderChecksum(*font);
184 offset = 8;
185 StoreU32(0xb1b0afba - file_checksum, &offset, head_buf);
186 return true;
187}
188
189bool NormalizeFont(Font* font) {
Roderick Sheeter2ec0cb82014-05-07 11:01:07 -0700190 return (RemoveDigitalSignature(font) &&
191 NormalizeGlyphs(font) &&
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800192 NormalizeOffsets(font) &&
193 FixChecksums(font));
194}
195
196} // namespace woff2