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