1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Converts an Input protobuf Message to a string that can be successfully read
6 // by SkImageFilter::Deserialize and used as an image filter. The string
7 // is essentially a valid flattened skia image filter. Note: We will sometimes
8 // not use the exact values given to us by LPM in cases where those particular
9 // values cause issues with OOMs and timeouts. Other times, we may write a value
10 // that isn't exactly the same as the one given to us by LPM, since we may want
11 // to write invalid values that the proto definition forbids (eg a number that
12 // is not in enum). Also note that the skia unflattening code is necessary to
13 // apply the output of the converter to a canvas, but it isn't the main target
14 // of the fuzzer. This means that we will generally try to produce output that
15 // can be applied to a canvas, even if we will consequently be unable to produce
16 // outputs that allow us to reach paths in the unflattening code (in particular,
17 // code that handles invalid input). We make this tradeoff because being applied
18 // to a canvas makes an image filter more likely to cause bugs than if it were
19 // just deserialized. Thus, increasing the chance that a filter is applied is
20 // more important than hitting all paths in unflattening, particularly if those
21 // paths return nullptr because they've detected an invalid filter. The mutated
22 // enum values are a case where we knowingly generate output that may not be
23 // unflattened successfully, which is why we mutate enums relatively
24 // infrequently.
25 // Note that since this is a work in progress and skia serialization is a
26 // moving target, not everything is finished. Many of these parts of the code
27 // are #defined out if DEVELOPMENT is not defined.
28
29 #include "testing/libfuzzer/proto/skia_image_filter_proto_converter.h"
30
31 #include <stdlib.h>
32
33 #include <algorithm>
34 #include <cmath>
35 #include <limits>
36 #include <random>
37 #include <set>
38 #include <string>
39 #include <tuple>
40 #include <unordered_map>
41 #include <vector>
42
43 #include "base/check_op.h"
44 #include "base/containers/contains.h"
45 #include "base/notreached.h"
46 #include "third_party/protobuf/src/google/protobuf/descriptor.h"
47 #include "third_party/protobuf/src/google/protobuf/message.h"
48 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
49 #include "third_party/skia/include/core/SkPoint.h"
50 #include "third_party/skia/include/core/SkRect.h"
51
52 using google::protobuf::Descriptor;
53 using google::protobuf::EnumDescriptor;
54 using google::protobuf::EnumValueDescriptor;
55 using google::protobuf::FieldDescriptor;
56 using google::protobuf::Message;
57 using google::protobuf::Reflection;
58
59 namespace skia_image_filter_proto_converter {
60
61 // Visit the skia flattenable that is stored on the oneof FIELD field of MSG if
62 // not flattenable_visited and MSG.has_FIELD. Sets flattenable_visited to true
63 // if the MSG.FIELD() is visited. Note that `bool flattenable_visited` must be
64 // defined false in the same context that this macro is used, before it can be
65 // used.
66 #define VISIT_ONEOF_FLATTENABLE(MSG, FIELD) \
67 if (MSG.has_##FIELD() && !IsBlacklisted(#FIELD)) { \
68 CHECK(!flattenable_visited); \
69 if (PreVisitFlattenable(FieldToFlattenableName(#FIELD))) { \
70 Visit(MSG.FIELD()); \
71 PostVisitFlattenable(); \
72 } \
73 flattenable_visited = true; \
74 }
75
76 // Visit FIELD if FIELD is set or if no other field on message was visited
77 // (this should be used at the end of a series of calls to
78 // VISIT_ONEOF_FLATTENABLE).
79 // Note FIELD should not be a message that contains itself by default.
80 // This is used for messages like ImageFilterChild where we must visit one of
81 // the fields in a oneof. Even though protobuf doesn't mandate that one of these
82 // be set, we can still visit one of them if they are not set and protobuf will
83 // return the default values for each field on that message.
84 #define VISIT_DEFAULT_FLATTENABLE(MSG, FIELD) \
85 VISIT_ONEOF_FLATTENABLE(MSG, FIELD); \
86 if (!flattenable_visited) { \
87 flattenable_visited = true; \
88 if (PreVisitFlattenable(FieldToFlattenableName(#FIELD))) { \
89 Visit(MSG.FIELD()); \
90 PostVisitFlattenable(); \
91 } \
92 }
93
94 // Visit FIELD if it is set on MSG, or write a NULL to indicate it is not
95 // present.
96 #define VISIT_OPT_OR_NULL(MSG, FIELD) \
97 if (MSG.has_##FIELD()) { \
98 Visit(MSG.FIELD()); \
99 } else { \
100 WriteNum(0); \
101 }
102
103 // Call VisitPictureTag on picture_tag.FIELD() if it is set.
104 #define VISIT_OPT_TAG(FIELD, TAG) \
105 if (picture_tag.has_##FIELD()) { \
106 VisitPictureTag(picture_tag.FIELD(), TAG); \
107 }
108
109 // Copied from third_party/skia/include/core/SkTypes.h:SkSetFourByteTag.
110 #define SET_FOUR_BYTE_TAG(A, B, C, D) \
111 (((A) << 24) | ((B) << 16) | ((C) << 8) | (D))
112
113 // The following enums and constants are copied from various parts of the skia
114 // codebase.
115 enum FlatFlags {
116 kHasTypeface_FlatFlag = 0x1,
117 kHasEffects_FlatFlag = 0x2,
118 kFlatFlagMask = 0x3,
119 };
120
121 enum LightType {
122 kDistant_LightType,
123 kPoint_LightType,
124 kSpot_LightType,
125 };
126
127 // Copied from SkVertices.cpp.
128 using VerticesConstants = int;
129 constexpr VerticesConstants kMode_Mask = 0x0FF;
130 constexpr VerticesConstants kHasTexs_Mask = 0x100;
131 constexpr VerticesConstants kHasColors_Mask = 0x200;
132
133 // Copied from SerializationOffsets in SkPath.h. Named PathSerializationOffsets
134 // to avoid conflicting with PathRefSerializationOffsets. Both enums were named
135 // SerializationOffsets in skia.
136 enum PathSerializationOffsets {
137 kType_SerializationShift = 28,
138 kDirection_SerializationShift = 26,
139 kIsVolatile_SerializationShift = 25,
140 kConvexity_SerializationShift = 16,
141 kFillType_SerializationShift = 8,
142 };
143
144 // Copied from SerializationOffsets in SkPathRef.h. Named
145 // PathRefSerializationOffsets to avoid conflicting with
146 // PathSerializationOffsets. Both enums were named SerializationOffsets in skia.
147 enum PathRefSerializationOffsets {
148 kLegacyRRectOrOvalStartIdx_SerializationShift = 28,
149 kLegacyRRectOrOvalIsCCW_SerializationShift = 27,
150 kLegacyIsRRect_SerializationShift = 26,
151 kIsFinite_SerializationShift = 25,
152 kLegacyIsOval_SerializationShift = 24,
153 kSegmentMask_SerializationShift = 0
154 };
155
156 const uint32_t Converter::kPictEofTag = SET_FOUR_BYTE_TAG('e', 'o', 'f', ' ');
157
158 const uint32_t Converter::kProfileLookupTable[] = {
159 SET_FOUR_BYTE_TAG('m', 'n', 't', 'r'),
160 SET_FOUR_BYTE_TAG('s', 'c', 'n', 'r'),
161 SET_FOUR_BYTE_TAG('p', 'r', 't', 'r'),
162 SET_FOUR_BYTE_TAG('s', 'p', 'a', 'c'),
163 };
164
165 const uint32_t Converter::kInputColorSpaceLookupTable[] = {
166 SET_FOUR_BYTE_TAG('R', 'G', 'B', ' '),
167 SET_FOUR_BYTE_TAG('C', 'M', 'Y', 'K'),
168 SET_FOUR_BYTE_TAG('G', 'R', 'A', 'Y'),
169 };
170
171 const uint32_t Converter::kPCSLookupTable[] = {
172 SET_FOUR_BYTE_TAG('X', 'Y', 'Z', ' '),
173 SET_FOUR_BYTE_TAG('L', 'a', 'b', ' '),
174 };
175
176 const uint32_t Converter::kTagLookupTable[] = {
177 SET_FOUR_BYTE_TAG('r', 'X', 'Y', 'Z'),
178 SET_FOUR_BYTE_TAG('g', 'X', 'Y', 'Z'),
179 SET_FOUR_BYTE_TAG('b', 'X', 'Y', 'Z'),
180 SET_FOUR_BYTE_TAG('r', 'T', 'R', 'C'),
181 SET_FOUR_BYTE_TAG('g', 'T', 'R', 'C'),
182 SET_FOUR_BYTE_TAG('b', 'T', 'R', 'C'),
183 SET_FOUR_BYTE_TAG('k', 'T', 'R', 'C'),
184 SET_FOUR_BYTE_TAG('A', '2', 'B', '0'),
185 SET_FOUR_BYTE_TAG('c', 'u', 'r', 'v'),
186 SET_FOUR_BYTE_TAG('p', 'a', 'r', 'a'),
187 SET_FOUR_BYTE_TAG('m', 'l', 'u', 'c'),
188 };
189
190 const char Converter::kSkPictReaderTag[] = {'r', 'e', 'a', 'd'};
191 const char Converter::kPictureMagicString[] = {'s', 'k', 'i', 'a',
192 'p', 'i', 'c', 't'};
193
194 const uint8_t Converter::kCountNibBits[] = {0, 1, 1, 2, 1, 2, 2, 3,
195 1, 2, 2, 3, 2, 3, 3, 4};
196
197 // The rest of the Converter attributes are not copied from skia.
198 const int Converter::kFlattenableDepthLimit = 3;
199 const int Converter::kColorTableBufferLength = 256;
200 uint8_t Converter::kColorTableBuffer[kColorTableBufferLength];
201 const int Converter::kNumBound = 20;
202 const uint8_t Converter::kMutateEnumDenominator = 40;
203
204 // Does not include SkSumPathEffect, SkComposePathEffect or SkRegion
205 // since they don't use the VISIT FLATTENABLE macros.
206 const string_map_t Converter::kFieldToFlattenableName = {
207 {"path_1d_path_effect", "SkPath1DPathEffect"},
208 {"path_2d_path_effect", "SkPath2DPathEffect"},
209 {"alpha_threshold_filter_impl", "SkAlphaThresholdFilterImpl"},
210 {"arithmetic_image_filter", "SkArithmeticImageFilter"},
211 {"blur_image_filter_impl", "SkBlurImageFilterImpl"},
212 {"blur_mask_filter_impl", "SkBlurMaskFilterImpl"},
213 {"color_4_shader", "SkColor4Shader"},
214 {"color_filter_image_filter", "SkColorFilterImageFilter"},
215 {"color_filter_shader", "SkColorFilterShader"},
216 {"color_matrix_filter_row_major_255", "SkColorMatrixFilterRowMajor255"},
217 {"color_shader", "SkColorShader"},
218 {"compose_color_filter", "SkComposeColorFilter"},
219 {"compose_image_filter", "SkComposeImageFilter"},
220 {"compose_shader", "SkComposeShader"},
221 {"corner_path_effect", "SkCornerPathEffect"},
222 {"dash_impl", "SkDashImpl"},
223 {"diffuse_lighting_image_filter", "SkDiffuseLightingImageFilter"},
224 {"dilate_image_filter", "SkDilateImageFilter"},
225 {"discrete_path_effect", "SkDiscretePathEffect"},
226 {"displacement_map_effect", "SkDisplacementMapEffect"},
227 {"drop_shadow_image_filter", "SkDropShadowImageFilter"},
228 {"emboss_mask_filter", "SkEmbossMaskFilter"},
229 {"empty_shader", "SkEmptyShader"},
230 {"image_shader", "SkImageShader"},
231 {"image_source", "SkImageSource"},
232 {"line_2d_path_effect", "SkLine2DPathEffect"},
233 {"linear_gradient", "SkLinearGradient"},
234 {"local_matrix_image_filter", "SkLocalMatrixImageFilter"},
235 {"local_matrix_shader", "SkLocalMatrixShader"},
236 {"luma_color_filter", "SkLumaColorFilter"},
237 {"magnifier_image_filter", "SkMagnifierImageFilter"},
238 {"matrix_convolution_image_filter", "SkMatrixConvolutionImageFilter"},
239 {"matrix_image_filter", "SkMatrixImageFilter"},
240 {"merge_image_filter", "SkMergeImageFilter"},
241 {"mode_color_filter", "SkModeColorFilter"},
242 {"offset_image_filter", "SkOffsetImageFilter"},
243 {"overdraw_color_filter", "SkOverdrawColorFilter"},
244 {"paint_image_filter", "SkPaintImageFilter"},
245 {"picture_image_filter", "SkPictureImageFilter"},
246 {"picture_shader", "SkPictureShader"},
247 {"radial_gradient", "SkRadialGradient"},
248 {"specular_lighting_image_filter", "SkSpecularLightingImageFilter"},
249 {"sweep_gradient", "SkSweepGradient"},
250 {"tile_image_filter", "SkTileImageFilter"},
251 {"two_point_conical_gradient", "SkTwoPointConicalGradient"},
252 {"xfermode_image_filter", "SkXfermodeImageFilter"},
253 {"xfermode_image_filter__base", "SkXfermodeImageFilter_Base"},
254 {"srgb_gamma_color_filter", "SkSRGBGammaColorFilter"},
255 {"high_contrast__filter", "SkHighContrast_Filter"},
256 {"table__color_filter", "SkTable_ColorFilter"},
257 {"to_srgb_color_filter", "SkToSRGBColorFilter"},
258 {"layer_draw_looper", "SkLayerDrawLooper"},
259 {"perlin_noise_shader_impl", "SkPerlinNoiseShaderImpl"},
260 {"erode_image_filter", "SkErodeImageFilter"},
261 };
262
263 const std::set<std::string> Converter::kMisbehavedFlattenableBlacklist = {
264 "matrix_image_filter", // Causes OOMs.
265 "discrete_path_effect", // Causes timeouts.
266 "path_1d_path_effect", // Causes timeouts.
267 };
268
269 // We don't care about default values of attributes because Reset() sets them to
270 // correct values and is called by Convert(), the only important public
271 // function.
Converter()272 Converter::Converter() {
273 CHECK_GT(kMutateEnumDenominator, 2);
274 }
275
~Converter()276 Converter::~Converter() {}
277
Converter(const Converter & other)278 Converter::Converter(const Converter& other) {}
279
FieldToFlattenableName(const std::string & field_name) const280 std::string Converter::FieldToFlattenableName(
281 const std::string& field_name) const {
282 CHECK(base::Contains(kFieldToFlattenableName, field_name));
283
284 return kFieldToFlattenableName.at(field_name);
285 }
286
Reset()287 void Converter::Reset() {
288 output_.clear();
289 bound_positive_ = false;
290 dont_mutate_enum_ = true;
291 pair_path_effect_depth_ = 0;
292 flattenable_depth_ = 0;
293 stroke_style_used_ = false;
294 in_compose_color_filter_ = false;
295 // In production we don't need attributes used by ICC code since it is not
296 // built for production code.
297 #ifdef DEVELOPMENT
298 tag_offset_ = 0;
299 icc_base_ = 0;
300 #endif // DEVELOPMENT
301 }
302
Convert(const Input & input)303 std::string Converter::Convert(const Input& input) {
304 Reset();
305 rand_gen_ = std::mt19937(input.rng_seed());
306 enum_mutator_chance_distribution_ =
307 std::uniform_int_distribution<>(2, kMutateEnumDenominator);
308
309 // This will recursively call Visit on each proto flattenable until all of
310 // them are converted to strings and stored in output_.
311 Visit(input.image_filter());
312 CheckAlignment();
313 return std::string(&output_[0], output_.size());
314 }
315
Visit(const CropRectangle & crop_rectangle)316 void Converter::Visit(const CropRectangle& crop_rectangle) {
317 Visit(crop_rectangle.rectangle());
318 WriteNum(BoundNum(crop_rectangle.flags()));
319 }
320
Visit(const Rectangle & rectangle)321 void Converter::Visit(const Rectangle& rectangle) {
322 WriteRectangle(GetValidRectangle(rectangle.left(), rectangle.top(),
323 rectangle.right(), rectangle.bottom()));
324 }
325
326 std::tuple<float, float, float, float>
GetValidRectangle(float left,float top,float right,float bottom)327 Converter::GetValidRectangle(float left, float top, float right, float bottom) {
328 bool initial = bound_positive_;
329 bound_positive_ = true;
330 left = BoundFloat(left);
331 top = BoundFloat(top);
332 right = BoundFloat(right);
333 bottom = BoundFloat(bottom);
334
335 if (right < left)
336 right = left;
337
338 if (bottom < top)
339 bottom = top;
340
341 // Inspired by SkValidationUtils.h:SkIsValidRect
342 CHECK_LE(left, right);
343 CHECK_LE(top, bottom);
344 CHECK(IsFinite(right - left));
345 CHECK(IsFinite(bottom - top));
346 bound_positive_ = initial;
347 return std::make_tuple(left, top, right, bottom);
348 }
349
GetValidIRect(int32_t left,int32_t top,int32_t right,int32_t bottom)350 std::tuple<int32_t, int32_t, int32_t, int32_t> Converter::GetValidIRect(
351 int32_t left,
352 int32_t top,
353 int32_t right,
354 int32_t bottom) {
355 auto float_rectangle = GetValidRectangle(left, top, right, bottom);
356 return std::make_tuple(static_cast<int32_t>(std::get<0>(float_rectangle)),
357 static_cast<int32_t>(std::get<1>(float_rectangle)),
358 static_cast<int32_t>(std::get<2>(float_rectangle)),
359 static_cast<int32_t>(std::get<3>(float_rectangle)));
360 }
361
362 template <typename T>
WriteRectangle(std::tuple<T,T,T,T> rectangle)363 void Converter::WriteRectangle(std::tuple<T, T, T, T> rectangle) {
364 WriteNum(std::get<0>(rectangle));
365 WriteNum(std::get<1>(rectangle));
366 WriteNum(std::get<2>(rectangle));
367 WriteNum(std::get<3>(rectangle));
368 }
369
Visit(const LightChild & light_child)370 void Converter::Visit(const LightChild& light_child) {
371 if (light_child.has_point_light())
372 Visit(light_child.point_light());
373 else if (light_child.has_spot_light())
374 Visit(light_child.spot_light());
375 else
376 Visit(light_child.distant_light());
377 }
378
Visit(const LightParent & light_parent)379 void Converter::Visit(const LightParent& light_parent) {
380 if (light_parent.light_child().has_point_light())
381 WriteNum(kPoint_LightType);
382 else if (light_parent.light_child().has_spot_light())
383 WriteNum(kSpot_LightType);
384 else // Assume we have distant light
385 WriteNum(kDistant_LightType);
386 Visit(light_parent.color());
387 Visit(light_parent.light_child());
388 }
389
Visit(const ImageFilterChild & image_filter_child)390 void Converter::Visit(const ImageFilterChild& image_filter_child) {
391 bool flattenable_visited = false;
392 VISIT_ONEOF_FLATTENABLE(image_filter_child, specular_lighting_image_filter);
393 VISIT_ONEOF_FLATTENABLE(image_filter_child, matrix_image_filter);
394 VISIT_ONEOF_FLATTENABLE(image_filter_child, arithmetic_image_filter);
395 VISIT_ONEOF_FLATTENABLE(image_filter_child, alpha_threshold_filter_impl);
396 VISIT_ONEOF_FLATTENABLE(image_filter_child, blur_image_filter_impl);
397 VISIT_ONEOF_FLATTENABLE(image_filter_child, color_filter_image_filter);
398 VISIT_ONEOF_FLATTENABLE(image_filter_child, compose_image_filter);
399 VISIT_ONEOF_FLATTENABLE(image_filter_child, displacement_map_effect);
400 VISIT_ONEOF_FLATTENABLE(image_filter_child, drop_shadow_image_filter);
401 VISIT_ONEOF_FLATTENABLE(image_filter_child, local_matrix_image_filter);
402 VISIT_ONEOF_FLATTENABLE(image_filter_child, magnifier_image_filter);
403 VISIT_ONEOF_FLATTENABLE(image_filter_child, matrix_convolution_image_filter);
404 VISIT_ONEOF_FLATTENABLE(image_filter_child, merge_image_filter);
405 VISIT_ONEOF_FLATTENABLE(image_filter_child, dilate_image_filter);
406 VISIT_ONEOF_FLATTENABLE(image_filter_child, erode_image_filter);
407 VISIT_ONEOF_FLATTENABLE(image_filter_child, offset_image_filter);
408 VISIT_ONEOF_FLATTENABLE(image_filter_child, picture_image_filter);
409 VISIT_ONEOF_FLATTENABLE(image_filter_child, tile_image_filter);
410 VISIT_ONEOF_FLATTENABLE(image_filter_child, xfermode_image_filter__base);
411 VISIT_ONEOF_FLATTENABLE(image_filter_child, xfermode_image_filter);
412 VISIT_ONEOF_FLATTENABLE(image_filter_child, diffuse_lighting_image_filter);
413 VISIT_ONEOF_FLATTENABLE(image_filter_child, image_source);
414 VISIT_DEFAULT_FLATTENABLE(image_filter_child, paint_image_filter);
415 }
416
Visit(const DiffuseLightingImageFilter & diffuse_lighting_image_filter)417 void Converter::Visit(
418 const DiffuseLightingImageFilter& diffuse_lighting_image_filter) {
419 Visit(diffuse_lighting_image_filter.parent(), 1);
420 Visit(diffuse_lighting_image_filter.light());
421 WriteNum(diffuse_lighting_image_filter.surface_scale());
422 // Can't be negative, see:
423 // https://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
424 const float kd = fabs(BoundFloat(diffuse_lighting_image_filter.kd()));
425 WriteNum(kd);
426 }
427
Visit(const XfermodeImageFilter & xfermode_image_filter)428 void Converter::Visit(const XfermodeImageFilter& xfermode_image_filter) {
429 Visit(xfermode_image_filter.parent(), 2);
430 WriteNum(xfermode_image_filter.mode());
431 }
432
Visit(const XfermodeImageFilter_Base & xfermode_image_filter__base)433 void Converter::Visit(
434 const XfermodeImageFilter_Base& xfermode_image_filter__base) {
435 Visit(xfermode_image_filter__base.parent(), 2);
436 WriteNum(xfermode_image_filter__base.mode());
437 }
438
Visit(const TileImageFilter & tile_image_filter)439 void Converter::Visit(const TileImageFilter& tile_image_filter) {
440 Visit(tile_image_filter.parent(), 1);
441 Visit(tile_image_filter.src());
442 Visit(tile_image_filter.dst());
443 }
444
Visit(const OffsetImageFilter & offset_image_filter)445 void Converter::Visit(const OffsetImageFilter& offset_image_filter) {
446 Visit(offset_image_filter.parent(), 1);
447 Visit(offset_image_filter.offset());
448 }
449
Visit(const HighContrast_Filter & high_contrast__filter)450 void Converter::Visit(const HighContrast_Filter& high_contrast__filter) {
451 WriteFields(high_contrast__filter, 1, 2);
452 // Use contrast as a seed.
453 WriteNum(GetRandomFloat(high_contrast__filter.contrast(), -1.0, 1.0));
454 }
455
Visit(const MergeImageFilter & merge_image_filter)456 void Converter::Visit(const MergeImageFilter& merge_image_filter) {
457 Visit(merge_image_filter.parent(), merge_image_filter.parent().inputs_size());
458 }
459
Visit(const ErodeImageFilter & erode_image_filter)460 void Converter::Visit(const ErodeImageFilter& erode_image_filter) {
461 Visit(erode_image_filter.parent(), 1);
462 bool initial = bound_positive_;
463 bound_positive_ = true;
464 WriteFields(erode_image_filter, 2);
465 bound_positive_ = initial;
466 }
467
468 template <typename T>
BoundNum(T num,int upper_bound) const469 T Converter::BoundNum(T num, int upper_bound) const {
470 if (bound_positive_)
471 num = Abs(num);
472 if (num >= 0) {
473 return num % upper_bound;
474 } else {
475 // Don't let negative numbers be too negative.
476 return num % -upper_bound;
477 }
478 }
479
480 template <typename T>
BoundNum(T num)481 T Converter::BoundNum(T num) {
482 return BoundNum(num, kNumBound);
483 }
484
BoundFloat(float num)485 float Converter::BoundFloat(float num) {
486 return BoundFloat(num, kNumBound);
487 }
488
BoundFloat(float num,const float num_bound)489 float Converter::BoundFloat(float num, const float num_bound) {
490 // Don't allow nans infs, they can cause OOMs.
491 if (!IsFinite(num))
492 num = GetRandomFloat(&rand_gen_);
493
494 float result;
495 if (num >= 0)
496 result = fmod(num, num_bound);
497 else if (bound_positive_)
498 result = fmod(fabsf(num), num_bound);
499 else
500 // Bound negative numbers.
501 result = fmod(num, -num_bound);
502 if (!IsFinite(result))
503 return BoundFloat(num);
504 return result;
505 }
506
Visit(const DilateImageFilter & dilate_image_filter)507 void Converter::Visit(const DilateImageFilter& dilate_image_filter) {
508 Visit(dilate_image_filter.parent(), 1);
509 // Make sure WriteFields writes positive values for width and height.
510 // Save the value of bound_positive_ and restore it after WriteFields
511 // returns.
512 bool initial_bound_positive = bound_positive_;
513 bound_positive_ = true;
514 WriteFields(dilate_image_filter, 2);
515 bound_positive_ = initial_bound_positive;
516 }
517
Visit(const MatrixConvolutionImageFilter & matrix_convolution_image_filter)518 void Converter::Visit(
519 const MatrixConvolutionImageFilter& matrix_convolution_image_filter) {
520 Visit(matrix_convolution_image_filter.parent(), 1);
521 // Avoid timeouts from having to generate too many random numbers.
522 // TODO(metzman): actually calculate the limit based on this bound (eg 31 x 1
523 // probably doesn't need to be bounded).
524 const int upper_bound = 30;
525
526 // Use 2 instead of 1 to avoid FPEs in BoundNum.
527 int32_t width = std::max(
528 2, BoundNum(Abs(matrix_convolution_image_filter.width()), upper_bound));
529
530 WriteNum(width);
531
532 int32_t height = std::max(
533 2, BoundNum(Abs(matrix_convolution_image_filter.height()), upper_bound));
534
535 WriteNum(height);
536
537 std::mt19937 rand_gen(matrix_convolution_image_filter.kernel_seed());
538 const uint32_t kernel_size = width * height;
539 WriteNum(kernel_size);
540 // Use rand_gen to ensure we have a large enough kernel.
541 for (uint32_t kernel_counter = 0; kernel_counter < kernel_size;
542 kernel_counter++) {
543 float kernel_element = GetRandomFloat(&rand_gen);
544 WriteNum(kernel_element);
545 }
546 WriteFields(matrix_convolution_image_filter, 5, 6);
547
548 const uint32_t offset_x =
549 std::max(0, matrix_convolution_image_filter.offset_x());
550
551 const uint32_t offset_y =
552 std::max(0, matrix_convolution_image_filter.offset_y());
553
554 WriteNum(BoundNum(offset_x, width - 1));
555 WriteNum(BoundNum(offset_y, height - 1));
556 WriteFields(matrix_convolution_image_filter, 9);
557 }
558
Visit(const MagnifierImageFilter & magnifier_image_filter)559 void Converter::Visit(const MagnifierImageFilter& magnifier_image_filter) {
560 Visit(magnifier_image_filter.parent(), 1);
561 Visit(magnifier_image_filter.src());
562 const float inset = fabs(BoundFloat(magnifier_image_filter.inset()));
563 CHECK(IsFinite(inset));
564 WriteNum(inset);
565 }
566
Visit(const LocalMatrixImageFilter & local_matrix_image_filter)567 void Converter::Visit(const LocalMatrixImageFilter& local_matrix_image_filter) {
568 // TODO(metzman): Make it so that deserialization always succeeds by ensuring
569 // the type isn't kAffine_Mask or KPerspectiveMask (see constructor for
570 // SkLocalMatrixImageFilter).
571 Visit(local_matrix_image_filter.parent(), 1);
572 Visit(local_matrix_image_filter.matrix(), true);
573 }
574
Visit(const ImageSource & image_source)575 void Converter::Visit(const ImageSource& image_source) {
576 WriteNum(image_source.filter_quality());
577 auto src_rect = GetValidRectangle(
578 image_source.src().left(), image_source.src().top(),
579 image_source.src().right(), image_source.src().bottom());
580
581 // See SkImageSource::Make for why we mandate width and height be at least
582 // .01. This is such a small difference that we won't bother bounding again.
583 float left = std::get<0>(src_rect);
584 float* right = &std::get<2>(src_rect);
585 if ((*right - left) <= 0.0f)
586 *right += .01;
587
588 float top = std::get<1>(src_rect);
589 float* bottom = &std::get<3>(src_rect);
590 if ((*bottom - top) <= 0.0f)
591 *bottom += .01;
592
593 WriteRectangle(src_rect);
594 Visit(image_source.dst());
595 Visit(image_source.image());
596 }
597
Visit(const DropShadowImageFilter & drop_shadow_image_filter)598 void Converter::Visit(const DropShadowImageFilter& drop_shadow_image_filter) {
599 Visit(drop_shadow_image_filter.parent(), 1);
600 WriteFields(drop_shadow_image_filter, 2);
601 }
602
Visit(const DisplacementMapEffect & displacement_map_effect)603 void Converter::Visit(const DisplacementMapEffect& displacement_map_effect) {
604 Visit(displacement_map_effect.parent(), 2);
605 bool initial = dont_mutate_enum_;
606 dont_mutate_enum_ = true;
607 WriteFields(displacement_map_effect, 2);
608 dont_mutate_enum_ = initial;
609 }
610
Visit(const ComposeImageFilter & compose_image_filter)611 void Converter::Visit(const ComposeImageFilter& compose_image_filter) {
612 Visit(compose_image_filter.parent(), 2);
613 }
614
Visit(const ColorFilterImageFilter & color_filter_image_filter)615 void Converter::Visit(const ColorFilterImageFilter& color_filter_image_filter) {
616 Visit(color_filter_image_filter.parent(), 1);
617 Visit(color_filter_image_filter.color_filter());
618 }
619
Visit(const BlurImageFilterImpl & blur_image_filter_impl)620 void Converter::Visit(const BlurImageFilterImpl& blur_image_filter_impl) {
621 Visit(blur_image_filter_impl.parent(), 1);
622 WriteFields(blur_image_filter_impl, 2);
623 }
624
Visit(const AlphaThresholdFilterImpl & alpha_threshold_filter_impl)625 void Converter::Visit(
626 const AlphaThresholdFilterImpl& alpha_threshold_filter_impl) {
627 Visit(alpha_threshold_filter_impl.parent(), 1);
628 WriteFields(alpha_threshold_filter_impl, 2, 3);
629 Visit(alpha_threshold_filter_impl.rgn());
630 }
631
WriteNonEmptyIRect(const IRect & irect)632 std::tuple<int32_t, int32_t, int32_t, int32_t> Converter::WriteNonEmptyIRect(
633 const IRect& irect) {
634 // Make sure bounds do not specify an empty rectangle.
635 // See SkRect.h:202
636 auto rectangle =
637 GetValidIRect(irect.left(), irect.top(), irect.right(), irect.bottom());
638
639 // Ensure top and right are greater than left and top.
640 if (irect.left() >= irect.right() || irect.top() >= irect.bottom()) {
641 std::get<2>(rectangle) = std::get<0>(rectangle) + 1;
642 std::get<3>(rectangle) = std::get<1>(rectangle) + 1;
643 }
644 WriteRectangle(rectangle);
645 return rectangle;
646 }
647
Visit(const Region & region)648 void Converter::Visit(const Region& region) {
649 // Write simple region.
650 WriteNum(0);
651 WriteNonEmptyIRect(region.bounds());
652
653 // Complex regions are not finished.
654 #ifdef DEVELOPMENT
655 enum { kRunTypeSentinel = 0x7FFFFFFF };
656 auto rectangle = WriteNonEmptyIRect(region.bounds());
657 const int32_t bound_left = std::get<0>(rectangle);
658 const int32_t bound_top = std::get<1>(rectangle);
659 const int32_t bound_right = std::get<2>(rectangle);
660 const int32_t bound_bottom = std::get<3>(rectangle);
661
662 const int32_t y_span_count =
663 BoundNum(std::max(1, Abs(region.y_span_count())));
664
665 const int32_t interval_count = BoundNum(std::max(1, Abs(region.interval_())));
666
667 WriteNum(run_count);
668 WriteNum(y_span_count);
669 WriteNum(interval_count);
670
671 // See SkRegion::validate_run.
672 // Really this is two less, but we will write the two sentinels
673 ourselves const int32_t run_count = 3 * y_span_count + 2 * interval_count;
674 CHECK(run_count >= 7);
675
676 WriteNum(run_count + 2);
677 // Write runs.
678
679 // Write top.
680 Write(bound_top);
681
682 WriteNum(kRunTypeSentinel);
683 WriteNum(kRunTypeSentinel);
684 #endif // DEVELOPMENT
685 }
686
Visit(const PictureInfo & picture_info)687 void Converter::Visit(const PictureInfo& picture_info) {
688 WriteArray(kPictureMagicString, sizeof(kPictureMagicString));
689 WriteNum(picture_info.version());
690 Visit(picture_info.rectangle());
691 if (picture_info.version() < PictureInfo::kRemoveHeaderFlags_Version)
692 WriteNum(picture_info.flags());
693 }
694
Visit(const ImageFilterParent & image_filter,const int num_inputs_required)695 void Converter::Visit(const ImageFilterParent& image_filter,
696 const int num_inputs_required) {
697 CHECK_GE(num_inputs_required, 0);
698 if (!num_inputs_required) {
699 WriteNum(0);
700 } else {
701 WriteNum(num_inputs_required);
702 WriteBool(true);
703 Visit(image_filter.default_input());
704 int num_inputs = 1;
705 for (const auto& input : image_filter.inputs()) {
706 if (num_inputs++ >= num_inputs_required)
707 break;
708 WriteBool(true);
709 Visit(input);
710 }
711 for (; num_inputs < num_inputs_required; num_inputs++) {
712 // Copy default_input until we have enough.
713 WriteBool(true);
714 Visit(image_filter.default_input());
715 }
716 }
717 Visit(image_filter.crop_rectangle());
718 }
719
Visit(const ArithmeticImageFilter & arithmetic_image_filter)720 void Converter::Visit(const ArithmeticImageFilter& arithmetic_image_filter) {
721 Visit(arithmetic_image_filter.parent(), 2);
722
723 // This is field is ignored, but write kSrcOver (3) as the flattening code
724 // does.
725 // TODO(metzman): change to enum value (SkBlendMode::kSrcOver) when it
726 // is uncommented, for now just write, its value: 3.
727 WriteNum(3);
728
729 WriteFields(arithmetic_image_filter, 2);
730 }
731
Visit(const SpecularLightingImageFilter & specular_lighting_image_filter)732 void Converter::Visit(
733 const SpecularLightingImageFilter& specular_lighting_image_filter) {
734 Visit(specular_lighting_image_filter.image_filter_parent(), 1);
735 Visit(specular_lighting_image_filter.light());
736 WriteNum(BoundFloat(specular_lighting_image_filter.surface_scale()) * 255);
737 WriteNum(fabs(BoundFloat(specular_lighting_image_filter.ks())));
738 WriteNum(BoundFloat(specular_lighting_image_filter.shininess()));
739 }
740
RecordSize()741 void Converter::RecordSize() {
742 // Reserve space to overwrite when we are done writing whatever size we are
743 // recording.
744 WriteNum(0);
745 start_sizes_.push_back(output_.size());
746 }
747
PopStartSize()748 size_t Converter::PopStartSize() {
749 CHECK_GT(start_sizes_.size(), static_cast<size_t>(0));
750 const size_t back = start_sizes_.back();
751 start_sizes_.pop_back();
752 return back;
753 }
754
755 template <typename T>
WriteNum(const T num)756 void Converter::WriteNum(const T num) {
757 if (sizeof(T) > 4) {
758 CHECK(num <= UINT32_MAX);
759 uint32_t four_byte_num = static_cast<uint32_t>(num);
760 char num_arr[sizeof(four_byte_num)];
761 memcpy(num_arr, &four_byte_num, sizeof(four_byte_num));
762 for (size_t idx = 0; idx < sizeof(four_byte_num); idx++)
763 output_.push_back(num_arr[idx]);
764 return;
765 }
766 char num_arr[sizeof(T)];
767 memcpy(num_arr, &num, sizeof(T));
768 for (size_t idx = 0; idx < sizeof(T); idx++)
769 output_.push_back(num_arr[idx]);
770 }
771
InsertSize(const size_t size,const uint32_t position)772 void Converter::InsertSize(const size_t size, const uint32_t position) {
773 char size_arr[sizeof(uint32_t)];
774 memcpy(size_arr, &size, sizeof(uint32_t));
775
776 for (size_t idx = 0; idx < sizeof(uint32_t); idx++) {
777 const size_t output__idx = position + idx - sizeof(uint32_t);
778 CHECK_LT(output__idx, output_.size());
779 output_[output__idx] = size_arr[idx];
780 }
781 }
782
WriteBytesWritten()783 void Converter::WriteBytesWritten() {
784 const size_t start_size = PopStartSize();
785 CHECK_LT(start_size, std::numeric_limits<uint32_t>::max());
786 const size_t end_size = output_.size();
787 CHECK_LE(start_size, end_size);
788 const size_t bytes_written = end_size - start_size;
789 CHECK_LT(bytes_written, std::numeric_limits<uint32_t>::max());
790 InsertSize(bytes_written, start_size);
791 }
792
WriteString(const std::string str)793 void Converter::WriteString(const std::string str) {
794 WriteNum(str.size());
795 const char* c_str = str.c_str();
796 for (size_t idx = 0; idx < str.size(); idx++)
797 output_.push_back(c_str[idx]);
798
799 output_.push_back('\0'); // Add trailing NULL.
800
801 Pad(str.size() + 1);
802 }
803
WriteArray(const google::protobuf::RepeatedField<uint32_t> & repeated_field,const size_t size)804 void Converter::WriteArray(
805 const google::protobuf::RepeatedField<uint32_t>& repeated_field,
806 const size_t size) {
807 WriteNum(size * sizeof(uint32_t)); // Array size.
808 for (uint32_t element : repeated_field)
809 WriteNum(element);
810 // Padding is not a concern because uint32_ts are 4 bytes.
811 }
812
WriteArray(const char * arr,const size_t size)813 void Converter::WriteArray(const char* arr, const size_t size) {
814 WriteNum(size);
815 for (size_t idx = 0; idx < size; idx++)
816 output_.push_back(arr[idx]);
817
818 for (unsigned idx = 0; idx < size % 4; idx++)
819 output_.push_back('\0');
820 }
821
WriteBool(const bool bool_val)822 void Converter::WriteBool(const bool bool_val) {
823 // bools are usually written as 32 bit integers in skia flattening.
824 WriteNum(static_cast<uint32_t>(bool_val));
825 }
826
WriteNum(const char (& num_arr)[4])827 void Converter::WriteNum(const char (&num_arr)[4]) {
828 for (size_t idx = 0; idx < 4; idx++)
829 output_.push_back(num_arr[idx]);
830 }
831
Visit(const PictureShader & picture_shader)832 void Converter::Visit(const PictureShader& picture_shader) {
833 // PictureShader cannot be autovisited because matrix cannot be.
834 Visit(picture_shader.matrix());
835 WriteFields(picture_shader, 2, 3);
836 Visit(picture_shader.rect());
837 WriteBool(false);
838 }
839
Visit(const Message & msg)840 void Converter::Visit(const Message& msg) {
841 WriteFields(msg);
842 }
843
844 // Visit the Message elements of repeated_field, using the type-specific Visit
845 // methods (thanks to templating).
846 template <class T>
Visit(const google::protobuf::RepeatedPtrField<T> & repeated_field)847 void Converter::Visit(
848 const google::protobuf::RepeatedPtrField<T>& repeated_field) {
849 for (const T& single_field : repeated_field)
850 Visit(single_field);
851 }
852
Visit(const PictureImageFilter & picture_image_filter)853 void Converter::Visit(const PictureImageFilter& picture_image_filter) {
854 WriteBool(picture_image_filter.has_picture());
855 if (picture_image_filter.has_picture())
856 Visit(picture_image_filter.picture());
857 // Allow 0x0 rectangles to sometimes be written even though it will mess up
858 // make_localspace_filter.
859 Visit(picture_image_filter.crop_rectangle());
860 if (picture_image_filter.has_picture()) {
861 if (picture_image_filter.picture().info().version() <
862 PictureInfo::kRemoveHeaderFlags_Version)
863
864 WriteNum(picture_image_filter.resolution());
865 }
866 }
867
Visit(const PictureData & picture_data)868 void Converter::Visit(const PictureData& picture_data) {
869 for (auto& tag : picture_data.tags()) {
870 Visit(tag);
871 }
872 Visit(picture_data.reader_tag());
873
874 WriteNum(kPictEofTag);
875 }
876
VisitPictureTag(const PaintPictureTag & paint_picture_tag,uint32_t tag)877 void Converter::VisitPictureTag(const PaintPictureTag& paint_picture_tag,
878 uint32_t tag) {
879 WriteNum(tag);
880 WriteNum(1); // Size.
881 Visit(paint_picture_tag.paint());
882 }
883
VisitPictureTag(const PathPictureTag & path_picture_tag,uint32_t tag)884 void Converter::VisitPictureTag(const PathPictureTag& path_picture_tag,
885 uint32_t tag) {
886 WriteNum(tag);
887 WriteNum(1); // Size.
888 WriteNum(1); // Count.
889 Visit(path_picture_tag.path());
890 }
891
892 template <class T>
VisitPictureTag(const T & picture_tag_child,uint32_t tag)893 void Converter::VisitPictureTag(const T& picture_tag_child, uint32_t tag) {
894 WriteNum(tag);
895 WriteNum(1);
896 Visit(picture_tag_child);
897 }
898
Visit(const ReaderPictureTag & reader)899 void Converter::Visit(const ReaderPictureTag& reader) {
900 WriteNum(SET_FOUR_BYTE_TAG('r', 'e', 'a', 'd'));
901 const uint32_t size = sizeof(uint32_t) * (1 + reader.later_bytes_size());
902 WriteNum(size);
903 WriteNum(size);
904 WriteNum(reader.first_bytes());
905 for (auto bytes : reader.later_bytes())
906 WriteNum(bytes);
907 }
908
909 // Copied from SkPaint.cpp.
pack_4(unsigned a,unsigned b,unsigned c,unsigned d)910 static uint32_t pack_4(unsigned a, unsigned b, unsigned c, unsigned d) {
911 CHECK_EQ(a, (uint8_t)a);
912 CHECK_EQ(b, (uint8_t)b);
913 CHECK_EQ(c, (uint8_t)c);
914 CHECK_EQ(d, (uint8_t)d);
915 return (a << 24) | (b << 16) | (c << 8) | d;
916 }
917
918 // Copied from SkPaint.cpp.
pack_paint_flags(unsigned flags,unsigned hint,unsigned align,unsigned filter,unsigned flatFlags)919 static uint32_t pack_paint_flags(unsigned flags,
920 unsigned hint,
921 unsigned align,
922 unsigned filter,
923 unsigned flatFlags) {
924 // left-align the fields of "known" size, and right-align the last (flatFlags)
925 // so it can easily add more bits in the future.
926 return (flags << 16) | (hint << 14) | (align << 12) | (filter << 10) |
927 flatFlags;
928 }
929
IsFinite(float num) const930 bool Converter::IsFinite(float num) const {
931 // If num is inf, -inf, nan or -nan then num*0 will be nan.
932 return !std::isnan(num * 0);
933 }
934
Visit(const Paint & paint)935 void Converter::Visit(const Paint& paint) {
936 WriteFields(paint, 1, 6);
937
938 uint8_t flat_flags = 0;
939 if (paint.has_effects())
940 flat_flags |= kHasEffects_FlatFlag;
941
942 WriteNum(pack_paint_flags(paint.flags(), paint.hinting(), paint.align(),
943 paint.filter_quality(), flat_flags));
944
945 int style = paint.style();
946 Paint::StrokeCap stroke_cap = paint.stroke_cap();
947
948 if (stroke_style_used_) {
949 style = Paint::kFill_Style;
950 } else if (style == Paint::kStroke_Style) {
951 stroke_style_used_ = true;
952 // Avoid timeouts.
953 stroke_cap = Paint::kButt_Cap;
954 }
955
956 uint32_t tmp =
957 pack_4(stroke_cap, paint.stroke_join(),
958 (style << 4) | paint.text_encoding(), paint.blend_mode());
959
960 WriteNum(tmp); // See https://goo.gl/nYJfTy
961
962 if (paint.has_effects())
963 Visit(paint.effects());
964 }
965
Visit(const PaintEffects & paint_effects)966 void Converter::Visit(const PaintEffects& paint_effects) {
967 // There should be a NULL written for every paint_effects field that is not
968 // set.
969 VISIT_OPT_OR_NULL(paint_effects, path_effect);
970 VISIT_OPT_OR_NULL(paint_effects, shader);
971 VISIT_OPT_OR_NULL(paint_effects, mask_filter);
972 VISIT_OPT_OR_NULL(paint_effects, color_filter);
973 WriteNum(0); // Write ignored number where rasterizer used to be.
974 VISIT_OPT_OR_NULL(paint_effects, looper);
975 VISIT_OPT_OR_NULL(paint_effects, image_filter);
976 }
977
Visit(const ColorFilterChild & color_filter_child)978 void Converter::Visit(const ColorFilterChild& color_filter_child) {
979 bool flattenable_visited = false;
980 VISIT_ONEOF_FLATTENABLE(color_filter_child,
981 color_matrix_filter_row_major_255);
982
983 if (!in_compose_color_filter_)
984 VISIT_ONEOF_FLATTENABLE(color_filter_child, compose_color_filter);
985
986 VISIT_ONEOF_FLATTENABLE(color_filter_child, srgb_gamma_color_filter);
987 VISIT_ONEOF_FLATTENABLE(color_filter_child, high_contrast__filter);
988 VISIT_ONEOF_FLATTENABLE(color_filter_child, luma_color_filter);
989 VISIT_ONEOF_FLATTENABLE(color_filter_child, overdraw_color_filter);
990 VISIT_ONEOF_FLATTENABLE(color_filter_child, table__color_filter);
991 VISIT_ONEOF_FLATTENABLE(color_filter_child, to_srgb_color_filter);
992 VISIT_DEFAULT_FLATTENABLE(color_filter_child, mode_color_filter);
993 }
994
Visit(const Color4f & color_4f)995 void Converter::Visit(const Color4f& color_4f) {
996 WriteFields(color_4f);
997 }
998
Visit(const GradientDescriptor & gradient_descriptor)999 void Converter::Visit(const GradientDescriptor& gradient_descriptor) {
1000 // See SkGradientShaderBase::Descriptor::flatten in SkGradientShader.cpp.
1001 enum GradientSerializationFlags {
1002 // Bits 29:31 used for various boolean flags
1003 kHasPosition_GSF = 0x80000000,
1004 kHasLocalMatrix_GSF = 0x40000000,
1005 kHasColorSpace_GSF = 0x20000000,
1006
1007 // Bits 12:28 unused
1008
1009 // Bits 8:11 for fTileMode
1010 kTileModeShift_GSF = 8,
1011 kTileModeMask_GSF = 0xF,
1012
1013 // Bits 0:7 for fGradFlags (note that kForce4fContext_PrivateFlag is 0x80)
1014 kGradFlagsShift_GSF = 0,
1015 kGradFlagsMask_GSF = 0xFF,
1016 };
1017
1018 uint32_t flags = 0;
1019 if (gradient_descriptor.has_pos())
1020 flags |= kHasPosition_GSF;
1021 if (gradient_descriptor.has_local_matrix())
1022 flags |= kHasLocalMatrix_GSF;
1023 if (gradient_descriptor.has_color_space())
1024 flags |= kHasColorSpace_GSF;
1025 flags |= (gradient_descriptor.tile_mode() << kTileModeShift_GSF);
1026 uint32_t grad_flags =
1027 (gradient_descriptor.grad_flags() % (kGradFlagsMask_GSF + 1));
1028 CHECK_LE(grad_flags, static_cast<uint32_t>(kGradFlagsMask_GSF));
1029 WriteNum(flags);
1030
1031 const uint32_t count = gradient_descriptor.colors_size();
1032
1033 WriteNum(count);
1034 for (auto& color : gradient_descriptor.colors())
1035 Visit(color);
1036
1037 Visit(gradient_descriptor.color_space());
1038
1039 WriteNum(count);
1040 for (uint32_t counter = 0; counter < count; counter++)
1041 WriteNum(gradient_descriptor.pos());
1042
1043 Visit(gradient_descriptor.local_matrix());
1044 }
1045
Visit(const GradientParent & gradient_parent)1046 void Converter::Visit(const GradientParent& gradient_parent) {
1047 Visit(gradient_parent.gradient_descriptor());
1048 }
1049
Visit(const ToSRGBColorFilter & to_srgb_color_filter)1050 void Converter::Visit(const ToSRGBColorFilter& to_srgb_color_filter) {
1051 Visit(to_srgb_color_filter.color_space());
1052 }
1053
Visit(const LooperChild & looper)1054 void Converter::Visit(const LooperChild& looper) {
1055 if (PreVisitFlattenable("SkLayerDrawLooper")) {
1056 Visit(looper.layer_draw_looper());
1057 PostVisitFlattenable();
1058 }
1059 }
1060
1061 // Copied from SkPackBits.cpp.
flush_diff8(uint8_t * dst,const uint8_t * src,size_t count)1062 static uint8_t* flush_diff8(uint8_t* dst, const uint8_t* src, size_t count) {
1063 while (count > 0) {
1064 size_t n = count > 128 ? 128 : count;
1065 *dst++ = (uint8_t)(n + 127);
1066 memcpy(dst, src, n);
1067 src += n;
1068 dst += n;
1069 count -= n;
1070 }
1071 return dst;
1072 }
1073
1074 // Copied from SkPackBits.cpp.
flush_same8(uint8_t dst[],uint8_t value,size_t count)1075 static uint8_t* flush_same8(uint8_t dst[], uint8_t value, size_t count) {
1076 while (count > 0) {
1077 size_t n = count > 128 ? 128 : count;
1078 *dst++ = (uint8_t)(n - 1);
1079 *dst++ = (uint8_t)value;
1080 count -= n;
1081 }
1082 return dst;
1083 }
1084
1085 // Copied from SkPackBits.cpp.
compute_max_size8(size_t srcSize)1086 static size_t compute_max_size8(size_t srcSize) {
1087 // Worst case is the number of 8bit values + 1 byte per (up to) 128 entries.
1088 return ((srcSize + 127) >> 7) + srcSize;
1089 }
1090
1091 // Copied from SkPackBits.cpp.
pack8(const uint8_t * src,size_t srcSize,uint8_t * dst,size_t dstSize)1092 static size_t pack8(const uint8_t* src,
1093 size_t srcSize,
1094 uint8_t* dst,
1095 size_t dstSize) {
1096 if (dstSize < compute_max_size8(srcSize)) {
1097 return 0;
1098 }
1099
1100 uint8_t* const origDst = dst;
1101 const uint8_t* stop = src + srcSize;
1102
1103 for (intptr_t count = stop - src; count > 0; count = stop - src) {
1104 if (1 == count) {
1105 *dst++ = 0;
1106 *dst++ = *src;
1107 break;
1108 }
1109
1110 unsigned value = *src;
1111 const uint8_t* s = src + 1;
1112
1113 if (*s == value) { // accumulate same values...
1114 do {
1115 s++;
1116 if (s == stop) {
1117 break;
1118 }
1119 } while (*s == value);
1120 dst = flush_same8(dst, value, (size_t)(s - src));
1121 } else { // accumulate diff values...
1122 do {
1123 if (++s == stop) {
1124 goto FLUSH_DIFF;
1125 }
1126 // only stop if we hit 3 in a row,
1127 // otherwise we get bigger than compuatemax
1128 } while (*s != s[-1] || s[-1] != s[-2]);
1129 s -= 2; // back up so we don't grab the "same" values that follow
1130 FLUSH_DIFF:
1131 dst = flush_diff8(dst, src, (size_t)(s - src));
1132 }
1133 src = s;
1134 }
1135 return dst - origDst;
1136 }
1137
ColorTableToArray(const ColorTable & color_table)1138 const uint8_t* Converter::ColorTableToArray(const ColorTable& color_table) {
1139 float* dst = reinterpret_cast<float*>(kColorTableBuffer);
1140 const int array_size = 64;
1141 // Now write the 256 fields.
1142 const Descriptor* descriptor = color_table.GetDescriptor();
1143 CHECK(descriptor);
1144 const Reflection* reflection = color_table.GetReflection();
1145 CHECK(reflection);
1146 for (int field_num = 1; field_num <= array_size; field_num++, dst++) {
1147 const FieldDescriptor* field_descriptor =
1148 descriptor->FindFieldByNumber(field_num);
1149 CHECK(field_descriptor);
1150 *dst = BoundFloat(reflection->GetFloat(color_table, field_descriptor));
1151 }
1152 return kColorTableBuffer;
1153 }
1154
Visit(const Table_ColorFilter & table__color_filter)1155 void Converter::Visit(const Table_ColorFilter& table__color_filter) {
1156 // See SkTable_ColorFilter::SkTable_ColorFilter
1157 enum {
1158 kA_Flag = 1 << 0,
1159 kR_Flag = 1 << 1,
1160 kG_Flag = 1 << 2,
1161 kB_Flag = 1 << 3,
1162 };
1163 unsigned flags = 0;
1164 uint8_t f_storage[4 * kColorTableBufferLength];
1165 uint8_t* dst = f_storage;
1166
1167 if (table__color_filter.has_table_a()) {
1168 memcpy(dst, ColorTableToArray(table__color_filter.table_a()),
1169 kColorTableBufferLength);
1170
1171 dst += kColorTableBufferLength;
1172 flags |= kA_Flag;
1173 }
1174 if (table__color_filter.has_table_r()) {
1175 memcpy(dst, ColorTableToArray(table__color_filter.table_r()),
1176 kColorTableBufferLength);
1177
1178 dst += kColorTableBufferLength;
1179 flags |= kR_Flag;
1180 }
1181 if (table__color_filter.has_table_g()) {
1182 memcpy(dst, ColorTableToArray(table__color_filter.table_g()),
1183 kColorTableBufferLength);
1184
1185 dst += kColorTableBufferLength;
1186 flags |= kG_Flag;
1187 }
1188 if (table__color_filter.has_table_b()) {
1189 memcpy(dst, ColorTableToArray(table__color_filter.table_b()),
1190 kColorTableBufferLength);
1191
1192 dst += kColorTableBufferLength;
1193 flags |= kB_Flag;
1194 }
1195 uint8_t storage[5 * kColorTableBufferLength];
1196 const int count = kCountNibBits[flags & 0xF];
1197 const size_t size = pack8(f_storage, count * kColorTableBufferLength, storage,
1198 sizeof(storage));
1199
1200 CHECK_LE(flags, UINT32_MAX);
1201 const uint32_t flags_32 = (uint32_t)flags;
1202 WriteNum(flags_32);
1203 WriteNum((uint32_t)size);
1204 for (size_t idx = 0; idx < size; idx++)
1205 output_.push_back(storage[idx]);
1206 Pad(output_.size());
1207 }
1208
Visit(const ComposeColorFilter & compose_color_filter)1209 void Converter::Visit(const ComposeColorFilter& compose_color_filter) {
1210 CHECK(!in_compose_color_filter_);
1211 in_compose_color_filter_ = true;
1212 Visit(compose_color_filter.outer());
1213 Visit(compose_color_filter.inner());
1214 in_compose_color_filter_ = false;
1215 }
1216
Visit(const OverdrawColorFilter & overdraw_color_filter)1217 void Converter::Visit(const OverdrawColorFilter& overdraw_color_filter) {
1218 // This is written as a byte array (length-in-bytes followed by data).
1219 const uint32_t num_fields = 6;
1220 const uint32_t arr_size = num_fields * sizeof(uint32_t);
1221 WriteNum(arr_size);
1222 WriteFields(overdraw_color_filter);
1223 }
1224
Visit(const ColorMatrixFilterRowMajor255 & color_matrix_filter_row_major_255)1225 void Converter::Visit(
1226 const ColorMatrixFilterRowMajor255& color_matrix_filter_row_major_255) {
1227 Visit(color_matrix_filter_row_major_255.color_filter_matrix());
1228 }
1229
Visit(const ColorFilterMatrix & color_filter_matrix)1230 void Converter::Visit(const ColorFilterMatrix& color_filter_matrix) {
1231 static const int kColorFilterMatrixNumFields = 20;
1232 WriteNum(kColorFilterMatrixNumFields);
1233 WriteFields(color_filter_matrix);
1234 }
1235
Visit(const LayerDrawLooper & layer_draw_looper)1236 void Converter::Visit(const LayerDrawLooper& layer_draw_looper) {
1237 WriteNum(layer_draw_looper.layer_infos_size());
1238 int n = layer_draw_looper.layer_infos_size();
1239 #ifdef AVOID_MISBEHAVIOR
1240 n = 1; // Only write 1 to avoid timeouts.
1241 #endif
1242 for (int i = 0; i < n; ++i)
1243 Visit(layer_draw_looper.layer_infos(i));
1244 }
1245
Visit(const LayerInfo & layer_info)1246 void Converter::Visit(const LayerInfo& layer_info) {
1247 WriteNum(0);
1248 // Don't mutate these enum values or else a crash will be caused
1249 bool initial = dont_mutate_enum_;
1250 dont_mutate_enum_ = true;
1251 WriteFields(layer_info, 1, 4);
1252 dont_mutate_enum_ = initial;
1253 Visit(layer_info.paint());
1254 }
1255
Visit(const PairPathEffect & pair)1256 void Converter::Visit(const PairPathEffect& pair) {
1257 // Don't allow nesting of PairPathEffects for performance reasons
1258 if (pair_path_effect_depth_ >= 1)
1259 return;
1260 if (flattenable_depth_ > kFlattenableDepthLimit)
1261 return;
1262 pair_path_effect_depth_ += 1;
1263 flattenable_depth_ += 1;
1264
1265 std::string name;
1266 if (pair.type() == PairPathEffect::SUM)
1267 name = "SkSumPathEffect";
1268 else
1269 name = "SkComposePathEffect";
1270 WriteString(name);
1271 RecordSize();
1272
1273 Visit(pair.path_effect_1());
1274 Visit(pair.path_effect_2());
1275
1276 WriteBytesWritten(); // Flattenable size.
1277 CheckAlignment();
1278 pair_path_effect_depth_ -= 1;
1279 flattenable_depth_ -= 1;
1280 }
1281
1282 // See SkPathRef::writeToBuffer
Visit(const PathRef & path_ref)1283 void Converter::Visit(const PathRef& path_ref) {
1284 // Bound segment_mask to avoid timeouts and for proper behavior.
1285 const int32_t packed =
1286 (((path_ref.is_finite() & 1) << kIsFinite_SerializationShift) |
1287 (ToUInt8(path_ref.segment_mask()) << kSegmentMask_SerializationShift));
1288
1289 WriteNum(packed);
1290 WriteNum(0);
1291 std::vector<SkPoint> points;
1292 if (path_ref.verbs_size()) {
1293 WriteNum(path_ref.verbs_size() + 1);
1294 uint32_t num_points = 1; // The last move will add 1 point.
1295 uint32_t num_conics = 0;
1296 for (auto& verb : path_ref.verbs()) {
1297 switch (verb.value()) {
1298 case ValidVerb::kMove_Verb:
1299 case ValidVerb::kLine_Verb:
1300 num_points += 1;
1301 break;
1302 case ValidVerb::kConic_Verb:
1303 num_conics += 1;
1304 [[fallthrough]];
1305 case ValidVerb::kQuad_Verb:
1306 num_points += 2;
1307 break;
1308 case ValidVerb::kCubic_Verb:
1309 num_points += 3;
1310 break;
1311 case ValidVerb::kClose_Verb:
1312 break;
1313 default:
1314 NOTREACHED();
1315 }
1316 }
1317 WriteNum(num_points);
1318 WriteNum(num_conics);
1319 } else {
1320 WriteNum(0);
1321 WriteNum(0);
1322 WriteNum(0);
1323 }
1324
1325 for (auto& verb : path_ref.verbs()) {
1326 const uint8_t value = verb.value();
1327 WriteNum(value);
1328 }
1329 // Verbs must start (they are written backwards) with kMove_Verb (0).
1330 if (path_ref.verbs_size()) {
1331 uint8_t value = ValidVerb::kMove_Verb;
1332 WriteNum(value);
1333 }
1334
1335 // Write points
1336 for (auto& verb : path_ref.verbs()) {
1337 switch (verb.value()) {
1338 case ValidVerb::kMove_Verb:
1339 case ValidVerb::kLine_Verb: {
1340 Visit(verb.point1());
1341 AppendAsSkPoint(points, verb.point1());
1342 break;
1343 }
1344 case ValidVerb::kConic_Verb:
1345 case ValidVerb::kQuad_Verb: {
1346 Visit(verb.point1());
1347 Visit(verb.point2());
1348 AppendAsSkPoint(points, verb.point1());
1349 AppendAsSkPoint(points, verb.point2());
1350 break;
1351 }
1352 case ValidVerb::kCubic_Verb:
1353 Visit(verb.point1());
1354 Visit(verb.point2());
1355 Visit(verb.point3());
1356 AppendAsSkPoint(points, verb.point1());
1357 AppendAsSkPoint(points, verb.point2());
1358 AppendAsSkPoint(points, verb.point3());
1359 break;
1360 default:
1361 break;
1362 }
1363 }
1364 // Write point of the Move Verb we put at the end.
1365 if (path_ref.verbs_size()) {
1366 Visit(path_ref.first_verb().point1());
1367 AppendAsSkPoint(points, path_ref.first_verb().point1());
1368 }
1369
1370 // Write conic weights.
1371 for (auto& verb : path_ref.verbs()) {
1372 if (verb.value() == ValidVerb::kConic_Verb)
1373 WriteNum(verb.conic_weight());
1374 }
1375
1376 SkRect skrect;
1377 skrect.setBoundsCheck(&points[0], points.size());
1378 WriteNum(skrect.fLeft);
1379 WriteNum(skrect.fTop);
1380 WriteNum(skrect.fRight);
1381 WriteNum(skrect.fBottom);
1382 }
1383
AppendAsSkPoint(std::vector<SkPoint> & sk_points,const Point & proto_point) const1384 void Converter::AppendAsSkPoint(std::vector<SkPoint>& sk_points,
1385 const Point& proto_point) const {
1386 SkPoint sk_point;
1387 sk_point.fX = proto_point.x();
1388 sk_point.fY = proto_point.y();
1389 sk_points.push_back(sk_point);
1390 }
1391
Visit(const Path & path)1392 void Converter::Visit(const Path& path) {
1393 enum SerializationVersions {
1394 kPathPrivFirstDirection_Version = 1,
1395 kPathPrivLastMoveToIndex_Version = 2,
1396 kPathPrivTypeEnumVersion = 3,
1397 kCurrent_Version = 3
1398 };
1399
1400 enum FirstDirection {
1401 kCW_FirstDirection,
1402 kCCW_FirstDirection,
1403 kUnknown_FirstDirection,
1404 };
1405
1406 int32_t packed = (path.convexity() << kConvexity_SerializationShift) |
1407 (path.fill_type() << kFillType_SerializationShift) |
1408 (path.first_direction() << kDirection_SerializationShift) |
1409 (path.is_volatile() << kIsVolatile_SerializationShift) |
1410 kCurrent_Version;
1411
1412 // TODO(metzman): Allow writing as RRect.
1413 WriteNum(packed);
1414 WriteNum(path.last_move_to_index());
1415 Visit(path.path_ref());
1416 Pad(output_.size());
1417 CheckAlignment();
1418 }
1419
Visit(const BlurMaskFilter & blur_mask_filter)1420 void Converter::Visit(const BlurMaskFilter& blur_mask_filter) {
1421 // Sigma must be a finite number <= 0.
1422 float sigma = fabs(BoundFloat(blur_mask_filter.sigma()));
1423 sigma = sigma == 0 ? 1 : sigma;
1424 WriteNum(sigma);
1425 const bool old_value = dont_mutate_enum_;
1426 dont_mutate_enum_ = true;
1427 WriteFields(blur_mask_filter, 2, 3);
1428 dont_mutate_enum_ = old_value;
1429 Visit(blur_mask_filter.occluder());
1430 }
1431
CheckAlignment() const1432 void Converter::CheckAlignment() const {
1433 CHECK_EQ(output_.size() % 4, static_cast<size_t>(0));
1434 }
1435
Visit(const ShaderChild & shader)1436 void Converter::Visit(const ShaderChild& shader) {
1437 bool flattenable_visited = false;
1438 VISIT_ONEOF_FLATTENABLE(shader, color_4_shader);
1439 VISIT_ONEOF_FLATTENABLE(shader, color_filter_shader);
1440 VISIT_ONEOF_FLATTENABLE(shader, image_shader);
1441 VISIT_ONEOF_FLATTENABLE(shader, compose_shader);
1442 VISIT_ONEOF_FLATTENABLE(shader, empty_shader);
1443 VISIT_ONEOF_FLATTENABLE(shader, picture_shader);
1444 VISIT_ONEOF_FLATTENABLE(shader, perlin_noise_shader_impl);
1445 VISIT_ONEOF_FLATTENABLE(shader, local_matrix_shader);
1446 VISIT_ONEOF_FLATTENABLE(shader, linear_gradient);
1447 VISIT_ONEOF_FLATTENABLE(shader, radial_gradient);
1448 VISIT_ONEOF_FLATTENABLE(shader, sweep_gradient);
1449 VISIT_ONEOF_FLATTENABLE(shader, two_point_conical_gradient);
1450 VISIT_DEFAULT_FLATTENABLE(shader, color_shader);
1451 }
1452
Visit(const TwoPointConicalGradient & two_point_conical_gradient)1453 void Converter::Visit(
1454 const TwoPointConicalGradient& two_point_conical_gradient) {
1455 Visit(two_point_conical_gradient.parent());
1456 WriteFields(two_point_conical_gradient, 2, 5);
1457 }
1458
Visit(const LinearGradient & linear_gradient)1459 void Converter::Visit(const LinearGradient& linear_gradient) {
1460 Visit(linear_gradient.parent());
1461 WriteFields(linear_gradient, 2, 3);
1462 }
1463
Visit(const SweepGradient & sweep_gradient)1464 void Converter::Visit(const SweepGradient& sweep_gradient) {
1465 Visit(sweep_gradient.parent());
1466 WriteFields(sweep_gradient, 2, 4);
1467 }
1468
Visit(const RadialGradient & radial_gradient)1469 void Converter::Visit(const RadialGradient& radial_gradient) {
1470 Visit(radial_gradient.parent());
1471 WriteFields(radial_gradient, 2, 3);
1472 }
1473
1474 // Don't compile unfinished (dead) code in production.
1475 #ifdef DEVELOPMENT
1476 // ICC handling code is unfinished.
1477 // TODO(metzman): Finish implementing ICC.
1478
1479 // Copied from https://goo.gl/j78F6Z
1480 static constexpr uint32_t kTAG_lut8Type = SET_FOUR_BYTE_TAG('m', 'f', 't', '1');
1481 static constexpr uint32_t kTAG_lut16Type =
1482 SET_FOUR_BYTE_TAG('m', 'f', 't', '2');
Visit(const ICC & icc)1483 void Converter::Visit(const ICC& icc) {
1484 icc_base_ = output_.size();
1485 const uint32_t header_size = sizeof(uint8_t) * 4;
1486 uint32_t tag_count = 0;
1487 uint32_t tags_size = 0;
1488 if (icc.color_space().has_a2b0()) {
1489 if (icc.color_space().a2b0().has_lut8()) {
1490 tags_size =
1491 GetLut8Size(icc.color_space().a2b0().lut8()) + kICCTagTableEntrySize;
1492 } else if (icc.color_space().a2b0().has_lut16()) {
1493 tags_size = GetLut16Size(icc.color_space().a2b0().lut16()) +
1494 kICCTagTableEntrySize;
1495 } else {
1496 NOTREACHED();
1497 }
1498 tag_count = 1;
1499 } else {
1500 NOTREACHED();
1501 }
1502
1503 const uint32_t profile_size = sizeof(float) * 33 + tags_size;
1504 const uint32_t size = profile_size + sizeof(profile_size) + header_size;
1505 WriteNum(size);
1506
1507 // Header.
1508 WriteColorSpaceVersion();
1509 WriteNum(ToUInt8(icc.named()));
1510 WriteNum(ToUInt8(GammaNamed::kNonStandard_SkGammaNamed));
1511 WriteNum(kICC_Flag);
1512
1513 WriteNum(profile_size);
1514 WriteBigEndian(profile_size);
1515 WriteIgnoredFields(1);
1516 uint32_t version = icc.version() % 5;
1517 version <<= 24;
1518 WriteBigEndian(version);
1519 WriteBigEndian(kProfileLookupTable[icc.profile_class()]);
1520 WriteBigEndian(kInputColorSpaceLookupTable[icc.input_color_space()]);
1521 WriteBigEndian(kPCSLookupTable[icc.pcs()]);
1522 WriteIgnoredFields(3);
1523 WriteBigEndian(SET_FOUR_BYTE_TAG('a', 'c', 's', 'p'));
1524 WriteIgnoredFields(6);
1525 WriteBigEndian(icc.rendering_intent());
1526 WriteBigEndian(BoundIlluminant(icc.illuminant_x(), 0.96420f));
1527 WriteBigEndian(BoundIlluminant(icc.illuminant_y(), 1.00000f));
1528 WriteBigEndian(BoundIlluminant(icc.illuminant_z(), 0.82491f));
1529 WriteIgnoredFields(12);
1530 Visit(icc.color_space());
1531 const unsigned new_size = output_.size();
1532 CHECK_EQ(static_cast<size_t>(new_size - icc_base_), size + sizeof(size));
1533 }
1534
WriteTagSize(const char (& tag)[4],const size_t size)1535 void Converter::WriteTagSize(const char (&tag)[4], const size_t size) {
1536 WriteNum(tag);
1537 WriteNum(size);
1538 }
1539
1540 // Writes num as a big endian number.
1541 template <typename T>
WriteBigEndian(const T num)1542 void Converter::WriteBigEndian(const T num) {
1543 CHECK_LE(sizeof(T), static_cast<size_t>(4));
1544 uint8_t num_arr[sizeof(T)];
1545 memcpy(num_arr, &num, sizeof(T));
1546 uint8_t tmp1 = num_arr[0];
1547 uint8_t tmp2 = num_arr[3];
1548 num_arr[3] = tmp1;
1549 num_arr[0] = tmp2;
1550
1551 tmp1 = num_arr[1];
1552 tmp2 = num_arr[2];
1553 num_arr[2] = tmp1;
1554 num_arr[1] = tmp2;
1555
1556 for (size_t idx = 0; idx < sizeof(uint32_t); idx++)
1557 output_.push_back(num_arr[idx]);
1558 }
1559
Visit(const ICCColorSpace & icc_color_space)1560 void Converter::Visit(const ICCColorSpace& icc_color_space) {
1561 if (icc_color_space.has_xyz())
1562 Visit(icc_color_space.xyz());
1563 else if (icc_color_space.has_gray())
1564 Visit(icc_color_space.gray());
1565 else
1566 Visit(icc_color_space.a2b0());
1567 }
1568
Visit(const ICCXYZ & icc_xyz)1569 void Converter::Visit(const ICCXYZ& icc_xyz) {}
1570
Visit(const ICCGray & icc_gray)1571 void Converter::Visit(const ICCGray& icc_gray) {}
1572
Visit(const ICCA2B0 & icc_a2b0)1573 void Converter::Visit(const ICCA2B0& icc_a2b0) {
1574 if (icc_a2b0.has_lut8())
1575 Visit(icc_a2b0.lut8());
1576 else if (icc_a2b0.has_lut16())
1577 Visit(icc_a2b0.lut16());
1578 else
1579 Visit(icc_a2b0.atob());
1580 }
1581
Visit(const ICCA2B0AToB & icc_a2b0_atob)1582 void Converter::Visit(const ICCA2B0AToB& icc_a2b0_atob) {}
1583
GetClutGridPoints(const ICCA2B0Lut8 & icc_a2b0_lut8)1584 uint8_t Converter::GetClutGridPoints(const ICCA2B0Lut8& icc_a2b0_lut8) {
1585 uint8_t clut_grid_points = icc_a2b0_lut8.clut_grid_points();
1586 return clut_grid_points ? clut_grid_points > 1 : 2;
1587 }
1588
GetLut8Size(const ICCA2B0Lut8 & icc_a2b0_lut8)1589 uint32_t Converter::GetLut8Size(const ICCA2B0Lut8& icc_a2b0_lut8) {
1590 const uint32_t num_entries =
1591 GetClutGridPoints(icc_a2b0_lut8) * icc_a2b0_lut8.output_channels();
1592
1593 const uint32_t clut_bytes = kLut8Precision * num_entries * 4;
1594 const uint32_t gammas_size =
1595 kOneChannelGammasSize * (3 + icc_a2b0_lut8.input_channels());
1596 return kLut8InputSize + gammas_size + clut_bytes;
1597 }
1598
GetLut16Size(const ICCA2B0Lut16 & icc_a2b0_lut16)1599 uint32_t Converter::GetLut16Size(const ICCA2B0Lut16& icc_a2b0_lut16) {
1600 return 48;
1601 }
1602
Visit(const ICCA2B0Lut8 & icc_a2b0_lut8)1603 void Converter::Visit(const ICCA2B0Lut8& icc_a2b0_lut8) {
1604 // Write Header.
1605 WriteA2B0TagCommon();
1606
1607 // Write length.
1608 WriteBigEndian(GetLut8Size(icc_a2b0_lut8));
1609 // Specify type.
1610 WriteBigEndian(kTAG_lut8Type); // Bytes 0-3.
1611 WriteLut8(icc_a2b0_lut8);
1612 Visit(icc_a2b0_lut8.input_gammas_1());
1613 if (icc_a2b0_lut8.input_channels() == 2) {
1614 Visit(icc_a2b0_lut8.input_gammas_2());
1615 } else if (icc_a2b0_lut8.input_channels() == 3) {
1616 Visit(icc_a2b0_lut8.input_gammas_2());
1617 Visit(icc_a2b0_lut8.input_gammas_3());
1618 }
1619
1620 std::mt19937 gen(icc_a2b0_lut8.clut_bytes_seed());
1621 const uint32_t clut_bytes = GetClutGridPoints(icc_a2b0_lut8) *
1622 icc_a2b0_lut8.output_channels() * kLut8Precision *
1623 4;
1624 for (uint32_t i = 0; i < clut_bytes; i++)
1625 WriteUInt8(static_cast<uint8_t>(gen()));
1626
1627 Visit(icc_a2b0_lut8.output_gammas());
1628 }
1629
1630 // Write the parts of a lut8 used by a lut16.
WriteLut8(const ICCA2B0Lut8 & icc_a2b0_lut8)1631 void Converter::WriteLut8(const ICCA2B0Lut8& icc_a2b0_lut8) {
1632 // Bytes 4-7 are ignored.
1633 WriteUInt8(icc_a2b0_lut8.ignored_byte_4());
1634 WriteUInt8(icc_a2b0_lut8.ignored_byte_5());
1635 WriteUInt8(icc_a2b0_lut8.ignored_byte_6());
1636 WriteUInt8(icc_a2b0_lut8.ignored_byte_7());
1637 WriteUInt8(icc_a2b0_lut8.input_channels()); // Byte 8.
1638 WriteUInt8(icc_a2b0_lut8.output_channels()); // Byte 9.
1639 WriteUInt8(GetClutGridPoints(icc_a2b0_lut8)); // Byte 10.
1640 WriteUInt8(icc_a2b0_lut8.ignored_byte_11());
1641 Visit(icc_a2b0_lut8.matrix());
1642 }
1643
WriteA2B0TagCommon()1644 void Converter::WriteA2B0TagCommon() {
1645 WriteBigEndian(1); // ICC Tag Count
1646 WriteBigEndian(kTagLookupTable[ICCTag::kTAG_A2B0]);
1647 WriteBigEndian(GetCurrentICCOffset() - 4); // Offset.
1648 }
1649
WriteIgnoredFields(const int num_fields)1650 void Converter::WriteIgnoredFields(const int num_fields) {
1651 CHECK_GE(num_fields, 1);
1652 for (int counter = 0; counter < num_fields; counter++)
1653 WriteNum(0);
1654 }
1655
BoundIlluminant(float illuminant,const float num) const1656 int32_t Converter::BoundIlluminant(float illuminant, const float num) const {
1657 while (fabs(illuminant) >= 1) {
1658 illuminant /= 10;
1659 }
1660 const float result = num + 0.01f * illuminant;
1661 CHECK_LT(fabs(num - result), .01f);
1662 // 1.52587890625e-5f is a hardcoded value from SkFixed.h.
1663 return round(result / 1.52587890625e-5f);
1664 }
1665
GetCurrentICCOffset()1666 uint32_t Converter::GetCurrentICCOffset() {
1667 return output_.size() - icc_base_;
1668 }
1669
Visit(const ICCA2B0Lut16 & icc_a2b0_lut16)1670 void Converter::Visit(const ICCA2B0Lut16& icc_a2b0_lut16) {
1671 // Write Tag Header
1672 WriteA2B0TagCommon();
1673
1674 WriteBigEndian(GetLut16Size(icc_a2b0_lut16));
1675 WriteBigEndian(kTAG_lut16Type); // Bytes 0-3.
1676 WriteLut8(icc_a2b0_lut16.lut8());
1677
1678 uint16_t in_entries =
1679 icc_a2b0_lut16.in_table_entries() % (kMaxLut16GammaEntries + 1);
1680
1681 in_entries = in_entries ? in_entries >= 1 : 2;
1682
1683 uint16_t out_entries =
1684 icc_a2b0_lut16.out_table_entries() % (kMaxLut16GammaEntries + 1);
1685
1686 out_entries = out_entries ? out_entries >= 1 : 2;
1687
1688 WriteUInt16(static_cast<uint16_t>(in_entries));
1689 WriteUInt16(static_cast<uint16_t>(out_entries));
1690 }
1691
WriteTagHeader(const uint32_t tag,const uint32_t len)1692 void Converter::WriteTagHeader(const uint32_t tag, const uint32_t len) {
1693 WriteBigEndian(kTagLookupTable[tag]);
1694 WriteBigEndian(tag_offset_);
1695 WriteBigEndian(len);
1696 tag_offset_ += 12;
1697 }
1698
1699 // ImageInfo related code.
1700 // Copied from SkImageInfo.h
SkColorTypeBytesPerPixel(uint8_t ct)1701 static int SkColorTypeBytesPerPixel(uint8_t ct) {
1702 static const uint8_t gSize[] = {
1703 0, // Unknown
1704 1, // Alpha_8
1705 2, // RGB_565
1706 2, // ARGB_4444
1707 4, // RGBA_8888
1708 4, // BGRA_8888
1709 1, // kGray_8
1710 8, // kRGBA_F16
1711 };
1712 return gSize[ct];
1713 }
1714
ComputeMinByteSize(int32_t width,int32_t height,ImageInfo::AlphaType alpha_type) const1715 size_t Converter::ComputeMinByteSize(int32_t width,
1716 int32_t height,
1717 ImageInfo::AlphaType alpha_type) const {
1718 width = Abs(width);
1719 height = Abs(height);
1720
1721 if (!height)
1722 return 0;
1723 uint32_t bytes_per_pixel = SkColorTypeBytesPerPixel(alpha_type);
1724 uint64_t bytes_per_row_64 = width * bytes_per_pixel;
1725 CHECK(bytes_per_row_64 <= INT32_MAX);
1726 int32_t bytes_per_row = bytes_per_row_64;
1727 size_t num_bytes = (height - 1) * bytes_per_row + bytes_per_pixel * width;
1728 return num_bytes;
1729 }
1730
GetNumPixelBytes(const ImageInfo & image_info,int32_t width,int32_t height)1731 std::tuple<int32_t, int32_t, int32_t> Converter::GetNumPixelBytes(
1732 const ImageInfo& image_info,
1733 int32_t width,
1734 int32_t height) {
1735 // Returns a value for pixel bytes that is divisible by four by modifying
1736 // image_info.width() as needed until the computed min byte size is divisible
1737 // by four.
1738 size_t num_bytes_64 =
1739 ComputeMinByteSize(width, height, image_info.alpha_type());
1740 CHECK(num_bytes_64 <= INT32_MAX);
1741 int32_t num_bytes = num_bytes_64;
1742 bool subtract = (num_bytes >= 5);
1743 while (num_bytes % 4) {
1744 if (subtract)
1745 width -= 1;
1746 else
1747 width += 1;
1748 num_bytes_64 = ComputeMinByteSize(width, height, image_info.alpha_type());
1749 CHECK(num_bytes_64 <= INT32_MAX);
1750 num_bytes = num_bytes_64;
1751 }
1752 return std::make_tuple(num_bytes, width, height);
1753 }
1754
Visit(const ImageInfo & image_info,const int32_t width,const int32_t height)1755 void Converter::Visit(const ImageInfo& image_info,
1756 const int32_t width,
1757 const int32_t height) {
1758 WriteNum(width);
1759 WriteNum(height);
1760 uint32_t packed = (image_info.alpha_type() << 8) | image_info.color_type();
1761 WriteNum(packed);
1762 Visit(image_info.color_space());
1763 }
1764 #endif // DEVELOPMENT
1765
Visit(const ColorSpaceChild & color_space)1766 void Converter::Visit(const ColorSpaceChild& color_space) {
1767 // ICC code is not finished.
1768 #ifdef DEVELOPMENT
1769 if (color_space.has_icc())
1770 Visit(color_space.icc());
1771 else if (color_space.has_transfer_fn())
1772 #else
1773 if (color_space.has_transfer_fn())
1774 #endif // DEVELOPMENT
1775 Visit(color_space.transfer_fn());
1776 else if (color_space.has_color_space__xyz())
1777 Visit(color_space.color_space__xyz());
1778 else
1779 Visit(color_space.named());
1780 }
1781
1782 template <typename T>
WriteUInt8(T num)1783 void Converter::WriteUInt8(T num) {
1784 CHECK_LT(num, 256);
1785 output_.push_back(static_cast<uint8_t>(num));
1786 }
1787
WriteUInt16(uint16_t num)1788 void Converter::WriteUInt16(uint16_t num) {
1789 char num_arr[2];
1790 memcpy(num_arr, &num, 2);
1791 for (size_t idx = 0; idx < 2; idx++)
1792 output_.push_back(num_arr[idx]);
1793 }
1794
Visit(const TransferFn & transfer_fn)1795 void Converter::Visit(const TransferFn& transfer_fn) {
1796 const size_t size_64 =
1797 (12 * sizeof(float) + 7 * sizeof(float) + 4 * sizeof(uint8_t));
1798 CHECK_LT(size_64, UINT32_MAX);
1799 WriteNum((uint32_t)size_64);
1800 // Header
1801 WriteColorSpaceVersion();
1802 WriteNum(ToUInt8(transfer_fn.named()));
1803 WriteNum(ToUInt8(GammaNamed::kNonStandard_SkGammaNamed));
1804 WriteNum(ToUInt8(kTransferFn_Flag));
1805
1806 WriteFields(transfer_fn, 2);
1807 }
1808
WriteColorSpaceVersion()1809 void Converter::WriteColorSpaceVersion() {
1810 // See SkColorSpace::writeToMemory for why this always writes k0_Version.
1811 // TODO(metzman): Figure out how to keep this up to date.
1812 WriteNum(k0_Version);
1813 }
1814
Visit(const ColorSpace_XYZ & color_space__xyz)1815 void Converter::Visit(const ColorSpace_XYZ& color_space__xyz) {
1816 const uint32_t size = 12 * sizeof(float) + sizeof(uint8_t) * 4;
1817 WriteNum(size);
1818 // Header
1819 WriteColorSpaceVersion();
1820 WriteNum(ToUInt8(Named::kSRGB_Named));
1821 WriteNum(ToUInt8(color_space__xyz.gamma_named()));
1822 // See SkColorSpace.cpp:Deserialize (around here: https://goo.gl/R9xQ2B)
1823 WriteNum(ToUInt8(kMatrix_Flag));
1824
1825 Visit(color_space__xyz.three_by_four());
1826 }
1827
Visit(const ColorSpaceNamed & color_space_named)1828 void Converter::Visit(const ColorSpaceNamed& color_space_named) {
1829 const uint32_t size = sizeof(uint8_t) * 4;
1830 WriteNum(size);
1831 // Header
1832 WriteColorSpaceVersion();
1833 WriteNum(ToUInt8(color_space_named.named()));
1834 WriteNum(ToUInt8(color_space_named.gamma_named()));
1835 WriteNum(ToUInt8(0));
1836 }
1837
Visit(const ImageData & image_data)1838 void Converter::Visit(const ImageData& image_data) {
1839 WriteNum(-4 * image_data.data_size());
1840 for (uint32_t element : image_data.data())
1841 WriteNum(element);
1842 }
1843
Visit(const Image & image)1844 void Converter::Visit(const Image& image) {
1845 // Width and height must be greater than 0.
1846 WriteNum(std::max(1, BoundNum(Abs(image.width()))));
1847 WriteNum(std::max(1, BoundNum(Abs(image.height()))));
1848
1849 Visit(image.data());
1850 if (image.data().data_size()) {
1851 // origin_x and origin_y need to be positive.
1852 WriteNum(Abs(image.origin_x()));
1853 WriteNum(Abs(image.origin_y()));
1854 }
1855 }
1856
Visit(const ImageShader & image_shader)1857 void Converter::Visit(const ImageShader& image_shader) {
1858 WriteFields(image_shader, 1, 3);
1859 Visit(image_shader.image());
1860 }
1861
Visit(const ColorFilterShader & color_filter_shader)1862 void Converter::Visit(const ColorFilterShader& color_filter_shader) {
1863 Visit(color_filter_shader.shader());
1864 Visit(color_filter_shader.filter());
1865 }
1866
Visit(const ComposeShader & compose_shader)1867 void Converter::Visit(const ComposeShader& compose_shader) {
1868 if (flattenable_depth_ > kFlattenableDepthLimit)
1869 return;
1870 flattenable_depth_ += 1;
1871 Visit(compose_shader.dst());
1872 Visit(compose_shader.src());
1873 WriteFields(compose_shader, 3, 4);
1874 flattenable_depth_ -= 1;
1875 }
1876
Visit(const LocalMatrixShader & local_matrix_shader)1877 void Converter::Visit(const LocalMatrixShader& local_matrix_shader) {
1878 Visit(local_matrix_shader.matrix());
1879 Visit(local_matrix_shader.proxy_shader());
1880 }
1881
Visit(const Color4Shader & color_4_shader)1882 void Converter::Visit(const Color4Shader& color_4_shader) {
1883 WriteNum(color_4_shader.color());
1884 // TODO(metzman): Implement ColorSpaces when skia does. See
1885 // https://goo.gl/c6YAq7
1886 WriteBool(false);
1887 }
1888
Pad(const size_t write_size)1889 void Converter::Pad(const size_t write_size) {
1890 if (write_size % 4 == 0)
1891 return;
1892 for (size_t padding_count = 0; (padding_count + write_size) % 4 != 0;
1893 padding_count++)
1894 output_.push_back('\0');
1895 }
1896
Visit(const Path1DPathEffect & path_1d_path_effect)1897 void Converter::Visit(const Path1DPathEffect& path_1d_path_effect) {
1898 WriteNum(path_1d_path_effect.advance());
1899 if (path_1d_path_effect.advance()) {
1900 Visit(path_1d_path_effect.path());
1901 WriteFields(path_1d_path_effect, 3, 4);
1902 }
1903 }
1904
PreVisitFlattenable(const std::string & name)1905 bool Converter::PreVisitFlattenable(const std::string& name) {
1906 if (flattenable_depth_ > kFlattenableDepthLimit)
1907 return false;
1908 flattenable_depth_ += 1;
1909 WriteString(name);
1910 RecordSize();
1911 return true;
1912 }
1913
PostVisitFlattenable()1914 void Converter::PostVisitFlattenable() {
1915 WriteBytesWritten(); // Flattenable size.
1916 CheckAlignment();
1917 flattenable_depth_ -= 1;
1918 }
1919
Visit(const DashImpl & dash_impl)1920 void Converter::Visit(const DashImpl& dash_impl) {
1921 WriteNum(BoundFloat(dash_impl.phase()));
1922 int num_left = dash_impl.intervals_size();
1923 int size = dash_impl.intervals_size() + 2;
1924 if (size % 2) {
1925 num_left = num_left - 1;
1926 size = size - 1;
1927 }
1928 WriteNum(size);
1929 WriteNum(fabs(BoundFloat(dash_impl.interval_1())));
1930 WriteNum(fabs(BoundFloat(dash_impl.interval_2())));
1931 for (int idx = 0; idx < num_left; idx++)
1932 WriteNum(fabs(BoundFloat(dash_impl.intervals().Get(idx))));
1933 }
1934
Visit(const Path2DPathEffect & path_2d_path_effect)1935 void Converter::Visit(const Path2DPathEffect& path_2d_path_effect) {
1936 Visit(path_2d_path_effect.matrix());
1937 Visit(path_2d_path_effect.path());
1938 }
1939
Visit(const PathEffectChild & path_effect)1940 void Converter::Visit(const PathEffectChild& path_effect) {
1941 bool flattenable_visited = false;
1942 // Visit(pair_path_effect) implements the functionality of
1943 // VisitFlattenable by writing the correct names itself.
1944 if (path_effect.has_pair_path_effect()) {
1945 Visit(path_effect.pair_path_effect());
1946 flattenable_visited = true;
1947 }
1948 VISIT_ONEOF_FLATTENABLE(path_effect, path_2d_path_effect);
1949 VISIT_ONEOF_FLATTENABLE(path_effect, line_2d_path_effect);
1950 VISIT_ONEOF_FLATTENABLE(path_effect, corner_path_effect);
1951 VISIT_ONEOF_FLATTENABLE(path_effect, discrete_path_effect);
1952 VISIT_ONEOF_FLATTENABLE(path_effect, path_1d_path_effect);
1953 VISIT_DEFAULT_FLATTENABLE(path_effect, dash_impl);
1954 }
1955
Visit(const DiscretePathEffect & discrete_path_effect)1956 void Converter::Visit(const DiscretePathEffect& discrete_path_effect) {
1957 // Don't write seg_length because it causes too many timeouts.
1958 // See SkScalar.h for why this value is picked
1959 const float SK_ScalarNotNearlyZero = 1.0 / (1 << 11);
1960 WriteNum(SK_ScalarNotNearlyZero);
1961 // Found in testing to be a good value that is unlikely to cause timeouts.
1962 float perterb = discrete_path_effect.perterb();
1963 // Do this to avoid timeouts.
1964 if (perterb < 1)
1965 perterb += 1;
1966 WriteNum(perterb);
1967 WriteNum(discrete_path_effect.seed_assist());
1968 }
1969
Visit(const MaskFilterChild & mask_filter)1970 void Converter::Visit(const MaskFilterChild& mask_filter) {
1971 bool flattenable_visited = false;
1972 VISIT_ONEOF_FLATTENABLE(mask_filter, emboss_mask_filter);
1973 VISIT_DEFAULT_FLATTENABLE(mask_filter, blur_mask_filter_impl);
1974 }
1975
1976 template <typename T>
ToUInt8(const T input_num) const1977 uint8_t Converter::ToUInt8(const T input_num) const {
1978 return input_num % (UINT8_MAX + 1);
1979 }
1980
Visit(const EmbossMaskFilterLight & emboss_mask_filter_light)1981 void Converter::Visit(const EmbossMaskFilterLight& emboss_mask_filter_light) {
1982 // This is written as a byte array, so first write its size, direction_* are
1983 // floats, fPad is uint16_t and ambient and specular are uint8_ts.
1984 const uint32_t byte_array_size =
1985 (3 * sizeof(float) + sizeof(uint16_t) + (2 * sizeof(uint8_t)));
1986 WriteNum(byte_array_size);
1987 WriteFields(emboss_mask_filter_light, 1, 3);
1988 const uint16_t pad = 0;
1989 WriteNum(pad); // fPad = 0;
1990 WriteNum(ToUInt8(emboss_mask_filter_light.ambient()));
1991 WriteNum(ToUInt8(emboss_mask_filter_light.specular()));
1992 }
1993
Visit(const EmbossMaskFilter & emboss_mask_filter)1994 void Converter::Visit(const EmbossMaskFilter& emboss_mask_filter) {
1995 Visit(emboss_mask_filter.light());
1996 WriteNum(emboss_mask_filter.blur_sigma());
1997 }
1998
Visit(const RecordingData & recording_data)1999 void Converter::Visit(const RecordingData& recording_data) {
2000 WriteNum(kSkPictReaderTag);
2001 Visit(recording_data.paints());
2002 }
2003
Visit(const PictureTagChild & picture_tag)2004 void Converter::Visit(const PictureTagChild& picture_tag) {
2005 VISIT_OPT_TAG(paint, SET_FOUR_BYTE_TAG('p', 'n', 't', ' '));
2006 VISIT_OPT_TAG(path, SET_FOUR_BYTE_TAG('p', 't', 'h', ' '));
2007 VISIT_OPT_TAG(image, SET_FOUR_BYTE_TAG('i', 'm', 'a', 'g'));
2008 VISIT_OPT_TAG(vertices, SET_FOUR_BYTE_TAG('v', 'e', 'r', 't'));
2009 VISIT_OPT_TAG(text_blob, SET_FOUR_BYTE_TAG('b', 'l', 'o', 'b'));
2010 }
2011
Visit(const Picture & picture)2012 void Converter::Visit(const Picture& picture) {
2013 Visit(picture.info());
2014 WriteNum(1);
2015 Visit(picture.data());
2016 }
2017
Visit(const Matrix & matrix,bool is_local)2018 void Converter::Visit(const Matrix& matrix, bool is_local) {
2019 // Avoid OOMs by making sure that matrix fields aren't tiny fractions.
2020 WriteMatrixField(matrix.val1());
2021 WriteMatrixField(matrix.val2());
2022 WriteMatrixField(matrix.val3());
2023 WriteMatrixField(matrix.val4());
2024 WriteMatrixField(matrix.val5());
2025 WriteMatrixField(matrix.val6());
2026 // See SkLocalMatrixImageFilter.cpp:20
2027 if (is_local)
2028 WriteNum(0.0f);
2029 else
2030 WriteMatrixField(matrix.val7());
2031 if (is_local)
2032 WriteNum(0.0f);
2033 else
2034 WriteMatrixField(matrix.val8());
2035 if (is_local)
2036 WriteNum(1.0f);
2037 else
2038 WriteMatrixField(matrix.val9());
2039 }
2040
WriteMatrixField(float field_value)2041 void Converter::WriteMatrixField(float field_value) {
2042 // Don't let the field values be tiny fractions.
2043 field_value = BoundFloat(field_value);
2044 while ((field_value > 0 && field_value < 1e-5) ||
2045 (field_value < 0 && field_value > -1e-5))
2046 field_value /= 10.0;
2047 WriteNum(field_value);
2048 }
2049
Visit(const MatrixImageFilter & matrix_image_filter)2050 void Converter::Visit(const MatrixImageFilter& matrix_image_filter) {
2051 Visit(matrix_image_filter.image_filter_parent(), 1);
2052 Visit(matrix_image_filter.transform());
2053 WriteNum(matrix_image_filter.filter_quality());
2054 }
2055
Visit(const PaintImageFilter & paint_image_filter)2056 void Converter::Visit(const PaintImageFilter& paint_image_filter) {
2057 Visit(paint_image_filter.image_filter_parent(), 0);
2058 Visit(paint_image_filter.paint());
2059 }
2060
GetRandomFloat(std::mt19937 * gen_ptr)2061 float Converter::GetRandomFloat(std::mt19937* gen_ptr) {
2062 CHECK(gen_ptr);
2063 std::mt19937 gen = *gen_ptr;
2064 const float positive_random_float = gen();
2065 const bool is_negative = gen() % 2 == 1;
2066 if (is_negative)
2067 return -positive_random_float;
2068 return positive_random_float;
2069 }
2070
GetRandomFloat(float seed,float min,float max)2071 float Converter::GetRandomFloat(float seed, float min, float max) {
2072 std::mt19937 gen(seed);
2073 auto next_after_max = std::nextafter(max, std::numeric_limits<float>::max());
2074 std::uniform_real_distribution<> distribution(min, next_after_max);
2075 float result = distribution(gen);
2076 CHECK_LE(result, 1.0);
2077 CHECK_GE(result, -1.0);
2078 return result;
2079 }
2080
WriteFields(const Message & msg,const unsigned start,const unsigned end)2081 void Converter::WriteFields(const Message& msg,
2082 const unsigned start,
2083 const unsigned end) {
2084 // Do basic validation on start and end. If end == 0, then write all
2085 // fields left in msg (after start).
2086 CHECK_GE(start, static_cast<unsigned>(1));
2087 CHECK_GE(end, static_cast<unsigned>(0));
2088 CHECK(start <= end || end == 0);
2089 const Descriptor* descriptor = msg.GetDescriptor();
2090 CHECK(descriptor);
2091 const Reflection* reflection = msg.GetReflection();
2092 CHECK(reflection);
2093 int field_count = descriptor->field_count();
2094 CHECK_LE(end, static_cast<unsigned>(field_count));
2095 const bool write_until_last = end == 0;
2096 const unsigned last_field_to_write = write_until_last ? field_count : end;
2097
2098 for (auto field_num = start; field_num <= last_field_to_write; field_num++) {
2099 const FieldDescriptor* field_descriptor =
2100 descriptor->FindFieldByNumber(field_num);
2101 CHECK(field_descriptor);
2102 const auto& tp = field_descriptor->cpp_type();
2103 if (field_descriptor->is_repeated()) {
2104 switch (tp) {
2105 case FieldDescriptor::CPPTYPE_UINT32: {
2106 const size_t num_elements =
2107 reflection->FieldSize(msg, field_descriptor);
2108 for (size_t idx = 0; idx < num_elements; idx++) {
2109 WriteNum(reflection->GetRepeatedUInt32(msg, field_descriptor, idx));
2110 }
2111 break;
2112 }
2113 case FieldDescriptor::CPPTYPE_FLOAT: {
2114 const size_t num_elements =
2115 reflection->FieldSize(msg, field_descriptor);
2116 for (size_t idx = 0; idx < num_elements; idx++) {
2117 WriteNum(reflection->GetRepeatedFloat(msg, field_descriptor, idx));
2118 }
2119 break;
2120 }
2121 case FieldDescriptor::CPPTYPE_MESSAGE: {
2122 Visit(reflection->GetRepeatedPtrField<google::protobuf::Message>(
2123 msg, field_descriptor));
2124 break;
2125 }
2126 default: { NOTREACHED(); }
2127 }
2128 continue;
2129 // Skip field if it is optional and it is unset.
2130 } else if (!field_descriptor->is_required() &&
2131 !reflection->HasField(msg, field_descriptor)) {
2132 continue;
2133 }
2134
2135 // Field is either required or it is optional but is set, so write it:
2136 switch (tp) {
2137 case FieldDescriptor::CPPTYPE_INT32:
2138 WriteNum(BoundNum(reflection->GetInt32(msg, field_descriptor)));
2139 break;
2140 case FieldDescriptor::CPPTYPE_UINT32:
2141 WriteNum(BoundNum(reflection->GetUInt32(msg, field_descriptor)));
2142 break;
2143 case FieldDescriptor::CPPTYPE_FLOAT:
2144 WriteNum(BoundFloat(reflection->GetFloat(msg, field_descriptor)));
2145 break;
2146 case FieldDescriptor::CPPTYPE_BOOL:
2147 WriteBool(reflection->GetBool(msg, field_descriptor));
2148 break;
2149 case FieldDescriptor::CPPTYPE_ENUM:
2150 WriteEnum(msg, reflection, field_descriptor);
2151 break;
2152 case FieldDescriptor::CPPTYPE_STRING:
2153 WriteString(reflection->GetString(msg, field_descriptor));
2154 break;
2155 case FieldDescriptor::CPPTYPE_MESSAGE:
2156 Visit(reflection->GetMessage(msg, field_descriptor));
2157 break;
2158 default:
2159 NOTREACHED();
2160 }
2161 }
2162 CHECK(!write_until_last ||
2163 !descriptor->FindFieldByNumber(last_field_to_write + 1));
2164 }
2165
WriteEnum(const Message & msg,const Reflection * reflection,const FieldDescriptor * field_descriptor)2166 void Converter::WriteEnum(const Message& msg,
2167 const Reflection* reflection,
2168 const FieldDescriptor* field_descriptor) {
2169 enum MutationState {
2170 MORE = 1,
2171 LESS = 2,
2172 };
2173
2174 const int value = reflection->GetEnumValue(msg, field_descriptor);
2175 if (dont_mutate_enum_) {
2176 WriteNum(value);
2177 return;
2178 }
2179
2180 const int should_mutate = enum_mutator_chance_distribution_(rand_gen_);
2181 if (should_mutate != MORE && should_mutate != LESS) {
2182 // Don't mutate, just write it.
2183 WriteNum(value);
2184 return;
2185 }
2186
2187 const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
2188 CHECK(enum_descriptor);
2189
2190 const EnumValueDescriptor* min_value_descriptor = enum_descriptor->value(0);
2191 CHECK(min_value_descriptor);
2192 const int min_value = min_value_descriptor->number();
2193
2194 const int num_values = enum_descriptor->value_count();
2195 const EnumValueDescriptor* max_value_descriptor =
2196 enum_descriptor->value(num_values - 1);
2197 CHECK(max_value_descriptor);
2198 const int max_value = max_value_descriptor->number();
2199
2200 // If we are trying to write less than the min value, but it is 0, just write
2201 // than the max instead.
2202 if (should_mutate == LESS && min_value != 0) {
2203 std::uniform_int_distribution<> value_distribution(-min_value,
2204 min_value - 1);
2205
2206 const int new_value = value_distribution(rand_gen_);
2207 CHECK_EQ(enum_descriptor->FindValueByNumber(new_value), nullptr);
2208 WriteNum(new_value);
2209 // Don't also write an enum that is larger than it is supposed to be.
2210 return;
2211 }
2212 const int distribution_lower_bound = max_value + 1;
2213 CHECK_GT(distribution_lower_bound, max_value);
2214 const int distribution_upper_bound = 2 * max_value;
2215 CHECK_GE(distribution_upper_bound, distribution_lower_bound);
2216 std::uniform_int_distribution<> value_distribution(distribution_lower_bound,
2217 distribution_upper_bound);
2218
2219 const int new_value = value_distribution(rand_gen_);
2220 CHECK_EQ(enum_descriptor->FindValueByNumber(new_value), nullptr);
2221 WriteNum(new_value);
2222 }
2223
Abs(const int val) const2224 int Converter::Abs(const int val) const {
2225 if (val == INT_MIN)
2226 return abs(val + 1);
2227 return abs(val);
2228 }
2229
Visit(const Vertices & vertices)2230 void Converter::Visit(const Vertices& vertices) {
2231 // Note that the size is only needed when this is deserialized as part of a
2232 // picture image filter. Since this the only way our fuzzer can deserialize
2233 // Vertices, we always write the size.
2234 RecordSize();
2235 int32_t packed = vertices.mode() | kMode_Mask;
2236 packed = packed ? !vertices.has_texs() : packed | kHasTexs_Mask;
2237 packed = packed ? !vertices.has_colors() : packed | kHasColors_Mask;
2238 WriteNum(packed);
2239 WriteNum(vertices.vertex_text_colors_size());
2240 WriteNum(vertices.indices_size());
2241 for (auto vertex_text_color : vertices.vertex_text_colors())
2242 Visit(vertex_text_color.vertex());
2243
2244 if (vertices.has_texs()) {
2245 for (auto vertex_text_color : vertices.vertex_text_colors())
2246 Visit(vertex_text_color.tex());
2247 }
2248
2249 if (vertices.has_colors()) {
2250 for (auto vertex_text_color : vertices.vertex_text_colors())
2251 Visit(vertex_text_color.color());
2252 }
2253 WriteBytesWritten();
2254 }
2255
Visit(const TextBlob & text_blob)2256 void Converter::Visit(const TextBlob& text_blob) {
2257 Visit(text_blob.bounds());
2258 int num_glyphs = 2 + text_blob.glyph_pos_clusters_size();
2259 if (num_glyphs % 2 != 0)
2260 num_glyphs--;
2261 CHECK_EQ(num_glyphs % 2, 0);
2262
2263 WriteNum(num_glyphs);
2264 WriteUInt8(text_blob.glyph_positioning());
2265 WriteUInt8(text_blob.extended());
2266 WriteUInt16(0); // padding
2267
2268 if (text_blob.extended())
2269 WriteNum(Abs(text_blob.text_size()));
2270 Visit(text_blob.offset());
2271
2272 Paint paint;
2273 paint.CopyFrom(text_blob.paint());
2274 paint.set_text_encoding(Paint::kGlyphID_TextEncoding);
2275 paint.set_text_size(text_blob.text_size());
2276 Visit(paint);
2277
2278 // Byte array size.
2279 WriteNum(sizeof(uint16_t) * num_glyphs);
2280 WriteUInt16(text_blob.glyph_pos_cluster_1().glyph());
2281 WriteUInt16(text_blob.glyph_pos_cluster_2().glyph());
2282 // Ensure 4-byte alignment doesn't get messed up by writing an odd number of
2283 // glyphs.
2284 int idx = 2;
2285 for (auto& glyph_pos_cluster : text_blob.glyph_pos_clusters()) {
2286 if (idx++ == num_glyphs)
2287 break;
2288 WriteUInt16(glyph_pos_cluster.glyph());
2289 }
2290
2291 WriteNum(sizeof(float) * num_glyphs * text_blob.glyph_positioning());
2292 idx = 2;
2293 if (text_blob.glyph_positioning() == TextBlob::kHorizontal_Positioning) {
2294 WriteNum(text_blob.glyph_pos_cluster_1().position_1());
2295 WriteNum(text_blob.glyph_pos_cluster_2().position_1());
2296 } else if (text_blob.glyph_positioning() == TextBlob::kFull_Positioning) {
2297 WriteNum(text_blob.glyph_pos_cluster_1().position_1());
2298 WriteNum(text_blob.glyph_pos_cluster_1().position_2());
2299 WriteNum(text_blob.glyph_pos_cluster_2().position_1());
2300 WriteNum(text_blob.glyph_pos_cluster_2().position_2());
2301 }
2302 for (auto& glyph_pos_cluster : text_blob.glyph_pos_clusters()) {
2303 if (idx++ == num_glyphs)
2304 break;
2305 if (text_blob.glyph_positioning() == TextBlob::kHorizontal_Positioning) {
2306 WriteNum(glyph_pos_cluster.position_1());
2307 } else if (text_blob.glyph_positioning() == TextBlob::kFull_Positioning) {
2308 WriteNum(glyph_pos_cluster.position_1());
2309 WriteNum(glyph_pos_cluster.position_2());
2310 }
2311 }
2312
2313 if (text_blob.extended()) {
2314 // Write clusters.
2315 WriteNum(text_blob.glyph_pos_cluster_1().cluster());
2316 WriteNum(text_blob.glyph_pos_cluster_2().cluster());
2317 WriteNum(sizeof(uint32_t) * num_glyphs);
2318 idx = 2;
2319 for (auto& glyph_pos_cluster : text_blob.glyph_pos_clusters()) {
2320 if (idx++ == num_glyphs)
2321 break;
2322 WriteNum(glyph_pos_cluster.cluster());
2323 }
2324 WriteArray(text_blob.text(), text_blob.text_size());
2325 }
2326
2327 // No more glyphs.
2328 WriteNum(0);
2329 }
2330
IsBlacklisted(const std::string & field_name) const2331 bool Converter::IsBlacklisted(const std::string& field_name) const {
2332 #ifndef AVOID_MISBEHAVIOR
2333 // Don't blacklist misbehaving flattenables.
2334 return false;
2335 #else
2336 return base::Contains(kMisbehavedFlattenableBlacklist, field_name);
2337 #endif // AVOID_MISBEHAVIOR
2338 }
2339 } // namespace skia_image_filter_proto_converter
2340