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