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.
22 #include "./store_bytes.h"
26 static const int32_t kFLAG_ONCURVE
= 1;
27 static const int32_t kFLAG_XSHORT
= 1 << 1;
28 static const int32_t kFLAG_YSHORT
= 1 << 2;
29 static const int32_t kFLAG_REPEAT
= 1 << 3;
30 static const int32_t kFLAG_XREPEATSIGN
= 1 << 4;
31 static const int32_t kFLAG_YREPEATSIGN
= 1 << 5;
32 static const int32_t kFLAG_ARG_1_AND_2_ARE_WORDS
= 1 << 0;
33 static const int32_t kFLAG_WE_HAVE_A_SCALE
= 1 << 3;
34 static const int32_t kFLAG_MORE_COMPONENTS
= 1 << 5;
35 static const int32_t kFLAG_WE_HAVE_AN_X_AND_Y_SCALE
= 1 << 6;
36 static const int32_t kFLAG_WE_HAVE_A_TWO_BY_TWO
= 1 << 7;
37 static const int32_t kFLAG_WE_HAVE_INSTRUCTIONS
= 1 << 8;
39 bool ReadCompositeGlyphData(Buffer
* buffer
, Glyph
* glyph
) {
40 glyph
->have_instructions
= false;
41 glyph
->composite_data
= buffer
->buffer() + buffer
->offset();
42 size_t start_offset
= buffer
->offset();
43 uint16_t flags
= kFLAG_MORE_COMPONENTS
;
44 while (flags
& kFLAG_MORE_COMPONENTS
) {
45 if (!buffer
->ReadU16(&flags
)) {
46 return FONT_COMPRESSION_FAILURE();
48 glyph
->have_instructions
|= (flags
& kFLAG_WE_HAVE_INSTRUCTIONS
) != 0;
49 size_t arg_size
= 2; // glyph index
50 if (flags
& kFLAG_ARG_1_AND_2_ARE_WORDS
) {
55 if (flags
& kFLAG_WE_HAVE_A_SCALE
) {
57 } else if (flags
& kFLAG_WE_HAVE_AN_X_AND_Y_SCALE
) {
59 } else if (flags
& kFLAG_WE_HAVE_A_TWO_BY_TWO
) {
62 if (!buffer
->Skip(arg_size
)) {
63 return FONT_COMPRESSION_FAILURE();
66 if (buffer
->offset() - start_offset
> std::numeric_limits
<uint32_t>::max()) {
67 return FONT_COMPRESSION_FAILURE();
69 glyph
->composite_data_size
= buffer
->offset() - start_offset
;
73 bool ReadGlyph(const uint8_t* data
, size_t len
, Glyph
* glyph
) {
74 Buffer
buffer(data
, len
);
77 if (!buffer
.ReadS16(&num_contours
)) {
78 return FONT_COMPRESSION_FAILURE();
81 if (num_contours
== 0) {
86 // Read the bounding box.
87 if (!buffer
.ReadS16(&glyph
->x_min
) ||
88 !buffer
.ReadS16(&glyph
->y_min
) ||
89 !buffer
.ReadS16(&glyph
->x_max
) ||
90 !buffer
.ReadS16(&glyph
->y_max
)) {
91 return FONT_COMPRESSION_FAILURE();
94 if (num_contours
> 0) {
96 glyph
->contours
.resize(num_contours
);
98 // Read the number of points per contour.
99 uint16_t last_point_index
= 0;
100 for (int i
= 0; i
< num_contours
; ++i
) {
101 uint16_t point_index
;
102 if (!buffer
.ReadU16(&point_index
)) {
103 return FONT_COMPRESSION_FAILURE();
105 uint16_t num_points
= point_index
- last_point_index
+ (i
== 0 ? 1 : 0);
106 glyph
->contours
[i
].resize(num_points
);
107 last_point_index
= point_index
;
110 // Read the instructions.
111 if (!buffer
.ReadU16(&glyph
->instructions_size
)) {
112 return FONT_COMPRESSION_FAILURE();
114 glyph
->instructions_data
= data
+ buffer
.offset();
115 if (!buffer
.Skip(glyph
->instructions_size
)) {
116 return FONT_COMPRESSION_FAILURE();
119 // Read the run-length coded flags.
120 std::vector
<std::vector
<uint8_t> > flags(num_contours
);
122 uint8_t flag_repeat
= 0;
123 for (int i
= 0; i
< num_contours
; ++i
) {
124 flags
[i
].resize(glyph
->contours
[i
].size());
125 for (int j
= 0; j
< glyph
->contours
[i
].size(); ++j
) {
126 if (flag_repeat
== 0) {
127 if (!buffer
.ReadU8(&flag
)) {
128 return FONT_COMPRESSION_FAILURE();
130 if (flag
& kFLAG_REPEAT
) {
131 if (!buffer
.ReadU8(&flag_repeat
)) {
132 return FONT_COMPRESSION_FAILURE();
139 glyph
->contours
[i
][j
].on_curve
= flag
& kFLAG_ONCURVE
;
143 // Read the x coordinates.
145 for (int i
= 0; i
< num_contours
; ++i
) {
146 for (int j
= 0; j
< glyph
->contours
[i
].size(); ++j
) {
147 uint8_t flag
= flags
[i
][j
];
148 if (flag
& kFLAG_XSHORT
) {
149 // single byte x-delta coord value
151 if (!buffer
.ReadU8(&x_delta
)) {
152 return FONT_COMPRESSION_FAILURE();
154 int sign
= (flag
& kFLAG_XREPEATSIGN
) ? 1 : -1;
155 glyph
->contours
[i
][j
].x
= prev_x
+ sign
* x_delta
;
157 // double byte x-delta coord value
159 if (!(flag
& kFLAG_XREPEATSIGN
)) {
160 if (!buffer
.ReadS16(&x_delta
)) {
161 return FONT_COMPRESSION_FAILURE();
164 glyph
->contours
[i
][j
].x
= prev_x
+ x_delta
;
166 prev_x
= glyph
->contours
[i
][j
].x
;
170 // Read the y coordinates.
172 for (int i
= 0; i
< num_contours
; ++i
) {
173 for (int j
= 0; j
< glyph
->contours
[i
].size(); ++j
) {
174 uint8_t flag
= flags
[i
][j
];
175 if (flag
& kFLAG_YSHORT
) {
176 // single byte y-delta coord value
178 if (!buffer
.ReadU8(&y_delta
)) {
179 return FONT_COMPRESSION_FAILURE();
181 int sign
= (flag
& kFLAG_YREPEATSIGN
) ? 1 : -1;
182 glyph
->contours
[i
][j
].y
= prev_y
+ sign
* y_delta
;
184 // double byte y-delta coord value
186 if (!(flag
& kFLAG_YREPEATSIGN
)) {
187 if (!buffer
.ReadS16(&y_delta
)) {
188 return FONT_COMPRESSION_FAILURE();
191 glyph
->contours
[i
][j
].y
= prev_y
+ y_delta
;
193 prev_y
= glyph
->contours
[i
][j
].y
;
196 } else if (num_contours
== -1) {
198 if (!ReadCompositeGlyphData(&buffer
, glyph
)) {
199 return FONT_COMPRESSION_FAILURE();
201 // Read the instructions.
202 if (glyph
->have_instructions
) {
203 if (!buffer
.ReadU16(&glyph
->instructions_size
)) {
204 return FONT_COMPRESSION_FAILURE();
206 glyph
->instructions_data
= data
+ buffer
.offset();
207 if (!buffer
.Skip(glyph
->instructions_size
)) {
208 return FONT_COMPRESSION_FAILURE();
211 glyph
->instructions_size
= 0;
214 return FONT_COMPRESSION_FAILURE();
221 void StoreBbox(const Glyph
& glyph
, size_t* offset
, uint8_t* dst
) {
222 Store16(glyph
.x_min
, offset
, dst
);
223 Store16(glyph
.y_min
, offset
, dst
);
224 Store16(glyph
.x_max
, offset
, dst
);
225 Store16(glyph
.y_max
, offset
, dst
);
228 void StoreInstructions(const Glyph
& glyph
, size_t* offset
, uint8_t* dst
) {
229 Store16(glyph
.instructions_size
, offset
, dst
);
230 StoreBytes(glyph
.instructions_data
, glyph
.instructions_size
, offset
, dst
);
233 bool StoreEndPtsOfContours(const Glyph
& glyph
, size_t* offset
, uint8_t* dst
) {
235 for (const auto& contour
: glyph
.contours
) {
236 end_point
+= contour
.size();
237 if (contour
.size() > std::numeric_limits
<uint16_t>::max() ||
238 end_point
> std::numeric_limits
<uint16_t>::max()) {
239 return FONT_COMPRESSION_FAILURE();
241 Store16(end_point
, offset
, dst
);
246 bool StorePoints(const Glyph
& glyph
, size_t* offset
,
247 uint8_t* dst
, size_t dst_size
) {
249 int repeat_count
= 0;
255 // Store the flags and calculate the total size of the x and y coordinates.
256 for (const auto& contour
: glyph
.contours
) {
257 for (const auto& point
: contour
) {
258 int flag
= point
.on_curve
? kFLAG_ONCURVE
: 0;
259 int dx
= point
.x
- last_x
;
260 int dy
= point
.y
- last_y
;
262 flag
|= kFLAG_XREPEATSIGN
;
263 } else if (dx
> -256 && dx
< 256) {
264 flag
|= kFLAG_XSHORT
| (dx
> 0 ? kFLAG_XREPEATSIGN
: 0);
270 flag
|= kFLAG_YREPEATSIGN
;
271 } else if (dy
> -256 && dy
< 256) {
272 flag
|= kFLAG_YSHORT
| (dy
> 0 ? kFLAG_YREPEATSIGN
: 0);
277 if (flag
== last_flag
&& repeat_count
!= 255) {
278 dst
[*offset
- 1] |= kFLAG_REPEAT
;
281 if (repeat_count
!= 0) {
282 if (*offset
>= dst_size
) {
283 return FONT_COMPRESSION_FAILURE();
285 dst
[(*offset
)++] = repeat_count
;
287 if (*offset
>= dst_size
) {
288 return FONT_COMPRESSION_FAILURE();
290 dst
[(*offset
)++] = flag
;
298 if (repeat_count
!= 0) {
299 if (*offset
>= dst_size
) {
300 return FONT_COMPRESSION_FAILURE();
302 dst
[(*offset
)++] = repeat_count
;
305 if (*offset
+ x_bytes
+ y_bytes
> dst_size
) {
306 return FONT_COMPRESSION_FAILURE();
309 // Store the x and y coordinates.
310 size_t x_offset
= *offset
;
311 size_t y_offset
= *offset
+ x_bytes
;
314 for (const auto& contour
: glyph
.contours
) {
315 for (const auto& point
: contour
) {
316 int dx
= point
.x
- last_x
;
317 int dy
= point
.y
- last_y
;
320 } else if (dx
> -256 && dx
< 256) {
321 dst
[x_offset
++] = std::abs(dx
);
323 Store16(dx
, &x_offset
, dst
);
327 } else if (dy
> -256 && dy
< 256) {
328 dst
[y_offset
++] = std::abs(dy
);
330 Store16(dy
, &y_offset
, dst
);
342 bool StoreGlyph(const Glyph
& glyph
, uint8_t* dst
, size_t* dst_size
) {
344 if (glyph
.composite_data_size
> 0) {
346 if (*dst_size
< ((10ULL + glyph
.composite_data_size
) +
347 ((glyph
.have_instructions
? 2ULL : 0) +
348 glyph
.instructions_size
))) {
349 return FONT_COMPRESSION_FAILURE();
351 Store16(-1, &offset
, dst
);
352 StoreBbox(glyph
, &offset
, dst
);
353 StoreBytes(glyph
.composite_data
, glyph
.composite_data_size
, &offset
, dst
);
354 if (glyph
.have_instructions
) {
355 StoreInstructions(glyph
, &offset
, dst
);
357 } else if (glyph
.contours
.size() > 0) {
359 if (glyph
.contours
.size() > std::numeric_limits
<int16_t>::max()) {
360 return FONT_COMPRESSION_FAILURE();
362 if (*dst_size
< ((12ULL + 2 * glyph
.contours
.size()) +
363 glyph
.instructions_size
)) {
364 return FONT_COMPRESSION_FAILURE();
366 Store16(glyph
.contours
.size(), &offset
, dst
);
367 StoreBbox(glyph
, &offset
, dst
);
368 if (!StoreEndPtsOfContours(glyph
, &offset
, dst
)) {
369 return FONT_COMPRESSION_FAILURE();
371 StoreInstructions(glyph
, &offset
, dst
);
372 if (!StorePoints(glyph
, &offset
, dst
, *dst_size
)) {
373 return FONT_COMPRESSION_FAILURE();