Flutter Engine
The Flutter Engine
blurrect.cpp
Go to the documentation of this file.
1/*
2* Copyright 2012 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 <cmath>
9#include "gm/gm.h"
21#include "include/core/SkRect.h"
25#include "include/core/SkSize.h"
33#include "src/core/SkBlurMask.h"
34#include "src/core/SkMask.h"
37
38#include <vector>
39
40#define STROKE_WIDTH SkIntToScalar(10)
41
42typedef void (*Proc)(SkCanvas*, const SkRect&, const SkPaint&);
43
44static void fill_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
45 canvas->drawRect(r, p);
46}
47
48static void draw_donut(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
51
52 rect = r;
53 rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
54 path.addRect(rect);
55 rect = r;
56 rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
57
58 path.addRect(rect);
59 path.setFillType(SkPathFillType::kEvenOdd);
60
61 canvas->drawPath(path.detach(), p);
62}
63
64static void draw_donut_skewed(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
67
68 rect = r;
69 rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
70 path.addRect(rect);
71 rect = r;
72 rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
73
74 rect.offset(7, -7);
75
76 path.addRect(rect);
77 path.setFillType(SkPathFillType::kEvenOdd);
78
79 canvas->drawPath(path.detach(), p);
80}
81
82/*
83 * Spits out an arbitrary gradient to test blur with shader on paint
84 */
86 SkPoint pts[2] = {
87 { 0, 0 },
88 { SkIntToScalar(100), SkIntToScalar(100) }
89 };
92 const SkScalar pos[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
94 scale.setScale(0.5f, 0.5f);
95 scale.postTranslate(25.f, 25.f);
96 SkPoint center0, center1;
97 center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
98 SkScalarAve(pts[0].fY, pts[1].fY));
99 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
100 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
101 return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7,
102 center0, (pts[1].fX - pts[0].fX) / 2,
103 colors, pos, std::size(colors), tm,
104 0, &scale);
105}
106
107typedef void (*PaintProc)(SkPaint*, SkScalar width);
108
109class BlurRectGM : public skiagm::GM {
110public:
111 BlurRectGM(const char name[], U8CPU alpha) : fName(name), fAlpha(SkToU8(alpha)) {}
112
113private:
115 const char* fName;
116 SkAlpha fAlpha;
117
118 void onOnceBeforeDraw() override {
119 for (int i = 0; i <= kLastEnum_SkBlurStyle; ++i) {
120 fMaskFilters[i] = SkMaskFilter::MakeBlur((SkBlurStyle)i,
122 }
123 }
124
125 SkString getName() const override { return SkString(fName); }
126
127 SkISize getISize() override { return {860, 820}; }
128
129 void onDraw(SkCanvas* canvas) override {
130 canvas->translate(STROKE_WIDTH*3/2, STROKE_WIDTH*3/2);
131
132 SkRect r = { 0, 0, 100, 50 };
133 SkScalar scales[] = { SK_Scalar1, 0.6f };
134
135 for (size_t s = 0; s < std::size(scales); ++s) {
136 canvas->save();
137 for (size_t f = 0; f < std::size(fMaskFilters); ++f) {
139 paint.setMaskFilter(fMaskFilters[f]);
140 paint.setAlpha(fAlpha);
141
142 SkPaint paintWithRadial = paint;
143 paintWithRadial.setShader(make_radial());
144
145 constexpr Proc procs[] = {
147 };
148
149 canvas->save();
150 canvas->scale(scales[s], scales[s]);
151 this->drawProcs(canvas, r, paint, false, procs, std::size(procs));
152 canvas->translate(r.width() * 4/3, 0);
153 this->drawProcs(canvas, r, paintWithRadial, false, procs, std::size(procs));
154 canvas->translate(r.width() * 4/3, 0);
155 this->drawProcs(canvas, r, paint, true, procs, std::size(procs));
156 canvas->translate(r.width() * 4/3, 0);
157 this->drawProcs(canvas, r, paintWithRadial, true, procs, std::size(procs));
158 canvas->restore();
159
160 canvas->translate(0, std::size(procs) * r.height() * 4/3 * scales[s]);
161 }
162 canvas->restore();
163 canvas->translate(4 * r.width() * 4/3 * scales[s], 0);
164 }
165 }
166
167 void drawProcs(SkCanvas* canvas, const SkRect& r, const SkPaint& paint,
168 bool doClip, const Proc procs[], size_t procsCount) {
169 SkAutoCanvasRestore acr(canvas, true);
170 for (size_t i = 0; i < procsCount; ++i) {
171 if (doClip) {
172 SkRect clipRect(r);
174 canvas->save();
175 canvas->clipRect(r);
176 }
177 procs[i](canvas, r, paint);
178 if (doClip) {
179 canvas->restore();
180 }
181 canvas->translate(0, r.height() * 4/3);
182 }
183 }
184};
185
186DEF_SIMPLE_GM(blurrect_gallery, canvas, 1200, 1024) {
187 const int fGMWidth = 1200;
188 const int fPadding = 10;
189 const int fMargin = 100;
190
191 const int widths[] = {25, 5, 5, 100, 150, 25};
192 const int heights[] = {100, 100, 5, 25, 150, 25};
194 const float radii[] = {20, 5, 10};
195
196 canvas->translate(50,20);
197
198 int cur_x = 0;
199 int cur_y = 0;
200
201 int max_height = 0;
202
203 for (size_t i = 0 ; i < std::size(widths) ; i++) {
204 int width = widths[i];
205 int height = heights[i];
206 SkRect r;
208 SkAutoCanvasRestore autoRestore(canvas, true);
209
210 for (size_t j = 0 ; j < std::size(radii) ; j++) {
211 float radius = radii[j];
212 for (size_t k = 0 ; k < std::size(styles) ; k++) {
213 SkBlurStyle style = styles[k];
214
215 SkMaskBuilder mask;
217 &mask, r, style)) {
218 continue;
219 }
220
221 SkAutoMaskFreeImage amfi(mask.image());
222
223 SkBitmap bm;
224 bm.installMaskPixels(mask);
225
226 if (cur_x + bm.width() >= fGMWidth - fMargin) {
227 cur_x = 0;
228 cur_y += max_height + fPadding;
229 max_height = 0;
230 }
231
232 canvas->save();
233 canvas->translate((SkScalar)cur_x, (SkScalar)cur_y);
234 canvas->translate(-(bm.width() - r.width())/2, -(bm.height()-r.height())/2);
235 canvas->drawImage(bm.asImage(), 0.f, 0.f);
236 canvas->restore();
237
238 cur_x += bm.width() + fPadding;
239 if (bm.height() > max_height)
240 max_height = bm.height();
241 }
242 }
243 }
244}
245
246namespace skiagm {
247
248// Compares actual blur rects with reference masks created by the GM. Animates sigma in viewer.
249class BlurRectCompareGM : public GM {
250protected:
251 SkString getName() const override { return SkString("blurrect_compare"); }
252
253 SkISize getISize() override { return {900, 1220}; }
254
255 void onOnceBeforeDraw() override { this->prepareReferenceMasks(); }
256
257 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
258 if (canvas->imageInfo().colorType() == kUnknown_SkColorType ||
259 (canvas->recordingContext() && !canvas->recordingContext()->asDirectContext())) {
260 *errorMsg = "Not supported when recording, relies on canvas->makeSurface()";
261 return DrawResult::kSkip;
262 }
263 int32_t ctxID = canvas->recordingContext() ? canvas->recordingContext()->priv().contextID()
264 : 0;
265 if (fRecalcMasksForAnimation || !fActualMasks[0][0][0] || ctxID != fLastContextUniqueID) {
266 if (fRecalcMasksForAnimation) {
267 // Sigma is changing so references must also be recalculated.
268 this->prepareReferenceMasks();
269 }
270 this->prepareActualMasks(canvas);
271 this->prepareMaskDifferences(canvas);
272 fLastContextUniqueID = ctxID;
273 fRecalcMasksForAnimation = false;
274 }
275 canvas->clear(SK_ColorBLACK);
276 static constexpr float kMargin = 30;
277 float totalW = 0;
278 for (auto w : kSizes) {
279 totalW += w + kMargin;
280 }
281 canvas->translate(kMargin, kMargin);
282 for (int mode = 0; mode < 3; ++mode) {
283 canvas->save();
284 for (size_t sigmaIdx = 0; sigmaIdx < kNumSigmas; ++sigmaIdx) {
285 auto sigma = kSigmas[sigmaIdx] + fSigmaAnimationBoost;
286 for (size_t heightIdx = 0; heightIdx < kNumSizes; ++heightIdx) {
287 auto h = kSizes[heightIdx];
288 canvas->save();
289 for (size_t widthIdx = 0; widthIdx < kNumSizes; ++widthIdx) {
290 auto w = kSizes[widthIdx];
292 paint.setColor(SK_ColorWHITE);
293 SkImage* img;
294 switch (mode) {
295 case 0:
296 img = fReferenceMasks[sigmaIdx][heightIdx][widthIdx].get();
297 break;
298 case 1:
299 img = fActualMasks[sigmaIdx][heightIdx][widthIdx].get();
300 break;
301 case 2:
302 img = fMaskDifferences[sigmaIdx][heightIdx][widthIdx].get();
303 // The error images are opaque, use kPlus so they are additive if
304 // the overlap between test cases.
305 paint.setBlendMode(SkBlendMode::kPlus);
306 break;
307 }
308 auto pad = PadForSigma(sigma);
309 canvas->drawImage(img, -pad, -pad, SkSamplingOptions(), &paint);
310#if 0 // Uncomment to hairline stroke around blurred rect in red on top of the blur result.
311 // The rect is defined at integer coords. We inset by 1/2 pixel so our stroke lies on top
312 // of the edge pixels.
314 stroke.setColor(SK_ColorRED);
315 stroke.setStrokeWidth(0.f);
317 canvas->drawRect(SkRect::MakeWH(w, h).makeInset(0.5, 0.5), stroke);
318#endif
319 canvas->translate(w + kMargin, 0.f);
320 }
321 canvas->restore();
322 canvas->translate(0, h + kMargin);
323 }
324 }
325 canvas->restore();
326 canvas->translate(totalW + 2 * kMargin, 0);
327 }
328 return DrawResult::kOk;
329 }
330 bool onAnimate(double nanos) override {
331 fSigmaAnimationBoost = TimeUtils::SineWave(nanos, 5, 2.5f, 0.f, 2.f);
332 fRecalcMasksForAnimation = true;
333 return true;
334 }
335
336private:
337 void prepareReferenceMasks() {
338 auto create_reference_mask = [](int w, int h, float sigma, int numSubpixels) {
339 int pad = PadForSigma(sigma);
340 int maskW = w + 2 * pad;
341 int maskH = h + 2 * pad;
342 // We'll do all our calculations at subpixel resolution, so adjust params
343 w *= numSubpixels;
344 h *= numSubpixels;
345 sigma *= numSubpixels;
346 auto scale = SK_ScalarRoot2Over2 / sigma;
347 auto def_integral_approx = [scale](float a, float b) {
348 return 0.5f * (std::erf(b * scale) - std::erf(a * scale));
349 };
350 // Do the x-pass. Above/below rect are rows of zero. All rows that intersect the rect
351 // are the same. The row is calculated and stored at subpixel resolution.
352 SkASSERT(!(numSubpixels & 0b1));
353 std::unique_ptr<float[]> row(new float[maskW * numSubpixels]);
354 for (int col = 0; col < maskW * numSubpixels; ++col) {
355 // Compute distance to rect left in subpixel units
356 float ldiff = numSubpixels * pad - (col + 0.5f);
357 float rdiff = ldiff + w;
358 row[col] = def_integral_approx(ldiff, rdiff);
359 }
360 // y-pass
361 SkBitmap bmp;
362 bmp.allocPixels(SkImageInfo::MakeA8(maskW, maskH));
363 std::unique_ptr<float[]> accums(new float[maskW]);
364 const float accumScale = 1.f / (numSubpixels * numSubpixels);
365 for (int y = 0; y < maskH; ++y) {
366 // Initialize subpixel accumulation buffer for this row.
367 std::fill_n(accums.get(), maskW, 0);
368 for (int ys = 0; ys < numSubpixels; ++ys) {
369 // At each subpixel we want to integrate over the kernel centered at the
370 // subpixel multiplied by the x-pass. The x-pass is zero above and below the
371 // rect and constant valued from rect top to rect bottom. So we can get the
372 // integral of just the kernel from rect top to rect bottom and multiply by
373 // the single x-pass value from our precomputed row.
374 float tdiff = numSubpixels * pad - (y * numSubpixels + ys + 0.5f);
375 float bdiff = tdiff + h;
376 auto integral = def_integral_approx(tdiff, bdiff);
377 for (int x = 0; x < maskW; ++x) {
378 for (int xs = 0; xs < numSubpixels; ++xs) {
379 int rowIdx = x * numSubpixels + xs;
380 accums[x] += integral * row[rowIdx];
381 }
382 }
383 }
384 for (int x = 0; x < maskW; ++x) {
385 auto result = accums[x] * accumScale;
386 *bmp.getAddr8(x, y) = SkToU8(sk_float_round2int(255.f * result));
387 }
388 }
389 return bmp.asImage();
390 };
391
392 // Number of times to subsample (in both X and Y). If fRecalcMasksForAnimation is true
393 // then we're animating, don't subsample as much to keep fps higher.
394 const int numSubpixels = fRecalcMasksForAnimation ? 2 : 8;
395
396 for (size_t sigmaIdx = 0; sigmaIdx < kNumSigmas; ++sigmaIdx) {
397 auto sigma = kSigmas[sigmaIdx] + fSigmaAnimationBoost;
398 for (size_t heightIdx = 0; heightIdx < kNumSizes; ++heightIdx) {
399 auto h = kSizes[heightIdx];
400 for (size_t widthIdx = 0; widthIdx < kNumSizes; ++widthIdx) {
401 auto w = kSizes[widthIdx];
402 fReferenceMasks[sigmaIdx][heightIdx][widthIdx] =
403 create_reference_mask(w, h, sigma, numSubpixels);
404 }
405 }
406 }
407 }
408
409 void prepareActualMasks(SkCanvas* canvas) {
410 for (size_t sigmaIdx = 0; sigmaIdx < kNumSigmas; ++sigmaIdx) {
411 auto sigma = kSigmas[sigmaIdx] + fSigmaAnimationBoost;
412 for (size_t heightIdx = 0; heightIdx < kNumSizes; ++heightIdx) {
413 auto h = kSizes[heightIdx];
414 for (size_t widthIdx = 0; widthIdx < kNumSizes; ++widthIdx) {
415 auto w = kSizes[widthIdx];
416 auto pad = PadForSigma(sigma);
417 auto ii = SkImageInfo::MakeA8(w + 2 * pad, h + 2 * pad);
418 auto surf = canvas->makeSurface(ii);
419 if (!surf) {
420 // Some GPUs don't have renderable A8 :(
421 surf = canvas->makeSurface(ii.makeColorType(kRGBA_8888_SkColorType));
422 if (!surf) {
423 return;
424 }
425 }
426 auto rect = SkRect::MakeXYWH(pad, pad, w, h);
428 // Color doesn't matter if we're rendering to A8 but does if we promoted to
429 // RGBA above.
430 paint.setColor(SK_ColorWHITE);
431 paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, sigma));
432 surf->getCanvas()->drawRect(rect, paint);
433 fActualMasks[sigmaIdx][heightIdx][widthIdx] = surf->makeImageSnapshot();
434 }
435 }
436 }
437 }
438
439 void prepareMaskDifferences(SkCanvas* canvas) {
440 for (size_t sigmaIdx = 0; sigmaIdx < kNumSigmas; ++sigmaIdx) {
441 for (size_t heightIdx = 0; heightIdx < kNumSizes; ++heightIdx) {
442 for (size_t widthIdx = 0; widthIdx < kNumSizes; ++widthIdx) {
443 const auto& r = fReferenceMasks[sigmaIdx][heightIdx][widthIdx];
444 const auto& a = fActualMasks[sigmaIdx][heightIdx][widthIdx];
445 auto& d = fMaskDifferences[sigmaIdx][heightIdx][widthIdx];
446 // The actual image might not be present if we're on an abandoned GrContext.
447 if (!a) {
448 d.reset();
449 continue;
450 }
451 SkASSERT(r->width() == a->width());
452 SkASSERT(r->height() == a->height());
453 auto ii = SkImageInfo::Make(r->width(), r->height(),
455 auto surf = canvas->makeSurface(ii);
456 if (!surf) {
457 return;
458 }
459 // We visualize the difference by turning both the alpha masks into opaque green
460 // images (where alpha becomes the green channel) and then perform a
461 // SkBlendMode::kDifference between them.
462 SkPaint filterPaint;
463 filterPaint.setColor(SK_ColorWHITE);
464 // Actually 8 * alpha becomes green to really highlight differences.
465 static constexpr float kGreenifyM[] = {0, 0, 0, 0, 0,
466 0, 0, 0, 8, 0,
467 0, 0, 0, 0, 0,
468 0, 0, 0, 0, 1};
469 auto greenifyCF = SkColorFilters::Matrix(kGreenifyM);
471 paint.setBlendMode(SkBlendMode::kSrc);
472 paint.setColorFilter(std::move(greenifyCF));
473 surf->getCanvas()->drawImage(a, 0, 0, SkSamplingOptions(), &paint);
474 paint.setBlendMode(SkBlendMode::kDifference);
475 surf->getCanvas()->drawImage(r, 0, 0, SkSamplingOptions(), &paint);
476 d = surf->makeImageSnapshot();
477 }
478 }
479 }
480 }
481
482 // Per side padding around mask images for a sigma. Make this overly generous to ensure bugs
483 // related to big blurs are fully visible.
484 static int PadForSigma(float sigma) { return sk_float_ceil2int(4 * sigma); }
485
486 inline static constexpr int kSizes[] = {1, 2, 4, 8, 16, 32};
487 inline static constexpr float kSigmas[] = {0.5f, 1.2f, 2.3f, 3.9f, 7.4f};
488 inline static constexpr size_t kNumSizes = std::size(kSizes);
489 inline static constexpr size_t kNumSigmas = std::size(kSigmas);
490
491 sk_sp<SkImage> fReferenceMasks[kNumSigmas][kNumSizes][kNumSizes];
492 sk_sp<SkImage> fActualMasks[kNumSigmas][kNumSizes][kNumSizes];
493 sk_sp<SkImage> fMaskDifferences[kNumSigmas][kNumSizes][kNumSizes];
494 int32_t fLastContextUniqueID;
495 // These are used only when animating.
496 float fSigmaAnimationBoost = 0;
497 bool fRecalcMasksForAnimation = false;
498};
499
500} // namespace skiagm
501
502//////////////////////////////////////////////////////////////////////////////
503
504DEF_GM(return new BlurRectGM("blurrects", 0xFF);)
506
507//////////////////////////////////////////////////////////////////////////////
508
509DEF_SIMPLE_GM(blur_matrix_rect, canvas, 650, 685) {
510 static constexpr auto kRect = SkRect::MakeWH(14, 60);
511 static constexpr float kSigmas[] = {0.5f, 1.2f, 2.3f, 3.9f, 7.4f};
512 static constexpr size_t kNumSigmas = std::size(kSigmas);
513
514 const SkPoint c = {kRect.centerX(), kRect.centerY()};
515
516 std::vector<SkMatrix> matrices;
517
518 matrices.push_back(SkMatrix::RotateDeg(4.f, c));
519
520 matrices.push_back(SkMatrix::RotateDeg(63.f, c));
521
522 matrices.push_back(SkMatrix::RotateDeg(30.f, c));
523 matrices.back().preScale(1.1f, .5f);
524
525 matrices.push_back(SkMatrix::RotateDeg(147.f, c));
526 matrices.back().preScale(3.f, .1f);
527
529 mirror.setAll(0, 1, 0,
530 1, 0, 0,
531 0, 0, 1);
532 matrices.push_back(SkMatrix::Concat(mirror, matrices.back()));
533
534 matrices.push_back(SkMatrix::RotateDeg(197.f, c));
535 matrices.back().preSkew(.3f, -.5f);
536
537 auto bounds = SkRect::MakeEmpty();
538 for (const auto& m : matrices) {
539 SkRect mapped;
540 m.mapRect(&mapped, kRect);
541 bounds.joinNonEmptyArg(mapped.makeSorted());
542 }
543 float blurPad = 2.f*kSigmas[kNumSigmas - 1];
544 bounds.outset(blurPad, blurPad);
545 canvas->translate(-bounds.left(), -bounds.top());
546 for (auto sigma : kSigmas) {
548 paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, sigma));
549 canvas->save();
550 for (const auto& m : matrices) {
551 canvas->save();
552 canvas->concat(m);
553 canvas->drawRect(kRect, paint);
554 canvas->restore();
555 canvas->translate(0, bounds.height());
556 }
557 canvas->restore();
558 canvas->translate(bounds.width(), 0);
559 }
560}
SkPoint pos
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
static unsigned mirror(SkFixed fx, int max)
@ kPlus
r = min(s + d, 1)
@ kDifference
rc = s + d - 2*(min(s*da, d*sa)), ra = kSrcOver
SkBlurStyle
Definition: SkBlurTypes.h:11
@ kOuter_SkBlurStyle
nothing inside, fuzzy outside
Definition: SkBlurTypes.h:14
@ kInner_SkBlurStyle
fuzzy inside, nothing outside
Definition: SkBlurTypes.h:15
@ kNormal_SkBlurStyle
fuzzy inside and outside
Definition: SkBlurTypes.h:12
@ kLastEnum_SkBlurStyle
Definition: SkBlurTypes.h:17
unsigned U8CPU
Definition: SkCPUTypes.h:18
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kUnknown_SkColorType
uninitialized
Definition: SkColorType.h:20
uint32_t SkColor
Definition: SkColor.h:37
uint8_t SkAlpha
Definition: SkColor.h:26
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
constexpr SkColor SK_ColorGREEN
Definition: SkColor.h:131
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
#define sk_float_ceil2int(x)
#define sk_float_round2int(x)
std::unique_ptr< uint8_t, SkFunctionObject< SkMaskBuilder::FreeImage > > SkAutoMaskFreeImage
Definition: SkMask.h:316
#define SK_Scalar1
Definition: SkScalar.h:18
#define SkScalarAve(a, b)
Definition: SkScalar.h:74
#define SkIntToScalar(x)
Definition: SkScalar.h:57
static SkScalar SkScalarInterp(SkScalar A, SkScalar B, SkScalar t)
Definition: SkScalar.h:131
#define SK_ScalarRoot2Over2
Definition: SkScalar.h:23
SkTileMode
Definition: SkTileMode.h:13
constexpr uint8_t SkToU8(S x)
Definition: SkTo.h:22
const SkScalar widths[]
Definition: StrokerTest.cpp:39
constexpr int kMargin
Definition: aaxfermodes.cpp:31
static void draw_donut(SkCanvas *canvas, const SkRect &r, const SkPaint &p)
Definition: blurrect.cpp:48
#define STROKE_WIDTH
Definition: blurrect.cpp:40
static void draw_donut_skewed(SkCanvas *canvas, const SkRect &r, const SkPaint &p)
Definition: blurrect.cpp:64
static void fill_rect(SkCanvas *canvas, const SkRect &r, const SkPaint &p)
Definition: blurrect.cpp:44
DEF_SIMPLE_GM(blurrect_gallery, canvas, 1200, 1024)
Definition: blurrect.cpp:186
void(* PaintProc)(SkPaint *, SkScalar width)
Definition: blurrect.cpp:107
static sk_sp< SkShader > make_radial()
Definition: blurrect.cpp:85
void(* Proc)(SkCanvas *, const SkRect &, const SkPaint &)
Definition: blurrect.cpp:42
BlurRectGM(const char name[], U8CPU alpha)
Definition: blurrect.cpp:111
uint32_t contextID() const
virtual GrDirectContext * asDirectContext()
GrRecordingContextPriv priv()
bool installMaskPixels(SkMaskBuilder &mask)
Definition: SkBitmap.cpp:349
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:258
sk_sp< SkImage > asImage() const
Definition: SkBitmap.cpp:645
uint8_t * getAddr8(int x, int y) const
Definition: SkBitmap.h:1270
int width() const
Definition: SkBitmap.h:149
int height() const
Definition: SkBitmap.h:158
static bool BlurRect(SkScalar sigma, SkMaskBuilder *dst, const SkRect &src, SkBlurStyle, SkIPoint *margin=nullptr, SkMaskBuilder::CreateMode createMode=SkMaskBuilder::kComputeBoundsAndRenderImage_CreateMode)
Definition: SkBlurMask.cpp:407
static SkScalar SK_SPI ConvertRadiusToSigma(SkScalar radius)
Definition: SkBlurMask.cpp:39
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void clipRect(const SkRect &rect, SkClipOp op, bool doAntiAlias)
Definition: SkCanvas.cpp:1361
void restore()
Definition: SkCanvas.cpp:461
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
sk_sp< SkSurface > makeSurface(const SkImageInfo &info, const SkSurfaceProps *props=nullptr)
Definition: SkCanvas.cpp:1195
virtual GrRecordingContext * recordingContext() const
Definition: SkCanvas.cpp:1637
void clear(SkColor color)
Definition: SkCanvas.h:1199
int save()
Definition: SkCanvas.cpp:447
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
void scale(SkScalar sx, SkScalar sy)
Definition: SkCanvas.cpp:1289
void concat(const SkMatrix &matrix)
Definition: SkCanvas.cpp:1318
SkImageInfo imageInfo() const
Definition: SkCanvas.cpp:1206
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition: SkCanvas.h:1528
static sk_sp< SkColorFilter > Matrix(const SkColorMatrix &)
static sk_sp< SkShader > MakeTwoPointConical(const SkPoint &start, SkScalar startRadius, const SkPoint &end, SkScalar endRadius, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
static sk_sp< SkMaskFilter > MakeBlur(SkBlurStyle style, SkScalar sigma, bool respectCTM=true)
static SkMatrix RotateDeg(SkScalar deg)
Definition: SkMatrix.h:104
static SkMatrix Concat(const SkMatrix &a, const SkMatrix &b)
Definition: SkMatrix.h:1775
void setColor(SkColor color)
Definition: SkPaint.cpp:119
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
void setShader(sk_sp< SkShader > shader)
T * get() const
Definition: SkRefCnt.h:303
void onOnceBeforeDraw() override
Definition: blurrect.cpp:255
SkISize getISize() override
Definition: blurrect.cpp:253
SkString getName() const override
Definition: blurrect.cpp:251
DrawResult onDraw(SkCanvas *canvas, SkString *errorMsg) override
Definition: blurrect.cpp:257
bool onAnimate(double nanos) override
Definition: blurrect.cpp:330
Definition: gm.h:110
const Paint & paint
Definition: color_source.cc:38
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
float SkScalar
Definition: extension.cpp:12
static bool b
struct MyStruct s
struct MyStruct a[10]
GAsyncResult * result
#define DEF_GM(CODE)
Definition: gm.h:40
double y
double x
Optional< SkRect > bounds
Definition: SkRecords.h:189
clipRect(r.rect, r.opAA.op(), r.opAA.aa())) template<> void Draw
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
PODArray< SkColor > colors
Definition: SkRecords.h:276
static float SineWave(double time, float periodInSecs, float phaseInSecs, float min, float max)
Definition: TimeUtils.h:48
constexpr std::array< std::array< float, 2 >, 2 > kRect
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
static SkPath scale(const SkPath &path, SkScalar scale)
Definition: patheffects.cpp:68
SkSamplingOptions(SkFilterMode::kLinear))
DrawResult
Definition: gm.h:104
SkScalar w
SkScalar h
int32_t height
int32_t width
const Scalar scale
Definition: SkSize.h:16
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
SkColorType colorType() const
Definition: SkImageInfo.h:373
static SkImageInfo MakeA8(int width, int height)
uint8_t *& image()
Definition: SkMask.h:236
void set(float x, float y)
Definition: SkPoint_impl.h:200
SkRect makeSorted() const
Definition: SkRect.h:1330
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595
void setWH(float width, float height)
Definition: SkRect.h:944
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
constexpr float height() const
Definition: SkRect.h:769
constexpr float width() const
Definition: SkRect.h:762
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609