blob: bb3a27a4f799ee090d56943e01c0159631b2e125 [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// Library for preprocessing fonts as part of the WOFF 2.0 conversion.
16
17#include "./transform.h"
18
19#include <complex> // for std::abs
20
Kenichi Ishibashi142d8882014-05-30 09:06:32 +090021#include "./buffer.h"
Roderick Sheeter437bbad2013-11-19 14:32:56 -080022#include "./font.h"
23#include "./glyph.h"
Kenichi Ishibashi142d8882014-05-30 09:06:32 +090024#include "./table_tags.h"
Roderick Sheeter437bbad2013-11-19 14:32:56 -080025
26namespace woff2 {
27
28namespace {
29
30const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
31const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
32
33void WriteBytes(std::vector<uint8_t>* out, const uint8_t* data, size_t len) {
34 if (len == 0) return;
35 size_t offset = out->size();
36 out->resize(offset + len);
37 memcpy(&(*out)[offset], data, len);
38}
39
40void WriteBytes(std::vector<uint8_t>* out, const std::vector<uint8_t>& in) {
41 for (int i = 0; i < in.size(); ++i) {
42 out->push_back(in[i]);
43 }
44}
45
46void WriteUShort(std::vector<uint8_t>* out, int value) {
47 out->push_back(value >> 8);
48 out->push_back(value & 255);
49}
50
51void WriteLong(std::vector<uint8_t>* out, int value) {
52 out->push_back((value >> 24) & 255);
53 out->push_back((value >> 16) & 255);
54 out->push_back((value >> 8) & 255);
55 out->push_back(value & 255);
56}
57
58void Write255UShort(std::vector<uint8_t>* out, int value) {
59 if (value < 253) {
60 out->push_back(value);
61 } else if (value < 506) {
62 out->push_back(255);
63 out->push_back(value - 253);
64 } else if (value < 762) {
65 out->push_back(254);
66 out->push_back(value - 506);
67 } else {
68 out->push_back(253);
69 out->push_back(value >> 8);
70 out->push_back(value & 0xff);
71 }
72}
73
74// Glyf table preprocessing, based on
75// GlyfEncoder.java
76// but only the "sbbox" and "cbbox" options are supported.
77class GlyfEncoder {
78 public:
79 explicit GlyfEncoder(int num_glyphs)
80 : sbbox_(false), cbbox_(true), n_glyphs_(num_glyphs) {
81 bbox_bitmap_.resize(((num_glyphs + 31) >> 5) << 2);
82 }
83
84 bool Encode(int glyph_id, const Glyph& glyph) {
85 if (glyph.composite_data_size > 0) {
86 WriteCompositeGlyph(glyph_id, glyph);
87 } else if (glyph.contours.size() > 0) {
88 WriteSimpleGlyph(glyph_id, glyph);
89 } else {
90 WriteUShort(&n_contour_stream_, 0);
91 }
92 return true;
93 }
94
95 void GetTransformedGlyfBytes(std::vector<uint8_t>* result) {
96 WriteLong(result, 0); // version
97 WriteUShort(result, n_glyphs_);
98 WriteUShort(result, 0); // index_format, will be set later
99 WriteLong(result, n_contour_stream_.size());
100 WriteLong(result, n_points_stream_.size());
101 WriteLong(result, flag_byte_stream_.size());
102 WriteLong(result, glyph_stream_.size());
103 WriteLong(result, composite_stream_.size());
104 WriteLong(result, bbox_bitmap_.size() + bbox_stream_.size());
105 WriteLong(result, instruction_stream_.size());
106 WriteBytes(result, n_contour_stream_);
107 WriteBytes(result, n_points_stream_);
108 WriteBytes(result, flag_byte_stream_);
109 WriteBytes(result, glyph_stream_);
110 WriteBytes(result, composite_stream_);
111 WriteBytes(result, bbox_bitmap_);
112 WriteBytes(result, bbox_stream_);
113 WriteBytes(result, instruction_stream_);
114 }
115
116 private:
117 void WriteInstructions(const Glyph& glyph) {
118 Write255UShort(&glyph_stream_, glyph.instructions_size);
119 WriteBytes(&instruction_stream_,
120 glyph.instructions_data, glyph.instructions_size);
121 }
122
123 void WriteSimpleGlyph(int glyph_id, const Glyph& glyph) {
124 int num_contours = glyph.contours.size();
125 WriteUShort(&n_contour_stream_, num_contours);
126 if (sbbox_) {
127 WriteBbox(glyph_id, glyph);
128 }
129 // TODO: check that bbox matches, write bbox if not
130 for (int i = 0; i < num_contours; i++) {
131 Write255UShort(&n_points_stream_, glyph.contours[i].size());
132 }
133 int lastX = 0;
134 int lastY = 0;
135 for (int i = 0; i < num_contours; i++) {
136 int num_points = glyph.contours[i].size();
137 for (int j = 0; j < num_points; j++) {
138 int x = glyph.contours[i][j].x;
139 int y = glyph.contours[i][j].y;
140 int dx = x - lastX;
141 int dy = y - lastY;
142 WriteTriplet(glyph.contours[i][j].on_curve, dx, dy);
143 lastX = x;
144 lastY = y;
145 }
146 }
147 if (num_contours > 0) {
148 WriteInstructions(glyph);
149 }
150 }
151
152 void WriteCompositeGlyph(int glyph_id, const Glyph& glyph) {
153 WriteUShort(&n_contour_stream_, -1);
154 if (cbbox_) {
155 WriteBbox(glyph_id, glyph);
156 }
157 WriteBytes(&composite_stream_,
158 glyph.composite_data,
159 glyph.composite_data_size);
160 if (glyph.have_instructions) {
161 WriteInstructions(glyph);
162 }
163 }
164
165 void WriteBbox(int glyph_id, const Glyph& glyph) {
166 bbox_bitmap_[glyph_id >> 3] |= 0x80 >> (glyph_id & 7);
167 WriteUShort(&bbox_stream_, glyph.x_min);
168 WriteUShort(&bbox_stream_, glyph.y_min);
169 WriteUShort(&bbox_stream_, glyph.x_max);
170 WriteUShort(&bbox_stream_, glyph.y_max);
171 }
172
173 void WriteTriplet(bool on_curve, int x, int y) {
174 int abs_x = std::abs(x);
175 int abs_y = std::abs(y);
176 int on_curve_bit = on_curve ? 0 : 128;
177 int x_sign_bit = (x < 0) ? 0 : 1;
178 int y_sign_bit = (y < 0) ? 0 : 1;
179 int xy_sign_bits = x_sign_bit + 2 * y_sign_bit;
180 if (x == 0 && abs_y < 1280) {
181 flag_byte_stream_.push_back(on_curve_bit +
182 ((abs_y & 0xf00) >> 7) + y_sign_bit);
183 glyph_stream_.push_back(abs_y & 0xff);
184 } else if (y == 0 && abs_x < 1280) {
185 flag_byte_stream_.push_back(on_curve_bit + 10 +
186 ((abs_x & 0xf00) >> 7) + x_sign_bit);
187 glyph_stream_.push_back(abs_x & 0xff);
188 } else if (abs_x < 65 && abs_y < 65) {
189 flag_byte_stream_.push_back(on_curve_bit + 20 +
190 ((abs_x - 1) & 0x30) +
191 (((abs_y - 1) & 0x30) >> 2) +
192 xy_sign_bits);
193 glyph_stream_.push_back((((abs_x - 1) & 0xf) << 4) | ((abs_y - 1) & 0xf));
194 } else if (abs_x < 769 && abs_y < 769) {
195 flag_byte_stream_.push_back(on_curve_bit + 84 +
196 12 * (((abs_x - 1) & 0x300) >> 8) +
197 (((abs_y - 1) & 0x300) >> 6) + xy_sign_bits);
198 glyph_stream_.push_back((abs_x - 1) & 0xff);
199 glyph_stream_.push_back((abs_y - 1) & 0xff);
200 } else if (abs_x < 4096 && abs_y < 4096) {
201 flag_byte_stream_.push_back(on_curve_bit + 120 + xy_sign_bits);
202 glyph_stream_.push_back(abs_x >> 4);
203 glyph_stream_.push_back(((abs_x & 0xf) << 4) | (abs_y >> 8));
204 glyph_stream_.push_back(abs_y & 0xff);
205 } else {
206 flag_byte_stream_.push_back(on_curve_bit + 124 + xy_sign_bits);
207 glyph_stream_.push_back(abs_x >> 8);
208 glyph_stream_.push_back(abs_x & 0xff);
209 glyph_stream_.push_back(abs_y >> 8);
210 glyph_stream_.push_back(abs_y & 0xff);
211 }
212 }
213
214 std::vector<uint8_t> n_contour_stream_;
215 std::vector<uint8_t> n_points_stream_;
216 std::vector<uint8_t> flag_byte_stream_;
217 std::vector<uint8_t> composite_stream_;
218 std::vector<uint8_t> bbox_bitmap_;
219 std::vector<uint8_t> bbox_stream_;
220 std::vector<uint8_t> glyph_stream_;
221 std::vector<uint8_t> instruction_stream_;
222 bool sbbox_;
223 bool cbbox_;
224 int n_glyphs_;
225};
226
227} // namespace
228
229bool TransformGlyfAndLocaTables(Font* font) {
230 Font::Table* transformed_glyf = &font->tables[kGlyfTableTag ^ 0x80808080];
231 Font::Table* transformed_loca = &font->tables[kLocaTableTag ^ 0x80808080];
232
233 int num_glyphs = NumGlyphs(*font);
234 GlyfEncoder encoder(num_glyphs);
235 for (int i = 0; i < num_glyphs; ++i) {
236 Glyph glyph;
237 const uint8_t* glyph_data;
238 size_t glyph_size;
239 if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) ||
240 (glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900241 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800242 }
243 encoder.Encode(i, glyph);
244 }
245 encoder.GetTransformedGlyfBytes(&transformed_glyf->buffer);
246
247 const Font::Table* head_table = font->FindTable(kHeadTableTag);
248 if (head_table == NULL || head_table->length < 52) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900249 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800250 }
251 transformed_glyf->buffer[7] = head_table->data[51]; // index_format
252
253 transformed_glyf->tag = kGlyfTableTag ^ 0x80808080;
254 transformed_glyf->length = transformed_glyf->buffer.size();
255 transformed_glyf->data = transformed_glyf->buffer.data();
256
257 transformed_loca->tag = kLocaTableTag ^ 0x80808080;
258 transformed_loca->length = 0;
259 transformed_loca->data = NULL;
260
261 return true;
262}
263
264} // namespace woff2