1 // Copyright 2013 Google Inc. All Rights Reserved.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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
24 #include "./table_tags.h"
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
) {
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
) {
60 out
->push_back(value
);
61 } else if (value
< 506) {
63 out
->push_back(value
- 253);
64 } else if (value
< 762) {
66 out
->push_back(value
- 506);
69 out
->push_back(value
>> 8);
70 out
->push_back(value
& 0xff);
74 // Glyf table preprocessing, based on
76 // but only the "sbbox" and "cbbox" options are supported.
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
);
90 WriteUShort(&n_contour_stream_
, 0);
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_
);
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
);
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());
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
;
142 WriteTriplet(glyph
.contours
[i
][j
].on_curve
, dx
, dy
);
147 if (num_contours
> 0) {
148 WriteInstructions(glyph
);
152 void WriteCompositeGlyph(int glyph_id
, const Glyph
& glyph
) {
153 WriteUShort(&n_contour_stream_
, -1);
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) +
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);
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_
;
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
) {
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
) {
243 const uint8_t* glyph_data
;
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
;