Update mojo sdk to rev 1dc8a9a5db73d3718d99917fadf31f5fb2ebad4f
[chromium-blink-merge.git] / third_party / woff2 / src / transform.cc
blob44a47815408f7897bbefa79cd9a562f5f65252a7
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 // Library for preprocessing fonts as part of the WOFF 2.0 conversion.
17 #include "./transform.h"
19 #include <complex> // for std::abs
21 #include "./buffer.h"
22 #include "./font.h"
23 #include "./glyph.h"
24 #include "./table_tags.h"
26 namespace woff2 {
28 namespace {
30 const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
31 const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
33 void 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);
40 void 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]);
46 void WriteUShort(std::vector<uint8_t>* out, int value) {
47 out->push_back(value >> 8);
48 out->push_back(value & 255);
51 void 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);
58 void 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);
74 // Glyf table preprocessing, based on
75 // GlyfEncoder.java
76 // but only the "sbbox" and "cbbox" options are supported.
77 class 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);
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);
92 return true;
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_);
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);
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);
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());
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;
147 if (num_contours > 0) {
148 WriteInstructions(glyph);
152 void WriteCompositeGlyph(int glyph_id, const Glyph& glyph) {
153 WriteUShort(&n_contour_stream_, -1);
154 if (cbbox_) {
155 WriteBbox(glyph_id, glyph);
157 WriteBytes(&composite_stream_,
158 glyph.composite_data,
159 glyph.composite_data_size);
160 if (glyph.have_instructions) {
161 WriteInstructions(glyph);
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);
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);
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_;
227 } // namespace
229 bool TransformGlyfAndLocaTables(Font* font) {
230 // no transform for CFF
231 if (font->FindTable(kCffTableTag) != NULL
232 && font->FindTable(kGlyfTableTag) == NULL
233 && font->FindTable(kLocaTableTag) == NULL) {
234 return true;
236 Font::Table* transformed_glyf = &font->tables[kGlyfTableTag ^ 0x80808080];
237 Font::Table* transformed_loca = &font->tables[kLocaTableTag ^ 0x80808080];
239 int num_glyphs = NumGlyphs(*font);
240 GlyfEncoder encoder(num_glyphs);
241 for (int i = 0; i < num_glyphs; ++i) {
242 Glyph glyph;
243 const uint8_t* glyph_data;
244 size_t glyph_size;
245 if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) ||
246 (glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) {
247 return FONT_COMPRESSION_FAILURE();
249 encoder.Encode(i, glyph);
251 encoder.GetTransformedGlyfBytes(&transformed_glyf->buffer);
253 const Font::Table* head_table = font->FindTable(kHeadTableTag);
254 if (head_table == NULL || head_table->length < 52) {
255 return FONT_COMPRESSION_FAILURE();
257 transformed_glyf->buffer[7] = head_table->data[51]; // index_format
259 transformed_glyf->tag = kGlyfTableTag ^ 0x80808080;
260 transformed_glyf->length = transformed_glyf->buffer.size();
261 transformed_glyf->data = transformed_glyf->buffer.data();
263 transformed_loca->tag = kLocaTableTag ^ 0x80808080;
264 transformed_loca->length = 0;
265 transformed_loca->data = NULL;
267 return true;
270 } // namespace woff2