Delete unused downloads page asset.
[chromium-blink-merge.git] / third_party / woff2 / src / normalize.cc
bloba816feb4ba628a5561d101f7c3cf8988155801eb
1 // 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.
15 // Glyph normalization
17 #include "./normalize.h"
19 #include <inttypes.h>
20 #include <stddef.h>
22 #include "./buffer.h"
23 #include "./port.h"
24 #include "./font.h"
25 #include "./glyph.h"
26 #include "./round.h"
27 #include "./store_bytes.h"
28 #include "./table_tags.h"
30 namespace woff2 {
32 namespace {
34 void 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);
42 void NormalizeSimpleGlyphBoundingBox(Glyph* glyph) {
43 if (glyph->contours.empty() || glyph->contours[0].empty()) {
44 return;
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;
58 glyph->x_min = x_min;
59 glyph->y_min = y_min;
60 glyph->x_max = x_max;
61 glyph->y_max = y_max;
64 } // namespace
66 namespace {
68 bool WriteNormalizedLoca(int index_fmt, int num_glyphs, Font* font) {
69 Font::Table* glyf_table = font->FindTable(kGlyfTableTag);
70 Font::Table* loca_table = font->FindTable(kLocaTableTag);
72 int glyph_sz = index_fmt == 0 ? 2 : 4;
73 loca_table->buffer.resize(Round4(num_glyphs + 1) * glyph_sz);
74 loca_table->length = (num_glyphs + 1) * glyph_sz;
76 uint8_t* glyf_dst = &glyf_table->buffer[0];
77 uint8_t* loca_dst = &loca_table->buffer[0];
78 uint32_t glyf_offset = 0;
79 size_t loca_offset = 0;
81 for (int i = 0; i < num_glyphs; ++i) {
82 StoreLoca(index_fmt, glyf_offset, &loca_offset, loca_dst);
83 Glyph glyph;
84 const uint8_t* glyph_data;
85 size_t glyph_size;
86 if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) ||
87 (glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) {
88 return FONT_COMPRESSION_FAILURE();
90 NormalizeSimpleGlyphBoundingBox(&glyph);
91 size_t glyf_dst_size = glyf_table->buffer.size() - glyf_offset;
92 if (!StoreGlyph(glyph, glyf_dst + glyf_offset, &glyf_dst_size)) {
93 return FONT_COMPRESSION_FAILURE();
95 glyf_dst_size = Round4(glyf_dst_size);
96 if (glyf_dst_size > std::numeric_limits<uint32_t>::max() ||
97 glyf_offset + static_cast<uint32_t>(glyf_dst_size) < glyf_offset ||
98 (index_fmt == 0 && glyf_offset + glyf_dst_size >= (1UL << 17))) {
99 return FONT_COMPRESSION_FAILURE();
101 glyf_offset += glyf_dst_size;
103 if (glyf_offset == 0) {
104 return false;
107 StoreLoca(index_fmt, glyf_offset, &loca_offset, loca_dst);
109 glyf_table->buffer.resize(glyf_offset);
110 glyf_table->data = &glyf_table->buffer[0];
111 glyf_table->length = glyf_offset;
112 loca_table->data = &loca_table->buffer[0];
114 return true;
117 } // namespace
119 namespace {
121 bool MakeEditableBuffer(Font* font, int tableTag) {
122 Font::Table* table = font->FindTable(tableTag);
123 if (table == NULL) {
124 return FONT_COMPRESSION_FAILURE();
126 int sz = Round4(table->length);
127 table->buffer.resize(sz);
128 uint8_t* buf = &table->buffer[0];
129 memcpy(buf, table->data, sz);
130 table->data = buf;
131 return true;
134 } // namespace
136 bool NormalizeGlyphs(Font* font) {
137 Font::Table* cff_table = font->FindTable(kCffTableTag);
138 Font::Table* head_table = font->FindTable(kHeadTableTag);
139 Font::Table* glyf_table = font->FindTable(kGlyfTableTag);
140 Font::Table* loca_table = font->FindTable(kLocaTableTag);
141 if (head_table == NULL) {
142 return FONT_COMPRESSION_FAILURE();
144 // CFF, no loca, no glyf is OK for CFF. If so, don't normalize.
145 if (cff_table != NULL && loca_table == NULL && glyf_table == NULL) {
146 return true;
148 if (loca_table == NULL || glyf_table == NULL) {
149 return FONT_COMPRESSION_FAILURE();
151 int index_fmt = head_table->data[51];
152 int num_glyphs = NumGlyphs(*font);
154 // We need to allocate a bit more than its original length for the normalized
155 // glyf table, since it can happen that the glyphs in the original table are
156 // 2-byte aligned, while in the normalized table they are 4-byte aligned.
157 // That gives a maximum of 2 bytes increase per glyph. However, there is no
158 // theoretical guarantee that the total size of the flags plus the coordinates
159 // is the smallest possible in the normalized version, so we have to allow
160 // some general overhead.
161 // TODO(user) Figure out some more precise upper bound on the size of
162 // the overhead.
163 size_t max_normalized_glyf_size = 1.1 * glyf_table->length + 2 * num_glyphs;
165 glyf_table->buffer.resize(max_normalized_glyf_size);
167 // if we can't write a loca using short's (index_fmt 0)
168 // try again using longs (index_fmt 1)
169 if (!WriteNormalizedLoca(index_fmt, num_glyphs, font)) {
170 if (index_fmt != 0) {
171 return FONT_COMPRESSION_FAILURE();
174 // Rewrite loca with 4-byte entries & update head to match
175 index_fmt = 1;
176 if (!WriteNormalizedLoca(index_fmt, num_glyphs, font)) {
177 return FONT_COMPRESSION_FAILURE();
179 head_table->buffer[51] = 1;
182 return true;
185 bool NormalizeOffsets(Font* font) {
186 uint32_t offset = 12 + 16 * font->num_tables;
187 for (auto& i : font->tables) {
188 i.second.offset = offset;
189 offset += Round4(i.second.length);
191 return true;
194 namespace {
196 uint32_t ComputeChecksum(const uint8_t* buf, size_t size) {
197 uint32_t checksum = 0;
198 for (size_t i = 0; i < size; i += 4) {
199 checksum += ((buf[i] << 24) |
200 (buf[i + 1] << 16) |
201 (buf[i + 2] << 8) |
202 buf[i + 3]);
204 return checksum;
207 uint32_t ComputeHeaderChecksum(const Font& font) {
208 uint32_t checksum = font.flavor;
209 uint16_t max_pow2 = font.num_tables ? Log2Floor(font.num_tables) : 0;
210 uint16_t search_range = max_pow2 ? 1 << (max_pow2 + 4) : 0;
211 uint16_t range_shift = (font.num_tables << 4) - search_range;
212 checksum += (font.num_tables << 16 | search_range);
213 checksum += (max_pow2 << 16 | range_shift);
214 for (const auto& i : font.tables) {
215 checksum += i.second.tag;
216 checksum += i.second.checksum;
217 checksum += i.second.offset;
218 checksum += i.second.length;
220 return checksum;
223 } // namespace
225 bool FixChecksums(Font* font) {
226 Font::Table* head_table = font->FindTable(kHeadTableTag);
227 if (head_table == NULL || head_table->length < 12) {
228 return FONT_COMPRESSION_FAILURE();
230 uint8_t* head_buf = &head_table->buffer[0];
231 size_t offset = 8;
232 StoreU32(0, &offset, head_buf);
233 uint32_t file_checksum = 0;
234 for (auto& i : font->tables) {
235 Font::Table* table = &i.second;
236 table->checksum = ComputeChecksum(table->data, table->length);
237 file_checksum += table->checksum;
239 file_checksum += ComputeHeaderChecksum(*font);
240 offset = 8;
241 StoreU32(0xb1b0afba - file_checksum, &offset, head_buf);
242 return true;
245 bool NormalizeFont(Font* font) {
246 return (MakeEditableBuffer(font, kHeadTableTag) &&
247 RemoveDigitalSignature(font) &&
248 NormalizeGlyphs(font) &&
249 NormalizeOffsets(font) &&
250 FixChecksums(font));
253 } // namespace woff2