blob: 2fde8b5dac591cbdf639a9e41df77a979edffb95 [file] [log] [blame]
Hal Canary24ac42b2017-02-14 13:35:14 -05001/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "Fuzz.h"
Hal Canary24ac42b2017-02-14 13:35:14 -05009
10// CORE
11#include "SkCanvas.h"
12#include "SkColorFilter.h"
Kevin Lubick1ac8fd22017-03-01 10:42:45 -050013#include "SkDebugCanvas.h"
14#include "SkDocument.h"
Hal Canary671e4422017-02-27 13:36:38 -050015#include "SkFontMgr.h"
Hal Canary24ac42b2017-02-14 13:35:14 -050016#include "SkImageFilter.h"
17#include "SkMaskFilter.h"
Kevin Lubick1ac8fd22017-03-01 10:42:45 -050018#include "SkNullCanvas.h"
Hal Canary24ac42b2017-02-14 13:35:14 -050019#include "SkPathEffect.h"
20#include "SkPictureRecorder.h"
21#include "SkRegion.h"
Kevin Lubick1ac8fd22017-03-01 10:42:45 -050022#include "SkSurface.h"
Hal Canary24ac42b2017-02-14 13:35:14 -050023#include "SkTypeface.h"
24
25// EFFECTS
26#include "SkGaussianEdgeShader.h"
27#include "SkGradientShader.h"
28#include "SkPerlinNoiseShader.h"
29
30// SRC
31#include "SkUtils.h"
32
Kevin Lubick1ac8fd22017-03-01 10:42:45 -050033// MISC
34
35#include <iostream>
36
Hal Canary24ac42b2017-02-14 13:35:14 -050037// TODO:
38// SkCanvas::drawTextBlob
39// SkCanvas::drawTextRSXform
Hal Canary24ac42b2017-02-14 13:35:14 -050040// SkColorFilter
41// SkImageFilter
42// SkMaskFilter
43// SkPathEffect
Hal Canary24ac42b2017-02-14 13:35:14 -050044
45template <typename T, void (SkPaint::*S)(T)>
46inline void fuzz_input(Fuzz* fuzz, SkPaint* paint) {
47 T value;
48 fuzz->next(&value);
49 (paint->*S)(value);
50}
51
52template <typename T, void (SkPaint::*S)(T)>
53inline void fuzz_enum_input(Fuzz* fuzz, SkPaint* paint, T rmin, T rmax) {
54 using U = skstd::underlying_type_t<T>;
55 U value;
56 fuzz->nextRange(&value, (U)rmin, (U)rmax);
57 (paint->*S)((T)value);
58}
59
60// be careful: `foo(make_bool(f), make_bool(f))` is undefined.
61static bool make_bool(Fuzz* fuzz) {
62 bool b;
63 fuzz->next(&b);
64 return b;
65}
66
Hal Canaryce540ea2017-03-06 08:30:44 -050067// We don't always want to test NaNs.
68static void fuzz_nice_float(Fuzz* fuzz, float* f) {
69 fuzz->next(f);
70 if (*f != *f || ::fabs(*f) > 1.0e35f) {
71 *f = 0.0f;
72 }
73}
Hal Canary24ac42b2017-02-14 13:35:14 -050074
Hal Canaryce540ea2017-03-06 08:30:44 -050075template <typename... Args>
76void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) {
77 fuzz_nice_float(fuzz, f);
78 fuzz_nice_float(fuzz, rest...);
79}
80
81static void fuzz_path(Fuzz* fuzz, SkPath* path, int maxOps) {
82 if (maxOps < 2) {
83 maxOps = 2;
84 }
Hal Canary24ac42b2017-02-14 13:35:14 -050085 uint8_t fillType;
86 fuzz->nextRange(&fillType, 0, (uint8_t)SkPath::kInverseEvenOdd_FillType);
87 path->setFillType((SkPath::FillType)fillType);
88 uint8_t numOps;
Hal Canaryce540ea2017-03-06 08:30:44 -050089 fuzz->nextRange(&numOps, 2, maxOps);
Hal Canary24ac42b2017-02-14 13:35:14 -050090 for (uint8_t i = 0; i < numOps; ++i) {
91 uint8_t op;
92 fuzz->nextRange(&op, 0, 6);
93 SkScalar a, b, c, d, e, f;
94 switch (op) {
95 case 0:
Hal Canaryce540ea2017-03-06 08:30:44 -050096 fuzz_nice_float(fuzz, &a, &b);
Hal Canary24ac42b2017-02-14 13:35:14 -050097 path->moveTo(a, b);
98 break;
99 case 1:
Hal Canaryce540ea2017-03-06 08:30:44 -0500100 fuzz_nice_float(fuzz, &a, &b);
Hal Canary24ac42b2017-02-14 13:35:14 -0500101 path->lineTo(a, b);
102 break;
103 case 2:
Hal Canaryce540ea2017-03-06 08:30:44 -0500104 fuzz_nice_float(fuzz, &a, &b, &c, &d);
Hal Canary24ac42b2017-02-14 13:35:14 -0500105 path->quadTo(a, b, c, d);
106 break;
107 case 3:
Hal Canaryce540ea2017-03-06 08:30:44 -0500108 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e);
Hal Canary24ac42b2017-02-14 13:35:14 -0500109 path->conicTo(a, b, c, d, e);
110 break;
111 case 4:
Hal Canaryce540ea2017-03-06 08:30:44 -0500112 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e, &f);
Hal Canary24ac42b2017-02-14 13:35:14 -0500113 path->cubicTo(a, b, c, d, e, f);
114 break;
115 case 5:
Hal Canaryce540ea2017-03-06 08:30:44 -0500116 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e);
Hal Canary24ac42b2017-02-14 13:35:14 -0500117 path->arcTo(a, b, c, d, e);
118 break;
119 case 6:
120 path->close();
121 break;
122 default:
123 break;
124 }
125 }
126}
127
128static void fuzz_region(Fuzz* fuzz, SkRegion* region) {
129 uint8_t N;
130 fuzz->nextRange(&N, 0, 10);
131 for (uint8_t i = 0; i < N; ++i) {
132 SkIRect r;
133 uint8_t op;
134 fuzz->next(&r);
135 r.sort();
136 fuzz->nextRange(&op, 0, (uint8_t)SkRegion::kLastOp);
137 if (!region->op(r, (SkRegion::Op)op)) {
138 return;
139 }
140 }
141}
142
143template <> inline void Fuzz::next(SkShader::TileMode* m) {
144 using U = skstd::underlying_type_t<SkShader::TileMode>;
145 this->nextRange((U*)m, (U)0, (U)(SkShader::kTileModeCount - 1));
146}
147
148
149template <> inline void Fuzz::next(SkMatrix* m) {
150 constexpr int kArrayLength = 9;
151 SkScalar buffer[kArrayLength];
152 int matrixType;
153 this->nextRange(&matrixType, 0, 4);
154 switch (matrixType) {
155 case 0: // identity
156 *m = SkMatrix::I();
157 return;
158 case 1: // translate
159 this->nextRange(&buffer[0], -4000.0f, 4000.0f);
160 this->nextRange(&buffer[1], -4000.0f, 4000.0f);
161 *m = SkMatrix::MakeTrans(buffer[0], buffer[1]);
162 return;
163 case 2: // translate + scale
164 this->nextRange(&buffer[0], -400.0f, 400.0f);
165 this->nextRange(&buffer[1], -400.0f, 400.0f);
166 this->nextRange(&buffer[2], -4000.0f, 4000.0f);
167 this->nextRange(&buffer[3], -4000.0f, 4000.0f);
168 *m = SkMatrix::MakeScale(buffer[0], buffer[1]);
169 m->postTranslate(buffer[2], buffer[3]);
170 return;
171 case 3: // affine
172 this->nextN(buffer, 6);
173 m->setAffine(buffer);
174 return;
175 case 4: // perspective
176 this->nextN(buffer, kArrayLength);
177 m->set9(buffer);
178 return;
179 default:
180 return;
181 }
182}
183
184template <> inline void Fuzz::next(SkRRect* rr) {
185 SkRect r;
186 SkVector radii[4];
187 this->next(&r);
188 this->nextN(radii, 4);
189 rr->setRectRadii(r, radii);
190 SkASSERT(rr->isValid());
191}
192
193template <> inline void Fuzz::next(SkBlendMode* mode) {
194 using U = skstd::underlying_type_t<SkBlendMode>;
195 this->nextRange((U*)mode, (U)0, (U)SkBlendMode::kLastMode);
196}
197
198sk_sp<SkImage> MakeFuzzImage(Fuzz*);
Hal Canary671e4422017-02-27 13:36:38 -0500199
Hal Canary24ac42b2017-02-14 13:35:14 -0500200SkBitmap MakeFuzzBitmap(Fuzz*);
201
Hal Canary671e4422017-02-27 13:36:38 -0500202static sk_sp<SkPicture> make_picture(Fuzz*, int depth);
203
Hal Canary24ac42b2017-02-14 13:35:14 -0500204sk_sp<SkColorFilter> MakeColorFilter(Fuzz* fuzz) { return nullptr; /*TODO*/ }
205
206void make_pos(Fuzz* fuzz, SkScalar* pos, int colorCount) {
207 SkScalar totalPos = 0;
208 for (int i = 0; i < colorCount; ++i) {
209 fuzz->nextRange(&pos[i], 1.0f, 1024.0f);
210 totalPos += pos[i];
211 }
212 totalPos = 1.0f / totalPos;
213 for (int i = 0; i < colorCount; ++i) {
214 pos[i] *= totalPos;
215 }
216 //SkASSERT(fabs(pos[colorCount - 1] - 1.0f) < 0.00001f);
217 pos[colorCount - 1] = 1.0f;
218}
219
220sk_sp<SkShader> MakeFuzzShader(Fuzz* fuzz, int depth) {
221 sk_sp<SkShader> shader1(nullptr), shader2(nullptr);
222 sk_sp<SkColorFilter> colorFilter(nullptr);
223 SkBitmap bitmap;
224 sk_sp<SkImage> img;
225 SkShader::TileMode tmX, tmY;
226 bool useMatrix;
227 SkColor color;
228 SkMatrix matrix;
229 SkBlendMode blendMode;
230 int shaderType;
231 if (depth <= 0) {
232 return nullptr;
233 }
Hal Canary671e4422017-02-27 13:36:38 -0500234 fuzz->nextRange(&shaderType, 0, 14);
Hal Canary24ac42b2017-02-14 13:35:14 -0500235 switch (shaderType) {
236 case 0:
237 return nullptr;
238 case 1:
239 return SkShader::MakeEmptyShader();
240 case 2:
241 fuzz->next(&color);
242 return SkShader::MakeColorShader(color);
243 case 3:
244 img = MakeFuzzImage(fuzz);
245 fuzz->next(&tmX, &tmY, &useMatrix);
246 if (useMatrix) {
247 fuzz->next(&matrix);
248 }
249 return img->makeShader(tmX, tmY, useMatrix ? &matrix : nullptr);
250 case 4:
251 bitmap = MakeFuzzBitmap(fuzz);
252 fuzz->next(&tmX, &tmY, &useMatrix);
253 if (useMatrix) {
254 fuzz->next(&matrix);
255 }
256 return SkShader::MakeBitmapShader(bitmap, tmX, tmY, useMatrix ? &matrix : nullptr);
257 case 5:
258 shader1 = MakeFuzzShader(fuzz, depth - 1); // limit recursion.
259 fuzz->next(&matrix);
260 return shader1 ? shader1->makeWithLocalMatrix(matrix) : nullptr;
261 case 6:
262 shader1 = MakeFuzzShader(fuzz, depth - 1); // limit recursion.
263 colorFilter = MakeColorFilter(fuzz);
264 return shader1 ? shader1->makeWithColorFilter(std::move(colorFilter)) : nullptr;
265 case 7:
266 shader1 = MakeFuzzShader(fuzz, depth - 1); // limit recursion.
267 shader2 = MakeFuzzShader(fuzz, depth - 1);
268 fuzz->next(&blendMode);
269 return SkShader::MakeComposeShader(std::move(shader1), std::move(shader2), blendMode);
Hal Canary24ac42b2017-02-14 13:35:14 -0500270 case 8:
Hal Canary671e4422017-02-27 13:36:38 -0500271 {
272 auto pic = make_picture(fuzz, depth);
273 bool useTile;
274 SkRect tile;
275 fuzz->next(&tmX, &tmY, &useMatrix, &useTile);
276 if (useMatrix) {
277 fuzz->next(&matrix);
278 }
279 if (useTile) {
280 fuzz->next(&tile);
281 }
282 return SkShader::MakePictureShader(std::move(pic), tmX, tmY,
283 useMatrix ? &matrix : nullptr,
284 useTile ? &tile : nullptr);
285 }
286 // EFFECTS:
Hal Canary24ac42b2017-02-14 13:35:14 -0500287 case 9:
Hal Canary671e4422017-02-27 13:36:38 -0500288 return SkGaussianEdgeShader::Make();
289 case 10:
Hal Canary24ac42b2017-02-14 13:35:14 -0500290 {
291 constexpr int kMaxColors = 12;
292 SkPoint pts[2];
293 SkColor colors[kMaxColors];
294 SkScalar pos[kMaxColors];
295 int colorCount;
296 bool usePos;
Kevin Lubickedbeb8b2017-02-27 16:45:32 -0500297 fuzz->nextN(pts, 2);
Hal Canary24ac42b2017-02-14 13:35:14 -0500298 fuzz->nextRange(&colorCount, 2, kMaxColors);
299 fuzz->nextN(colors, colorCount);
300 fuzz->next(&tmX, &useMatrix, &usePos);
301 if (useMatrix) {
302 fuzz->next(&matrix);
303 }
304 if (usePos) {
305 make_pos(fuzz, pos, colorCount);
306 }
307 return SkGradientShader::MakeLinear(pts,
308 colors,
309 usePos ? pos : nullptr,
310 colorCount,
311 tmX, 0,
312 useMatrix ? &matrix : nullptr);
313 }
Hal Canary671e4422017-02-27 13:36:38 -0500314 case 11:
Hal Canary24ac42b2017-02-14 13:35:14 -0500315 {
316 constexpr int kMaxColors = 12;
317 SkPoint center;
318 SkScalar radius;
319 int colorCount;
320 bool usePos;
321 SkColor colors[kMaxColors];
322 SkScalar pos[kMaxColors];
323 fuzz->next(&tmX, &useMatrix, &usePos, &center, &radius);
324 fuzz->nextRange(&colorCount, 2, kMaxColors);
325 fuzz->nextN(colors, colorCount);
326 if (useMatrix) {
327 fuzz->next(&matrix);
328 }
329 if (usePos) {
330 make_pos(fuzz, pos, colorCount);
331 }
332 return SkGradientShader::MakeRadial(center, radius, colors,
333 usePos ? pos : nullptr,
334 colorCount, tmX, 0,
335 useMatrix ? &matrix : nullptr);
336 }
Hal Canary671e4422017-02-27 13:36:38 -0500337 case 12:
Hal Canary24ac42b2017-02-14 13:35:14 -0500338 {
339 constexpr int kMaxColors = 12;
340 SkPoint start, end;
341 SkScalar startRadius, endRadius;
342 int colorCount;
343 bool usePos;
344 SkColor colors[kMaxColors];
345 SkScalar pos[kMaxColors];
346 fuzz->next(&tmX, &useMatrix, &usePos, &startRadius, &endRadius, &start, &end);
347 fuzz->nextRange(&colorCount, 2, kMaxColors);
348 fuzz->nextN(colors, colorCount);
349 if (useMatrix) {
350 fuzz->next(&matrix);
351 }
352 if (usePos) {
353 make_pos(fuzz, pos, colorCount);
354 }
355 return SkGradientShader::MakeTwoPointConical(start, startRadius, end, endRadius,
356 colors, usePos ? pos : nullptr,
357 colorCount, tmX, 0,
358 useMatrix ? &matrix : nullptr);
359 }
Hal Canary671e4422017-02-27 13:36:38 -0500360 case 13:
Hal Canary24ac42b2017-02-14 13:35:14 -0500361 {
362 constexpr int kMaxColors = 12;
363 SkScalar cx, cy;
364 int colorCount;
365 bool usePos;
366 SkColor colors[kMaxColors];
367 SkScalar pos[kMaxColors];
368 fuzz->next(&cx, &cy, &useMatrix, &usePos);
369 fuzz->nextRange(&colorCount, 2, kMaxColors);
370 fuzz->nextN(colors, colorCount);
371 if (useMatrix) {
372 fuzz->next(&matrix);
373 }
374 if (usePos) {
375 make_pos(fuzz, pos, colorCount);
376 }
377 return SkGradientShader::MakeSweep(cx, cy, colors, usePos ? pos : nullptr,
378 colorCount, 0, useMatrix ? &matrix : nullptr);
379 }
Hal Canary671e4422017-02-27 13:36:38 -0500380 case 14:
Hal Canary24ac42b2017-02-14 13:35:14 -0500381 {
382 SkScalar baseFrequencyX, baseFrequencyY, seed;
383 int numOctaves;
384 SkISize tileSize;
385 bool useTileSize, turbulence;
386 fuzz->next(&baseFrequencyX, &baseFrequencyY, &seed, &useTileSize, &turbulence);
387 if (useTileSize) {
388 fuzz->next(&tileSize);
389 }
390 fuzz->nextRange(&numOctaves, 2, 7);
391 if (turbulence) {
392 return SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY,
393 numOctaves, seed,
394 useTileSize ? &tileSize : nullptr);
395 } else {
396 return SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY,
397 numOctaves, seed,
398 useTileSize ? &tileSize : nullptr);
399 }
400 }
401 default:
402 break;
403 }
Kevin Lubickedbeb8b2017-02-27 16:45:32 -0500404 return nullptr;
Hal Canary24ac42b2017-02-14 13:35:14 -0500405}
406
407
408sk_sp<SkPathEffect> MakeFuzzPathEffect(Fuzz* fuzz) { return nullptr; /*TODO*/ }
409
410sk_sp<SkMaskFilter> MakeFuzzMaskFilter(Fuzz* fuzz) { return nullptr; /*TODO*/ }
411
Hal Canary671e4422017-02-27 13:36:38 -0500412sk_sp<SkTypeface> MakeFuzzTypeface(Fuzz* fuzz) {
413 if (make_bool(fuzz)) {
414 return nullptr;
415 }
416 auto fontMugger = SkFontMgr::RefDefault();
417 SkASSERT(fontMugger);
418 int familyCount = fontMugger->countFamilies();
419 int i, j;
420 fuzz->nextRange(&i, 0, familyCount - 1);
421 sk_sp<SkFontStyleSet> family(fontMugger->createStyleSet(i));
422 int styleCount = family->count();
423 fuzz->nextRange(&j, 0, styleCount - 1);
424 return sk_sp<SkTypeface>(family->createTypeface(j));
425}
Hal Canary24ac42b2017-02-14 13:35:14 -0500426
427sk_sp<SkImageFilter> MakeFuzzImageFilter(Fuzz* fuzz) { return nullptr; /*TODO*/ }
428
429sk_sp<SkImage> MakeFuzzImage(Fuzz* fuzz) {
430 int w, h;
431 fuzz->nextRange(&w, 1, 1024);
432 fuzz->nextRange(&h, 1, 1024);
433 SkAutoTMalloc<SkPMColor> data(w * h);
434 SkPixmap pixmap(SkImageInfo::MakeN32Premul(w, h), data.get(), w * sizeof(SkPMColor));
435 int n = w * h;
436 for (int i = 0; i < n; ++i) {
437 SkColor c;
438 fuzz->next(&c);
439 data[i] = SkPreMultiplyColor(c);
440 }
441 (void)data.release();
442 return SkImage::MakeFromRaster(
443 pixmap, [](const void* p, void*) { sk_free((void*)p); }, nullptr);
444}
445
446SkBitmap MakeFuzzBitmap(Fuzz* fuzz) {
447 SkBitmap bitmap;
448 int w, h;
449 fuzz->nextRange(&w, 1, 1024);
450 fuzz->nextRange(&h, 1, 1024);
451 bitmap.allocN32Pixels(w, h);
452 SkAutoLockPixels autoLockPixels(bitmap);
453 for (int y = 0; y < h; ++y) {
454 for (int x = 0; x < w; ++x) {
455 SkColor c;
456 fuzz->next(&c);
457 *bitmap.getAddr32(x, y) = SkPreMultiplyColor(c);
458 }
459 }
460 return bitmap;
461}
462
Hal Canary24ac42b2017-02-14 13:35:14 -0500463void FuzzPaint(Fuzz* fuzz, SkPaint* paint, int depth) {
464 if (!fuzz || !paint || depth <= 0) {
465 return;
466 }
467
468 fuzz_input<bool, &SkPaint::setAntiAlias>(fuzz, paint);
469 fuzz_input<bool, &SkPaint::setDither>(fuzz, paint);
470 fuzz_input<SkColor, &SkPaint::setColor>(fuzz, paint);
471 fuzz_enum_input<SkBlendMode, &SkPaint::setBlendMode>(fuzz, paint, (SkBlendMode)0,
472 SkBlendMode::kLastMode);
473 fuzz_enum_input<SkPaint::Hinting, &SkPaint::setHinting>(fuzz, paint, SkPaint::kNo_Hinting,
474 SkPaint::kFull_Hinting);
475 fuzz_enum_input<SkFilterQuality, &SkPaint::setFilterQuality>(
476 fuzz, paint, SkFilterQuality::kNone_SkFilterQuality,
477 SkFilterQuality::kLast_SkFilterQuality);
478 fuzz_enum_input<SkPaint::Style, &SkPaint::setStyle>(fuzz, paint, SkPaint::kFill_Style,
479 SkPaint::kStrokeAndFill_Style);
480 paint->setShader(MakeFuzzShader(fuzz, depth));
481 paint->setPathEffect(MakeFuzzPathEffect(fuzz));
482 paint->setMaskFilter(MakeFuzzMaskFilter(fuzz));
483 paint->setImageFilter(MakeFuzzImageFilter(fuzz));
484 paint->setColorFilter(MakeColorFilter(fuzz));
485
486 if (paint->getStyle() != SkPaint::kFill_Style) {
487 fuzz_input<SkScalar, &SkPaint::setStrokeWidth>(fuzz, paint);
488 fuzz_input<SkScalar, &SkPaint::setStrokeMiter>(fuzz, paint);
489 fuzz_enum_input<SkPaint::Cap, &SkPaint::setStrokeCap>(fuzz, paint, SkPaint::kButt_Cap,
490 SkPaint::kLast_Cap);
491 fuzz_enum_input<SkPaint::Join, &SkPaint::setStrokeJoin>(fuzz, paint, SkPaint::kMiter_Join,
492 SkPaint::kLast_Join);
493 }
494}
495
496void FuzzPaintText(Fuzz* fuzz, SkPaint* paint) {
497 paint->setTypeface(MakeFuzzTypeface(fuzz));
498 fuzz_input<SkScalar, &SkPaint::setTextSize>(fuzz, paint);
499 fuzz_input<SkScalar, &SkPaint::setTextScaleX>(fuzz, paint);
500 fuzz_input<SkScalar, &SkPaint::setTextSkewX>(fuzz, paint);
501 fuzz_input<bool, &SkPaint::setLinearText>(fuzz, paint);
502 fuzz_input<bool, &SkPaint::setSubpixelText>(fuzz, paint);
503 fuzz_input<bool, &SkPaint::setLCDRenderText>(fuzz, paint);
504 fuzz_input<bool, &SkPaint::setEmbeddedBitmapText>(fuzz, paint);
505 fuzz_input<bool, &SkPaint::setAutohinted>(fuzz, paint);
506 fuzz_input<bool, &SkPaint::setVerticalText>(fuzz, paint);
507 fuzz_input<bool, &SkPaint::setFakeBoldText>(fuzz, paint);
508 fuzz_input<bool, &SkPaint::setDevKernText>(fuzz, paint);
509 fuzz_enum_input<SkPaint::Align, &SkPaint::setTextAlign>(fuzz, paint, SkPaint::kLeft_Align,
510 SkPaint::kRight_Align);
Hal Canary671e4422017-02-27 13:36:38 -0500511 fuzz_enum_input<SkPaint::TextEncoding, &SkPaint::setTextEncoding>(
512 fuzz, paint, SkPaint::kUTF8_TextEncoding, SkPaint::kGlyphID_TextEncoding);
Hal Canary24ac42b2017-02-14 13:35:14 -0500513}
514
Hal Canary671e4422017-02-27 13:36:38 -0500515SkTDArray<uint8_t> fuzz_text(Fuzz* fuzz, const SkPaint& paint) {
516 SkTDArray<uint8_t> array;
517 if (SkPaint::kGlyphID_TextEncoding == paint.getTextEncoding()) {
518 int glyphRange = paint.getTypeface()
519 ? paint.getTypeface()->countGlyphs()
520 : SkTypeface::MakeDefault()->countGlyphs();
521 constexpr int kMaxGlyphCount = 20;
522 int glyphCount;
523 fuzz->nextRange(&glyphCount, 0, kMaxGlyphCount);
524 SkGlyphID* glyphs = (SkGlyphID*)array.append(glyphCount * sizeof(SkGlyphID));
525 for (int i = 0; i < glyphCount; ++i) {
526 fuzz->nextRange(&glyphs[i], 0, glyphRange - 1);
527 }
528 return array;
529 }
530 static const SkUnichar ranges[][2] = {
531 {0x0020, 0x007F},
532 {0x00A1, 0x0250},
533 {0x0400, 0x0500},
534 };
535 int32_t count = 0;
536 for (size_t i = 0; i < SK_ARRAY_COUNT(ranges); ++i){
537 count += (ranges[i][1] - ranges[i][0]);
538 }
539 constexpr int kMaxLength = 30;
540 SkUnichar buffer[kMaxLength];
541 int length;
542 fuzz->nextRange(&length, 1, kMaxLength);
543 for (int j = 0; j < length; ++j) {
544 int32_t value;
545 fuzz->nextRange(&value, 0, count - 1);
546 for (size_t i = 0; i < SK_ARRAY_COUNT(ranges); ++i){
547 if (value + ranges[i][0] < ranges[i][1]) {
548 buffer[j] = value + ranges[i][0];
549 break;
550 } else {
551 value -= (ranges[i][1] - ranges[i][0]);
552 }
553 }
554 }
555 switch (paint.getTextEncoding()) {
556 case SkPaint::kUTF8_TextEncoding:
557 {
558 size_t utf8len = 0;
559 for (int j = 0; j < length; ++j) {
560 utf8len += SkUTF8_FromUnichar(buffer[j], nullptr);
561 }
562 char* ptr = (char*)array.append(utf8len);
563 for (int j = 0; j < length; ++j) {
564 ptr += SkUTF8_FromUnichar(buffer[j], ptr);
565 }
566 }
Hal Canaryc1a70e22017-03-01 15:40:46 -0500567 break;
Hal Canary671e4422017-02-27 13:36:38 -0500568 case SkPaint::kUTF16_TextEncoding:
569 {
570 size_t utf16len = 0;
571 for (int j = 0; j < length; ++j) {
572 utf16len += SkUTF16_FromUnichar(buffer[j]);
573 }
Hal Canaryc1a70e22017-03-01 15:40:46 -0500574 uint16_t* ptr = (uint16_t*)array.append(utf16len * sizeof(uint16_t));
Hal Canary671e4422017-02-27 13:36:38 -0500575 for (int j = 0; j < length; ++j) {
576 ptr += SkUTF16_FromUnichar(buffer[j], ptr);
577 }
578 }
Hal Canaryc1a70e22017-03-01 15:40:46 -0500579 break;
Hal Canary671e4422017-02-27 13:36:38 -0500580 case SkPaint::kUTF32_TextEncoding:
581 memcpy(array.append(length * sizeof(SkUnichar)), buffer, length * sizeof(SkUnichar));
Hal Canaryc1a70e22017-03-01 15:40:46 -0500582 break;
Hal Canary671e4422017-02-27 13:36:38 -0500583 default:
584 SkASSERT(false);
585 }
586 return array;
587}
588
Hal Canary24ac42b2017-02-14 13:35:14 -0500589
590void fuzz_canvas(Fuzz* fuzz, SkCanvas* canvas, int depth = 4) {
591 if (!fuzz || !canvas || depth <= 0) {
592 return;
593 }
594 SkAutoCanvasRestore autoCanvasRestore(canvas, false);
595 unsigned N;
596 fuzz->nextRange(&N, 0, 2000);
597 for (unsigned i = 0; i < N; ++i) {
598 if (fuzz->exhausted()) {
599 return;
600 }
601 SkPaint paint;
602 SkMatrix matrix;
603 unsigned drawCommand;
604 fuzz->nextRange(&drawCommand, 0, 54);
605 switch (drawCommand) {
606 case 0:
607 canvas->flush();
608 break;
609 case 1:
610 canvas->save();
611 break;
612 case 2: {
613 SkRect bounds;
614 fuzz->next(&bounds);
615 FuzzPaint(fuzz, &paint, depth);
616 canvas->saveLayer(&bounds, &paint);
617 break;
618 }
619 case 3: {
620 SkRect bounds;
621 fuzz->next(&bounds);
622 canvas->saveLayer(&bounds, nullptr);
623 break;
624 }
625 case 4:
626 FuzzPaint(fuzz, &paint, depth);
627 canvas->saveLayer(nullptr, &paint);
628 break;
629 case 5:
630 canvas->saveLayer(nullptr, nullptr);
631 break;
632 case 6: {
633 uint8_t alpha;
634 fuzz->next(&alpha);
635 canvas->saveLayerAlpha(nullptr, (U8CPU)alpha);
636 break;
637 }
638 case 7: {
639 SkRect bounds;
640 uint8_t alpha;
641 fuzz->next(&bounds, &alpha);
642 canvas->saveLayerAlpha(&bounds, (U8CPU)alpha);
643 break;
644 }
645 case 8: {
646 SkCanvas::SaveLayerRec saveLayerRec;
647 SkRect bounds;
648 if (make_bool(fuzz)) {
649 fuzz->next(&bounds);
650 saveLayerRec.fBounds = &bounds;
651 }
652 if (make_bool(fuzz)) {
653 FuzzPaint(fuzz, &paint, depth);
654 saveLayerRec.fPaint = &paint;
655 }
656 sk_sp<SkImageFilter> imageFilter;
657 if (make_bool(fuzz)) {
658 imageFilter = MakeFuzzImageFilter(fuzz);
659 saveLayerRec.fBackdrop = imageFilter.get();
660 }
661 if (make_bool(fuzz)) {
662 saveLayerRec.fSaveLayerFlags |= SkCanvas::kIsOpaque_SaveLayerFlag;
663 }
664 if (make_bool(fuzz)) {
665 saveLayerRec.fSaveLayerFlags |= SkCanvas::kPreserveLCDText_SaveLayerFlag;
666 }
667 canvas->saveLayer(saveLayerRec);
668 break;
669 }
670 case 9:
671 canvas->restore();
672 break;
673 case 10: {
674 int saveCount;
675 fuzz->next(&saveCount);
676 canvas->restoreToCount(saveCount);
677 break;
678 }
679 case 11: {
680 SkScalar x, y;
681 fuzz->next(&x, &y);
682 canvas->translate(x, y);
683 break;
684 }
685 case 12: {
686 SkScalar x, y;
687 fuzz->next(&x, &y);
688 canvas->scale(x, y);
689 break;
690 }
691 case 13: {
692 SkScalar v;
693 fuzz->next(&v);
694 canvas->rotate(v);
695 break;
696 }
697 case 14: {
698 SkScalar x, y, v;
699 fuzz->next(&x, &y, &v);
700 canvas->rotate(v, x, y);
701 break;
702 }
703 case 15: {
704 SkScalar x, y;
705 fuzz->next(&x, &y);
706 canvas->skew(x, y);
707 break;
708 }
709 case 16: {
710 SkMatrix mat;
711 fuzz->next(&mat);
712 canvas->concat(mat);
713 break;
714 }
715 case 17: {
716 SkMatrix mat;
717 fuzz->next(&mat);
718 canvas->setMatrix(mat);
719 break;
720 }
721 case 18:
722 canvas->resetMatrix();
723 break;
724 case 19: {
725 SkRect r;
726 int op;
727 bool doAntiAlias;
728 fuzz->next(&r, &doAntiAlias);
729 fuzz->nextRange(&op, 0, 1);
730 r.sort();
731 canvas->clipRect(r, (SkClipOp)op, doAntiAlias);
732 break;
733 }
734 case 20: {
735 SkRRect rr;
736 int op;
737 bool doAntiAlias;
738 fuzz->next(&rr);
739 fuzz->next(&doAntiAlias);
740 fuzz->nextRange(&op, 0, 1);
741 canvas->clipRRect(rr, (SkClipOp)op, doAntiAlias);
742 break;
743 }
744 case 21: {
745 SkPath path;
Hal Canaryce540ea2017-03-06 08:30:44 -0500746 fuzz_path(fuzz, &path, 30);
Hal Canary24ac42b2017-02-14 13:35:14 -0500747 int op;
748 bool doAntiAlias;
749 fuzz->next(&doAntiAlias);
750 fuzz->nextRange(&op, 0, 1);
751 canvas->clipPath(path, (SkClipOp)op, doAntiAlias);
752 break;
753 }
754 case 22: {
755 SkRegion region;
756 fuzz_region(fuzz, &region);
757 int op;
758 fuzz->nextRange(&op, 0, 1);
759 canvas->clipRegion(region, (SkClipOp)op);
760 break;
761 }
762 case 23:
763 FuzzPaint(fuzz, &paint, depth);
764 canvas->drawPaint(paint);
765 break;
766 case 24: {
767 FuzzPaint(fuzz, &paint, depth);
768 uint8_t pointMode;
769 fuzz->nextRange(&pointMode, 0, 3);
770 size_t count;
771 constexpr int kMaxCount = 30;
772 fuzz->nextRange(&count, 0, kMaxCount);
773 SkPoint pts[kMaxCount];
774 fuzz->nextN(pts, count);
775 canvas->drawPoints((SkCanvas::PointMode)pointMode, count, pts, paint);
776 break;
777 }
778 case 25: {
779 FuzzPaint(fuzz, &paint, depth);
780 SkRect r;
781 fuzz->next(&r);
782 canvas->drawRect(r, paint);
783 break;
784 }
785 case 26: {
786 FuzzPaint(fuzz, &paint, depth);
787 SkRegion region;
788 fuzz_region(fuzz, &region);
789 canvas->drawRegion(region, paint);
790 break;
791 }
792 case 27: {
793 FuzzPaint(fuzz, &paint, depth);
794 SkRect r;
795 fuzz->next(&r);
796 canvas->drawOval(r, paint);
797 break;
798 }
799 case 29: {
800 FuzzPaint(fuzz, &paint, depth);
801 SkRRect rr;
802 fuzz->next(&rr);
803 canvas->drawRRect(rr, paint);
804 break;
805 }
806 case 30: {
807 FuzzPaint(fuzz, &paint, depth);
808 SkRRect orr, irr;
809 fuzz->next(&orr);
810 fuzz->next(&irr);
811 canvas->drawDRRect(orr, irr, paint);
812 break;
813 }
814 case 31: {
815 FuzzPaint(fuzz, &paint, depth);
816 SkRect r;
817 SkScalar start, sweep;
818 bool useCenter;
819 fuzz->next(&r, &start, &sweep, &useCenter);
820 canvas->drawArc(r, start, sweep, useCenter, paint);
821 break;
822 }
823 case 32: {
824 SkPath path;
Hal Canaryce540ea2017-03-06 08:30:44 -0500825 fuzz_path(fuzz, &path, 60);
Hal Canary24ac42b2017-02-14 13:35:14 -0500826 canvas->drawPath(path, paint);
827 break;
828 }
829 case 33: {
830 sk_sp<SkImage> img = MakeFuzzImage(fuzz);
831 SkScalar left, top;
832 bool usePaint;
833 fuzz->next(&left, &top, &usePaint);
834 if (usePaint) {
835 FuzzPaint(fuzz, &paint, depth);
836 }
837 canvas->drawImage(img.get(), left, top, usePaint ? &paint : nullptr);
838 break;
839 }
840 case 34: {
841 auto img = MakeFuzzImage(fuzz);
842 SkRect src, dst;
843 bool usePaint;
844 fuzz->next(&src, &dst, &usePaint);
845 if (usePaint) {
846 FuzzPaint(fuzz, &paint, depth);
847 }
848 SkCanvas::SrcRectConstraint constraint = make_bool(fuzz)
849 ? SkCanvas::kStrict_SrcRectConstraint
850 : SkCanvas::kFast_SrcRectConstraint;
851 canvas->drawImageRect(img, src, dst, usePaint ? &paint : nullptr, constraint);
852 break;
853 }
854 case 35: {
855 auto img = MakeFuzzImage(fuzz);
856 SkIRect src;
857 SkRect dst;
858 bool usePaint;
859 fuzz->next(&src, &dst, &usePaint);
860 if (usePaint) {
861 FuzzPaint(fuzz, &paint, depth);
862 }
863 SkCanvas::SrcRectConstraint constraint = make_bool(fuzz)
864 ? SkCanvas::kStrict_SrcRectConstraint
865 : SkCanvas::kFast_SrcRectConstraint;
866 canvas->drawImageRect(img, src, dst, usePaint ? &paint : nullptr, constraint);
867 break;
868 }
869 case 36: {
870 bool usePaint;
871 auto img = MakeFuzzImage(fuzz);
872 SkRect dst;
873 fuzz->next(&dst, &usePaint);
874 if (usePaint) {
875 FuzzPaint(fuzz, &paint, depth);
876 }
877 SkCanvas::SrcRectConstraint constraint = make_bool(fuzz)
878 ? SkCanvas::kStrict_SrcRectConstraint
879 : SkCanvas::kFast_SrcRectConstraint;
880 canvas->drawImageRect(img, dst, usePaint ? &paint : nullptr, constraint);
881 break;
882 }
883 case 37: {
884 auto img = MakeFuzzImage(fuzz);
885 SkIRect center;
886 SkRect dst;
887 bool usePaint;
888 fuzz->next(&center, &dst, &usePaint);
889 if (usePaint) {
890 FuzzPaint(fuzz, &paint, depth);
891 }
892 canvas->drawImageNine(img, center, dst, usePaint ? &paint : nullptr);
893 break;
894 }
895 case 38: {
896 SkBitmap bitmap = MakeFuzzBitmap(fuzz);
897 SkScalar left, top;
898 bool usePaint;
899 fuzz->next(&left, &top, &usePaint);
900 if (usePaint) {
901 FuzzPaint(fuzz, &paint, depth);
902 }
903 canvas->drawBitmap(bitmap, left, top, usePaint ? &paint : nullptr);
904 break;
905 }
906 case 39: {
907 SkBitmap bitmap = MakeFuzzBitmap(fuzz);
908 SkRect src, dst;
909 bool usePaint;
910 fuzz->next(&src, &dst, &usePaint);
911 if (usePaint) {
912 FuzzPaint(fuzz, &paint, depth);
913 }
914 SkCanvas::SrcRectConstraint constraint = make_bool(fuzz)
915 ? SkCanvas::kStrict_SrcRectConstraint
916 : SkCanvas::kFast_SrcRectConstraint;
917 canvas->drawBitmapRect(bitmap, src, dst, usePaint ? &paint : nullptr, constraint);
918 break;
919 }
920 case 40: {
921 SkBitmap img = MakeFuzzBitmap(fuzz);
922 SkIRect src;
923 SkRect dst;
924 bool usePaint;
925 fuzz->next(&src, &dst, &usePaint);
926 if (usePaint) {
927 FuzzPaint(fuzz, &paint, depth);
928 }
929 SkCanvas::SrcRectConstraint constraint = make_bool(fuzz)
930 ? SkCanvas::kStrict_SrcRectConstraint
931 : SkCanvas::kFast_SrcRectConstraint;
932 canvas->drawBitmapRect(img, src, dst, usePaint ? &paint : nullptr, constraint);
933 break;
934 }
935 case 41: {
936 SkBitmap img = MakeFuzzBitmap(fuzz);
937 SkRect dst;
938 bool usePaint;
939 fuzz->next(&dst, &usePaint);
940 if (usePaint) {
941 FuzzPaint(fuzz, &paint, depth);
942 }
943 SkCanvas::SrcRectConstraint constraint = make_bool(fuzz)
944 ? SkCanvas::kStrict_SrcRectConstraint
945 : SkCanvas::kFast_SrcRectConstraint;
946 canvas->drawBitmapRect(img, dst, usePaint ? &paint : nullptr, constraint);
947 break;
948 }
949 case 42: {
950 SkBitmap img = MakeFuzzBitmap(fuzz);
951 SkIRect center;
952 SkRect dst;
953 bool usePaint;
954 fuzz->next(&center, &dst, &usePaint);
955 if (usePaint) {
956 FuzzPaint(fuzz, &paint, depth);
957 }
958 canvas->drawBitmapNine(img, center, dst, usePaint ? &paint : nullptr);
959 break;
960 }
961 case 43: {
962 SkBitmap img = MakeFuzzBitmap(fuzz);
963 bool usePaint;
964 SkRect dst;
965 fuzz->next(&usePaint, &dst);
966 if (usePaint) {
967 FuzzPaint(fuzz, &paint, depth);
968 }
969 constexpr int kMax = 6;
970 int xDivs[kMax], yDivs[kMax];
971 SkCanvas::Lattice lattice{xDivs, yDivs, nullptr, 0, 0, nullptr};
972 fuzz->nextRange(&lattice.fXCount, 2, kMax);
973 fuzz->nextRange(&lattice.fYCount, 2, kMax);
974 fuzz->nextN(xDivs, lattice.fXCount);
975 fuzz->nextN(yDivs, lattice.fYCount);
976 canvas->drawBitmapLattice(img, lattice, dst, usePaint ? &paint : nullptr);
977 break;
978 }
979 case 44: {
980 auto img = MakeFuzzImage(fuzz);
981 bool usePaint;
982 SkRect dst;
983 fuzz->next(&usePaint, &dst);
984 if (usePaint) {
985 FuzzPaint(fuzz, &paint, depth);
986 }
987 constexpr int kMax = 6;
988 int xDivs[kMax], yDivs[kMax];
989 SkCanvas::Lattice lattice{xDivs, yDivs, nullptr, 0, 0, nullptr};
990 fuzz->nextRange(&lattice.fXCount, 2, kMax);
991 fuzz->nextRange(&lattice.fYCount, 2, kMax);
992 fuzz->nextN(xDivs, lattice.fXCount);
993 fuzz->nextN(yDivs, lattice.fYCount);
994 canvas->drawImageLattice(img.get(), lattice, dst, usePaint ? &paint : nullptr);
995 break;
996 }
997 case 45: {
Hal Canary671e4422017-02-27 13:36:38 -0500998 FuzzPaint(fuzz, &paint, depth);
Hal Canary24ac42b2017-02-14 13:35:14 -0500999 FuzzPaintText(fuzz, &paint);
Hal Canary24ac42b2017-02-14 13:35:14 -05001000 SkScalar x, y;
1001 fuzz->next(&x, &y);
Hal Canary671e4422017-02-27 13:36:38 -05001002 SkTDArray<uint8_t> text = fuzz_text(fuzz, paint);
1003 canvas->drawText(text.begin(), SkToSizeT(text.count()), x, y, paint);
Hal Canary24ac42b2017-02-14 13:35:14 -05001004 break;
1005 }
1006 case 46: {
Hal Canary671e4422017-02-27 13:36:38 -05001007 FuzzPaint(fuzz, &paint, depth);
Hal Canary24ac42b2017-02-14 13:35:14 -05001008 FuzzPaintText(fuzz, &paint);
Hal Canary671e4422017-02-27 13:36:38 -05001009 SkTDArray<uint8_t> text = fuzz_text(fuzz, paint);
1010 int glyphCount = paint.countText(text.begin(), SkToSizeT(text.count()));
Hal Canary24ac42b2017-02-14 13:35:14 -05001011 if (glyphCount < 1) {
1012 break;
1013 }
1014 SkAutoTMalloc<SkPoint> pos(glyphCount);
1015 SkAutoTMalloc<SkScalar> widths(glyphCount);
Hal Canary671e4422017-02-27 13:36:38 -05001016 paint.getTextWidths(text.begin(), SkToSizeT(text.count()), widths.get());
Hal Canary24ac42b2017-02-14 13:35:14 -05001017 pos[0] = {0, 0};
1018 for (int i = 1; i < glyphCount; ++i) {
1019 float y;
1020 fuzz->nextRange(&y, -0.5f * paint.getTextSize(),
1021 0.5f * paint.getTextSize());
1022 pos[i] = {pos[i - 1].x() + widths[i - 1], y};
1023 }
Hal Canary671e4422017-02-27 13:36:38 -05001024 canvas->drawPosText(text.begin(), SkToSizeT(text.count()), pos.get(), paint);
Hal Canary24ac42b2017-02-14 13:35:14 -05001025 break;
1026 }
1027 case 47: {
Hal Canary671e4422017-02-27 13:36:38 -05001028 FuzzPaint(fuzz, &paint, depth);
Hal Canary24ac42b2017-02-14 13:35:14 -05001029 FuzzPaintText(fuzz, &paint);
Hal Canary671e4422017-02-27 13:36:38 -05001030 SkTDArray<uint8_t> text = fuzz_text(fuzz, paint);
1031 int glyphCount = paint.countText(text.begin(), SkToSizeT(text.count()));
Hal Canary24ac42b2017-02-14 13:35:14 -05001032 SkAutoTMalloc<SkScalar> widths(glyphCount);
1033 if (glyphCount < 1) {
1034 break;
1035 }
Hal Canary671e4422017-02-27 13:36:38 -05001036 paint.getTextWidths(text.begin(), SkToSizeT(text.count()), widths.get());
Hal Canary24ac42b2017-02-14 13:35:14 -05001037 SkScalar x = widths[0];
1038 for (int i = 0; i < glyphCount; ++i) {
1039 SkTSwap(x, widths[i]);
1040 x += widths[i];
1041 SkScalar offset;
1042 fuzz->nextRange(&offset, -0.125f * paint.getTextSize(),
1043 0.125f * paint.getTextSize());
1044 widths[i] += offset;
1045 }
1046 SkScalar y;
1047 fuzz->next(&y);
Hal Canary671e4422017-02-27 13:36:38 -05001048 canvas->drawPosTextH(text.begin(), SkToSizeT(text.count()),
1049 widths.get(), y, paint);
Hal Canary24ac42b2017-02-14 13:35:14 -05001050 break;
1051 }
1052 case 48: {
Hal Canary671e4422017-02-27 13:36:38 -05001053 FuzzPaint(fuzz, &paint, depth);
Hal Canary24ac42b2017-02-14 13:35:14 -05001054 FuzzPaintText(fuzz, &paint);
Hal Canary671e4422017-02-27 13:36:38 -05001055 SkTDArray<uint8_t> text = fuzz_text(fuzz, paint);
Hal Canary24ac42b2017-02-14 13:35:14 -05001056 SkPath path;
Hal Canaryce540ea2017-03-06 08:30:44 -05001057 fuzz_path(fuzz, &path, 20);
Hal Canary24ac42b2017-02-14 13:35:14 -05001058 SkScalar hOffset, vOffset;
1059 fuzz->next(&hOffset, &vOffset);
Hal Canary671e4422017-02-27 13:36:38 -05001060 canvas->drawTextOnPathHV(text.begin(), SkToSizeT(text.count()),
1061 path, hOffset, vOffset, paint);
Hal Canary24ac42b2017-02-14 13:35:14 -05001062 break;
1063 }
1064 case 49: {
1065 SkMatrix matrix;
1066 bool useMatrix = make_bool(fuzz);
1067 if (useMatrix) {
1068 fuzz->next(&matrix);
1069 }
Hal Canary671e4422017-02-27 13:36:38 -05001070 FuzzPaint(fuzz, &paint, depth);
Hal Canary24ac42b2017-02-14 13:35:14 -05001071 FuzzPaintText(fuzz, &paint);
Hal Canary671e4422017-02-27 13:36:38 -05001072 SkTDArray<uint8_t> text = fuzz_text(fuzz, paint);
Hal Canary24ac42b2017-02-14 13:35:14 -05001073 SkPath path;
Hal Canaryce540ea2017-03-06 08:30:44 -05001074 fuzz_path(fuzz, &path, 20);
Hal Canary671e4422017-02-27 13:36:38 -05001075 canvas->drawTextOnPath(text.begin(), SkToSizeT(text.count()), path,
Hal Canary24ac42b2017-02-14 13:35:14 -05001076 useMatrix ? &matrix : nullptr, paint);
1077 break;
1078 }
1079 case 50: {
1080 // canvas->drawTextRSXform(...); // TODO
1081 break;
1082 }
1083 case 51: {
1084 // canvas->drawTextBlob(...); // TODO
1085 break;
1086 }
1087 case 52: {
1088 bool usePaint, useMatrix;
1089 fuzz->next(&usePaint, &useMatrix);
1090 if (usePaint) {
1091 FuzzPaint(fuzz, &paint, depth);
1092 }
1093 if (useMatrix) {
1094 fuzz->next(&matrix);
1095 }
1096 auto pic = make_picture(fuzz, depth);
1097 canvas->drawPicture(pic, useMatrix ? &matrix : nullptr,
1098 usePaint ? &paint : nullptr);
1099 break;
1100 }
1101 case 53: {
1102 FuzzPaint(fuzz, &paint, depth);
1103 SkCanvas::VertexMode vertexMode;
1104 SkBlendMode mode;
1105 uint8_t vm, bm;
Hal Canary3a97d272017-03-07 15:06:29 -05001106 fuzz->nextRange(&vm, 0, (uint8_t)SkCanvas::kTriangleFan_VertexMode);
1107 fuzz->nextRange(&bm, 0, (uint8_t)SkBlendMode::kLastMode);
Hal Canary24ac42b2017-02-14 13:35:14 -05001108 vertexMode = (SkCanvas::VertexMode)vm;
1109 mode = (SkBlendMode)bm;
1110 constexpr int kMaxCount = 100;
1111 int vertexCount;
1112 SkPoint vertices[kMaxCount];
1113 SkPoint texs[kMaxCount];
1114 SkColor colors[kMaxCount];
Hal Canary24ac42b2017-02-14 13:35:14 -05001115 fuzz->nextRange(&vertexCount, 3, kMaxCount);
1116 fuzz->nextN(vertices, vertexCount);
1117 bool useTexs, useColors;
1118 fuzz->next(&useTexs, &useColors);
1119 if (useTexs) {
1120 fuzz->nextN(texs, vertexCount);
1121 }
1122 if (useColors) {
1123 fuzz->nextN(colors, vertexCount);
1124 }
1125 int indexCount = 0;
Hal Canary68b9b572017-03-02 15:27:23 -05001126 uint16_t indices[kMaxCount * 2];
Hal Canary24ac42b2017-02-14 13:35:14 -05001127 if (make_bool(fuzz)) {
Hal Canary68b9b572017-03-02 15:27:23 -05001128 fuzz->nextRange(&indexCount, vertexCount, vertexCount + kMaxCount);
1129 for (int i = 0; i < indexCount; ++i) {
1130 fuzz->nextRange(&indices[i], 0, vertexCount - 1);
1131 }
Hal Canary24ac42b2017-02-14 13:35:14 -05001132 }
1133 canvas->drawVertices(vertexMode, vertexCount, vertices,
1134 useTexs ? texs : nullptr,
1135 useColors ? colors : nullptr,
1136 mode,
1137 indexCount > 0 ? indices : nullptr,
1138 indexCount,
1139 paint);
1140 break;
1141 }
1142 case 54: {
1143 // canvas->drawVertices(...);
1144 // TODO
1145 break;
1146 }
1147 default:
1148 break;
1149 }
1150 }
1151}
1152
1153static sk_sp<SkPicture> make_picture(Fuzz* fuzz, int depth) {
1154 SkScalar w, h;
1155 fuzz->next(&w, &h);
1156 SkPictureRecorder pictureRecorder;
1157 fuzz_canvas(fuzz, pictureRecorder.beginRecording(w, h), depth - 1);
1158 return pictureRecorder.finishRecordingAsPicture();
1159}
1160
Kevin Lubick1ac8fd22017-03-01 10:42:45 -05001161DEF_FUZZ(NullCanvas, fuzz) {
1162 fuzz_canvas(fuzz, SkMakeNullCanvas().get());
Hal Canary24ac42b2017-02-14 13:35:14 -05001163}
1164
Kevin Lubick1ac8fd22017-03-01 10:42:45 -05001165DEF_FUZZ(RasterN32Canvas, fuzz) {
1166 fuzz_canvas(fuzz, SkMakeNullCanvas().get());
1167 auto surface = SkSurface::MakeRasterN32Premul(612, 792);
1168 SkASSERT(surface && surface->getCanvas());
1169 fuzz_canvas(fuzz, surface->getCanvas());
1170}
1171
1172DEF_FUZZ(PDFCanvas, fuzz) {
1173 struct final : public SkWStream {
1174 bool write(const void*, size_t n) override { fN += n; return true; }
1175 size_t bytesWritten() const override { return fN; }
1176 size_t fN = 0;
1177 } stream;
1178 auto doc = SkDocument::MakePDF(&stream);
1179 fuzz_canvas(fuzz, doc->beginPage(612.0f, 792.0f));
1180}
1181
1182// not a "real" thing to fuzz, used to debug errors found while fuzzing.
1183DEF_FUZZ(_DumpCanvas, fuzz) {
1184 SkDebugCanvas debugCanvas(612, 792);
1185 fuzz_canvas(fuzz, &debugCanvas);
1186 std::unique_ptr<SkCanvas> nullCanvas = SkMakeNullCanvas();
1187 UrlDataManager dataManager(SkString("data"));
1188 Json::Value json = debugCanvas.toJSON(dataManager, debugCanvas.getSize(), nullCanvas.get());
1189 Json::StyledStreamWriter(" ").write(std::cout, json);
1190}