Flutter Engine
The Flutter Engine
rrects.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 "gm/gm.h"
15#include "include/core/SkRect.h"
17#include "include/core/SkSize.h"
32
33#include <memory>
34#include <utility>
35
36namespace skiagm {
37
38///////////////////////////////////////////////////////////////////////////////
39
40class RRectGM : public GM {
41public:
42 enum Type {
48 };
49 RRectGM(Type type) : fType(type) { }
50
51protected:
52
53 void onOnceBeforeDraw() override {
54 this->setBGColor(0xFFDDDDDD);
55 this->setUpRRects();
56 }
57
58 SkString getName() const override {
59 SkString name("rrect");
60 switch (fType) {
61 case kBW_Draw_Type:
62 name.append("_draw_bw");
63 break;
64 case kAA_Draw_Type:
65 name.append("_draw_aa");
66 break;
67 case kBW_Clip_Type:
68 name.append("_clip_bw");
69 break;
70 case kAA_Clip_Type:
71 name.append("_clip_aa");
72 break;
73 case kEffect_Type:
74 name.append("_effect");
75 break;
76 }
77 return name;
78 }
79
80 SkISize getISize() override { return SkISize::Make(kImageWidth, kImageHeight); }
81
82 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
84
85 auto rContext = canvas->recordingContext();
86 if (kEffect_Type == fType && (!sdc || !rContext)) {
88 return DrawResult::kSkip;
89 }
90
92 if (kAA_Draw_Type == fType) {
93 paint.setAntiAlias(true);
94 }
95
96 if (fType == kBW_Clip_Type || fType == kAA_Clip_Type) {
97 // Add a gradient to the paint to ensure local coords are respected.
98 SkPoint pts[3] = {{0, 0}, {1.5f, 1}};
100 paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, 2,
102 }
103
104#ifdef SK_DEBUG
105 const SkRect kMaxImageBound = SkRect::MakeWH(SkIntToScalar(kImageWidth),
106 SkIntToScalar(kImageHeight));
107#endif
108
109 int lastEdgeType = (kEffect_Type == fType) ? (int) GrClipEdgeType::kLast: 0;
110
111 int y = 1;
112 for (int et = 0; et <= lastEdgeType; ++et) {
113 int x = 1;
114 for (int curRRect = 0; curRRect < kNumRRects; ++curRRect) {
115 bool drew = true;
116#ifdef SK_DEBUG
117 if (curRRect != kNumRRects - 1) { // skip last rrect, which is large but clipped
118 SkRect imageSpaceBounds = fRRects[curRRect].getBounds();
119 imageSpaceBounds.offset(SkIntToScalar(x), SkIntToScalar(y));
120 SkASSERT(kMaxImageBound.contains(imageSpaceBounds));
121 }
122#endif
123 canvas->save();
125
126 SkRRect rrect = fRRects[curRRect];
127 if (curRRect == kNumRRects - 1) {
128 canvas->clipRect({0, 0, kTileX - 2, kTileY - 2});
129 canvas->translate(-0.14f * rrect.rect().width(),
130 -0.14f * rrect.rect().height());
131 }
132 if (kEffect_Type == fType) {
133 fRRects[curRRect].transform(canvas->getLocalToDeviceAs3x3(), &rrect);
134
135 GrClipEdgeType edgeType = (GrClipEdgeType) et;
136 const auto& caps = *rContext->priv().caps()->shaderCaps();
137 auto [success, fp] = GrRRectEffect::Make(/*inputFP=*/nullptr,
138 edgeType, rrect, caps);
139 if (success) {
140 GrPaint grPaint;
142 grPaint.setCoverageFragmentProcessor(std::move(fp));
143 grPaint.setColor4f({ 0, 0, 0, 1.f });
144
146 bounds.intersect(SkRect::MakeXYWH(x, y, kTileX - 2, kTileY - 2));
147 if (et >= (int) GrClipEdgeType::kInverseFillBW) {
148 bounds.outset(2.f, 2.f);
149 }
150
152 rContext, std::move(grPaint), SkMatrix::I(), bounds));
153 } else {
154 drew = false;
155 }
156 } else if (fType == kBW_Clip_Type || fType == kAA_Clip_Type) {
157 bool aaClip = (kAA_Clip_Type == fType);
158 canvas->clipRRect(rrect, aaClip);
159 canvas->setMatrix(SkMatrix::Scale(kImageWidth, kImageHeight));
160 canvas->drawRect(SkRect::MakeWH(1, 1), paint);
161 } else {
162 canvas->drawRRect(rrect, paint);
163 }
164
165 canvas->restore();
166 if (drew) {
167 x = x + kTileX;
168 if (x > kImageWidth) {
169 x = 1;
170 y += kTileY;
171 }
172 }
173 }
174 if (x != 1) {
175 y += kTileY;
176 }
177 }
178 return DrawResult::kOk;
179 }
180
181 void setUpRRects() {
182 // each RRect must fit in a 0x0 -> (kTileX-2)x(kTileY-2) block. These will be tiled across
183 // the screen in kTileX x kTileY tiles. The extra empty pixels on each side are for AA.
184
185 // simple cases
186 fRRects[0].setRect(SkRect::MakeWH(kTileX-2, kTileY-2));
187 fRRects[1].setOval(SkRect::MakeWH(kTileX-2, kTileY-2));
188 fRRects[2].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 10, 10);
189 fRRects[3].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 10, 5);
190 // small circular corners are an interesting test case for gpu clipping
191 fRRects[4].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 1, 1);
192 fRRects[5].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 0.5f, 0.5f);
193 fRRects[6].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 0.2f, 0.2f);
194
195 // The first complex case needs special handling since it is a square
196 fRRects[kNumSimpleCases].setRectRadii(SkRect::MakeWH(kTileY-2, kTileY-2), gRadii[0]);
197 for (size_t i = 1; i < std::size(gRadii); ++i) {
198 fRRects[kNumSimpleCases+i].setRectRadii(SkRect::MakeWH(kTileX-2, kTileY-2), gRadii[i]);
199 }
200 // The last case is larger than kTileX-2 x kTileY-2 but will be drawn at an offset
201 // into a clip rect that respects the tile size and highlights the rrect's corner curve.
202 fRRects[kNumRRects - 1].setRectXY({9.f, 9.f, 1699.f, 1699.f}, 843.749f, 843.75f);
203 }
204
205private:
206 Type fType;
207
208 inline static constexpr int kImageWidth = 640;
209 inline static constexpr int kImageHeight = 480;
210
211 inline static constexpr int kTileX = 80;
212 inline static constexpr int kTileY = 40;
213
214 inline static constexpr int kNumSimpleCases = 7;
215 inline static constexpr int kNumComplexCases = 35;
216
217 static const SkVector gRadii[kNumComplexCases][4];
218
219 inline static constexpr int kNumRRects = kNumSimpleCases + kNumComplexCases + 1 /* extra big */;
220 SkRRect fRRects[kNumRRects];
221
222 using INHERITED = GM;
223};
224
225// Radii for the various test cases. Order is UL, UR, LR, LL
226const SkVector RRectGM::gRadii[kNumComplexCases][4] = {
227 // a circle
228 { { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY } },
229
230 // odd ball cases
231 { { 8, 8 }, { 32, 32 }, { 8, 8 }, { 32, 32 } },
232 { { 16, 8 }, { 8, 16 }, { 16, 8 }, { 8, 16 } },
233 { { 0, 0 }, { 16, 16 }, { 8, 8 }, { 32, 32 } },
234
235 // UL
236 { { 30, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
237 { { 30, 15 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
238 { { 15, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
239
240 // UR
241 { { 0, 0 }, { 30, 30 }, { 0, 0 }, { 0, 0 } },
242 { { 0, 0 }, { 30, 15 }, { 0, 0 }, { 0, 0 } },
243 { { 0, 0 }, { 15, 30 }, { 0, 0 }, { 0, 0 } },
244
245 // LR
246 { { 0, 0 }, { 0, 0 }, { 30, 30 }, { 0, 0 } },
247 { { 0, 0 }, { 0, 0 }, { 30, 15 }, { 0, 0 } },
248 { { 0, 0 }, { 0, 0 }, { 15, 30 }, { 0, 0 } },
249
250 // LL
251 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 30 } },
252 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 15 } },
253 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 15, 30 } },
254
255 // over-sized radii
256 { { 0, 0 }, { 100, 400 }, { 0, 0 }, { 0, 0 } },
257 { { 0, 0 }, { 400, 400 }, { 0, 0 }, { 0, 0 } },
258 { { 400, 400 }, { 400, 400 }, { 400, 400 }, { 400, 400 } },
259
260 // circular corner tabs
261 { { 0, 0 }, { 20, 20 }, { 20, 20 }, { 0, 0 } },
262 { { 20, 20 }, { 20, 20 }, { 0, 0 }, { 0, 0 } },
263 { { 0, 0 }, { 0, 0 }, { 20, 20 }, { 20, 20 } },
264 { { 20, 20 }, { 0, 0 }, { 0, 0 }, { 20, 20 } },
265
266 // small radius circular corner tabs
267 { { 0, 0 }, { 0.2f, 0.2f }, { 0.2f, 0.2f }, { 0, 0 } },
268 { { 0.3f, 0.3f }, { 0.3f, .3f }, { 0, 0 }, { 0, 0 } },
269
270 // single circular corner cases
271 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 15, 15 } },
272 { { 0, 0 }, { 0, 0 }, { 15, 15 }, { 0, 0 } },
273 { { 0, 0 }, { 15, 15 }, { 0, 0 }, { 0, 0 } },
274 { { 15, 15 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
275
276 // nine patch elliptical
277 { { 5, 7 }, { 8, 7 }, { 8, 12 }, { 5, 12 } },
278 { { 0, 7 }, { 8, 7 }, { 8, 12 }, { 0, 12 } },
279
280 // nine patch elliptical, small radii
281 { { 0.4f, 7 }, { 8, 7 }, { 8, 12 }, { 0.4f, 12 } },
282 { { 0.4f, 0.4f }, { 8, 0.4f }, { 8, 12 }, { 0.4f, 12 } },
283 { { 20, 0.4f }, { 18, 0.4f }, { 18, 0.4f }, { 20, 0.4f } },
284 { { 0.3f, 0.4f }, { 0.3f, 0.4f }, { 0.3f, 0.4f }, { 0.3f, 0.4f } },
285
286};
287
288///////////////////////////////////////////////////////////////////////////////
289
295
296// This GM is designed to test a variety of fill and stroked rectangles and round rectangles, with
297// different stroke width and join type scenarios. The geometry parameters are chosen so that
298// Graphite should be able to use its AnalyticRoundRectRenderStep and batch into a single draw.
299DEF_SIMPLE_GM(stroke_rect_rrects, canvas, 1350, 700) {
300 canvas->scale(0.5f, 0.5f);
301 canvas->translate(50.f, 50.f);
302
303 auto draw = [&](int cx, int cy, bool rrect, float width, SkPaint::Join join) {
304 SkPaint p;
305 p.setAntiAlias(true);
306 p.setStrokeWidth(width);
308 p.setStrokeJoin(join);
309
310 canvas->save();
311 canvas->translate(cx * 110.f, cy * 110.f);
312 float dx = cx % 2 ? 0.5f : 0.f;
313 float dy = cy % 2 ? 0.5f : 0.f;
314 SkRect rect = SkRect::MakeWH(50.f, 40.f);
315 rect.offset(dx, dy);
316
317 if (width < 0.0) {
318 rect.outset(25.f, 25.f); // make it the same size as the largest stroke
319 }
320
321 // Filled rounded rects can have arbitrary corners
322 float cornerScale = std::min(rect.width(), rect.height());
323 SkVector outerRadii[4] = { { 0.25f * cornerScale, 0.75f * cornerScale },
324 { 0.f, 0.f},
325 { 0.50f * cornerScale, 0.50f * cornerScale },
326 { 0.75f * cornerScale, 0.25f * cornerScale } };
327 // Stroked rounded rects will only have circular corners so that they remain compatible with
328 // Graphite's AnalyticRoundRectRenderStep's requirements.
329 SkVector strokeRadii[4] = { { 0.25f * cornerScale, 0.25f * cornerScale },
330 { 0.f, 0.f }, // this corner matches join type
331 { 0.50f * cornerScale, 0.50f * cornerScale },
332 { 0.75f * cornerScale, 0.75f * cornerScale } };
333
334 if (rrect) {
335 SkRRect r;
336 if (width >= 0.0) {
337 r.setRectRadii(rect, strokeRadii);
338 } else {
339 r.setRectRadii(rect, outerRadii);
340 }
341 canvas->drawRRect(r, p);
342 } else {
343 canvas->drawRect(rect, p);
344 }
345 canvas->restore();
346 };
347
348 // The stroke widths are chosen to test when the inner stroke edges have completely crossed
349 // over (50); when the inner corner circles intersect each other (30); a typical "nice"
350 // stroke (10); a skinny stroke (1); and a hairline (0).
351 int i = 0;
352 for (float width : {-1.f, 50.f, 30.f, 10.f, 1.f, 0.f}) {
353 int j = 0;
357 if (width < 0 && join != SkPaint::kMiter_Join) {
358 continue; // Don't repeat fills, since join type is ignored
359 }
360 draw(2*i, 2*j, false, width, join);
361 draw(2*i+1, 2*j, false, width, join);
362 draw(2*i, 2*j+1, false, width, join);
363 draw(2*i+1, 2*j+1, false, width, join);
364 j++;
365 }
366 i++;
367 }
368
369 canvas->translate(0.f, 50.f);
370
371 i = 0;
372 for (float width : {-1.f, 50.f, 30.f, 10.f, 1.f, 0.f}) {
373 int j = 3;
377 if (width < 0 && join != SkPaint::kMiter_Join) {
378 continue;
379 }
380 draw(2*i, 2*j, true, width, join);
381 draw(2*i+1, 2*j, true, width, join);
382 draw(2*i, 2*j+1, true, width, join);
383 draw(2*i+1, 2*j+1, true, width, join);
384 j++;
385 }
386 i++;
387 }
388
389 // Rotated "footballs"
390 auto drawComplex = [&](int cx, int cy, float width, float stretch) {
391 SkPaint p;
392 p.setAntiAlias(true);
393 p.setStrokeWidth(width);
394 p.setStyle(SkPaint::kStroke_Style);
395 p.setStrokeJoin(SkPaint::kBevel_Join);
396
397 canvas->save();
398 canvas->translate(cx * 110.f, cy * 110.f);
399
400 SkRect rect = SkRect::MakeWH(cx % 2 ? 50.f : (40.f + stretch),
401 cx % 2 ? (40.f + stretch) : 50.f);
402 const SkVector kBigCorner{30.f, 30.f};
403 const SkVector kRectCorner{0.f, 0.f};
404
405 SkVector strokeRadii[4] = { cy % 2 ? kRectCorner : kBigCorner,
406 cy % 2 ? kBigCorner : kRectCorner,
407 cy % 2 ? kRectCorner : kBigCorner,
408 cy % 2 ? kBigCorner : kRectCorner };
409
410 SkRRect r;
411 r.setRectRadii(rect, strokeRadii);
412 canvas->drawRRect(r, p);
413
414 canvas->restore();
415 };
416
417 canvas->translate(0.f, -50.f);
418 i = 6;
419 for (float width : {50.f, 30.f, 20.f, 10.f, 1.f, 0.f}) {
420 int j = 0;
421 for (float stretch: {0.f, 5.f, 10.f}) {
422 drawComplex(2*i, 2*j, width, stretch);
423 drawComplex(2*i+1, 2*j, width, stretch);
424 drawComplex(2*i, 2*j+1, width, stretch);
425 drawComplex(2*i+1, 2*j+1, width, stretch);
426 j++;
427 }
428 i++;
429 }
430
431 // Rotated "D"s
432 auto drawComplex2 = [&](int cx, int cy, float width, float stretch) {
433 SkPaint p;
434 p.setAntiAlias(true);
435 p.setStrokeWidth(width);
436 p.setStyle(SkPaint::kStroke_Style);
437 p.setStrokeJoin(SkPaint::kMiter_Join);
438
439 canvas->save();
440 canvas->translate(cx * 110.f, cy * 110.f);
441
442 SkRect rect = SkRect::MakeWH(cx % 2 ? 50.f : (40.f + stretch),
443 cx % 2 ? (40.f + stretch) : 50.f);
444 const SkVector kBigCorner{30.f, 30.f};
445 const SkVector kRectCorner{0.f, 0.f};
446
447 SkVector strokeRadii[4] = { cx % 2 ? kRectCorner : kBigCorner,
448 (cx % 2) ^ (cy % 2) ? kBigCorner : kRectCorner,
449 cx % 2 ? kBigCorner : kRectCorner,
450 (cx % 2) ^ (cy % 2) ? kRectCorner : kBigCorner };
451
452 SkRRect r;
453 r.setRectRadii(rect, strokeRadii);
454 canvas->drawRRect(r, p);
455
456 canvas->restore();
457 };
458
459 canvas->translate(0.f, 50.f);
460 i = 6;
461 for (float width : {50.f, 30.f, 20.f, 10.f, 1.f, 0.f}) {
462 int j = 3;
463 for (float stretch: {0.f, 5.f, 10.f}) {
464 drawComplex2(2*i, 2*j, width, stretch);
465 drawComplex2(2*i+1, 2*j, width, stretch);
466 drawComplex2(2*i, 2*j+1, width, stretch);
467 drawComplex2(2*i+1, 2*j+1, width, stretch);
468 j++;
469 }
470 i++;
471 }
472}
473
474} // namespace skiagm
GrClipEdgeType
Definition: GrTypesPriv.h:361
#define SkASSERT(cond)
Definition: SkAssert.h:116
constexpr SkColor SK_ColorYELLOW
Definition: SkColor.h:139
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
#define SkIntToScalar(x)
Definition: SkScalar.h:57
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
Definition: aaclip.cpp:27
GLenum type
void setXPFactory(const GrXPFactory *xpFactory)
Definition: GrPaint.h:53
void setColor4f(const SkPMColor4f &color)
Definition: GrPaint.h:50
void setCoverageFragmentProcessor(std::unique_ptr< GrFragmentProcessor > fp)
Definition: GrPaint.h:75
static const GrXPFactory * Get(SkBlendMode blendMode)
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
SkMatrix getLocalToDeviceAs3x3() const
Definition: SkCanvas.h:2222
virtual GrRecordingContext * recordingContext() const
Definition: SkCanvas.cpp:1637
void drawRRect(const SkRRect &rrect, const SkPaint &paint)
Definition: SkCanvas.cpp:1705
int save()
Definition: SkCanvas.cpp:447
void setMatrix(const SkM44 &matrix)
Definition: SkCanvas.cpp:1349
void clipRRect(const SkRRect &rrect, SkClipOp op, bool doAntiAlias)
Definition: SkCanvas.cpp:1439
static sk_sp< SkShader > MakeLinear(const SkPoint pts[2], const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
@ kFill_Style
set to fill geometry
Definition: SkPaint.h:193
@ kRound_Join
adds circle
Definition: SkPaint.h:360
@ kMiter_Join
extends to miter limit
Definition: SkPaint.h:359
@ kBevel_Join
connects outside edges
Definition: SkPaint.h:361
const SkRect & rect() const
Definition: SkRRect.h:264
bool transform(const SkMatrix &matrix, SkRRect *dst) const
Definition: SkRRect.cpp:436
void setOval(const SkRect &oval)
Definition: SkRRect.cpp:30
void setRectRadii(const SkRect &rect, const SkVector radii[4])
Definition: SkRRect.cpp:189
void setRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition: SkRRect.cpp:52
const SkRect & getBounds() const
Definition: SkRRect.h:279
void setRect(const SkRect &rect)
Definition: SkRRect.h:126
static GrOp::Owner MakeNonAARect(GrRecordingContext *, GrPaint &&, const SkMatrix &view, const SkRect &, const GrUserStencilSettings *=nullptr)
Definition: FillRectOp.cpp:480
Definition: gm.h:110
GM(SkColor backgroundColor=SK_ColorWHITE)
Definition: gm.cpp:81
static constexpr char kErrorMsg_DrawSkippedGpuOnly[]
Definition: gm.h:127
void setBGColor(SkColor)
Definition: gm.cpp:159
void onOnceBeforeDraw() override
Definition: rrects.cpp:53
SkISize getISize() override
Definition: rrects.cpp:80
DrawResult onDraw(SkCanvas *canvas, SkString *errorMsg) override
Definition: rrects.cpp:82
SkString getName() const override
Definition: rrects.cpp:58
void setUpRRects()
Definition: rrects.cpp:181
RRectGM(Type type)
Definition: rrects.cpp:49
const Paint & paint
Definition: color_source.cc:38
static float min(float r, float g, float b)
Definition: hsl.cpp:48
double y
double x
GrFPResult Make(std::unique_ptr< GrFragmentProcessor >, GrClipEdgeType, const SkRRect &, const GrShaderCaps &)
Optional< SkRect > bounds
Definition: SkRecords.h:189
SkRRect rrect
Definition: SkRecords.h:232
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
PODArray< SkColor > colors
Definition: SkRecords.h:276
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition: SkRecords.h:208
const uint32_t fp
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 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
SurfaceDrawContext * TopDeviceSurfaceDrawContext(const SkCanvas *canvas)
Definition: GrCanvas.cpp:20
DEF_GM(return F(C(clipbox), 0.0f, 0.0f, {})) DEF_GM(return F(C(clipbox)
DEF_SIMPLE_GM(hugebitmapshader, canvas, 100, 100)
DrawResult
Definition: gm.h:104
int32_t width
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
bool contains(SkScalar x, SkScalar y) const
Definition: extension.cpp:19
void offset(float dx, float dy)
Definition: SkRect.h:1016
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