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