2 * Copyright 2012 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
9 #include "sk_tool_utils.h"
11 #include "GrContext.h"
12 #include "GrRenderTargetContextPriv.h"
13 #include "effects/GrRRectEffect.h"
14 #include "ops/GrDrawOp.h"
15 #include "ops/GrRectOpFactory.h"
21 ///////////////////////////////////////////////////////////////////////////////
23 class RRectGM : public GM {
32 RRectGM(Type type) : fType(type) { }
36 void onOnceBeforeDraw() override {
37 this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
41 SkString onShortName() override {
42 SkString name("rrect");
45 name.append("_draw_bw");
48 name.append("_draw_aa");
51 name.append("_clip_bw");
54 name.append("_clip_aa");
57 name.append("_effect");
63 SkISize onISize() override { return SkISize::Make(kImageWidth, kImageHeight); }
65 void onDraw(SkCanvas* canvas) override {
66 GrRenderTargetContext* renderTargetContext =
67 canvas->internal_private_accessTopLayerRenderTargetContext();
68 if (kEffect_Type == fType && !renderTargetContext) {
69 skiagm::GM::DrawGpuOnlyMessage(canvas);
74 if (kAA_Draw_Type == fType) {
75 paint.setAntiAlias(true);
78 const SkRect kMaxTileBound = SkRect::MakeWH(SkIntToScalar(kTileX),
79 SkIntToScalar(kTileY));
81 const SkRect kMaxImageBound = SkRect::MakeWH(SkIntToScalar(kImageWidth),
82 SkIntToScalar(kImageHeight));
86 int lastEdgeType = (kEffect_Type == fType) ? kLast_GrProcessorEdgeType: 0;
92 for (int et = 0; et <= lastEdgeType; ++et) {
94 for (int curRRect = 0; curRRect < kNumRRects; ++curRRect) {
97 SkASSERT(kMaxTileBound.contains(fRRects[curRRect].getBounds()));
98 SkRect imageSpaceBounds = fRRects[curRRect].getBounds();
99 imageSpaceBounds.offset(SkIntToScalar(x), SkIntToScalar(y));
100 SkASSERT(kMaxImageBound.contains(imageSpaceBounds));
103 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
104 if (kEffect_Type == fType) {
106 SkRRect rrect = fRRects[curRRect];
107 rrect.offset(SkIntToScalar(x), SkIntToScalar(y));
108 GrPrimitiveEdgeType edgeType = (GrPrimitiveEdgeType) et;
109 sk_sp<GrFragmentProcessor> fp(GrRRectEffect::Make(edgeType, rrect));
112 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
113 grPaint.addCoverageFragmentProcessor(std::move(fp));
115 SkRect bounds = rrect.getBounds();
116 bounds.outset(2.f, 2.f);
118 std::unique_ptr<GrLegacyMeshDrawOp> op(GrRectOpFactory::MakeNonAAFill(
119 0xff000000, SkMatrix::I(), bounds, nullptr, nullptr));
120 renderTargetContext->priv().testingOnly_addLegacyMeshDrawOp(
121 std::move(grPaint), GrAAType::kNone, std::move(op));
126 } else if (kBW_Clip_Type == fType || kAA_Clip_Type == fType) {
127 bool aaClip = (kAA_Clip_Type == fType);
128 canvas->clipRRect(fRRects[curRRect], aaClip);
129 canvas->drawRect(kMaxTileBound, paint);
131 canvas->drawRRect(fRRects[curRRect], paint);
136 if (x > kImageWidth) {
149 // each RRect must fit in a 0x0 -> (kTileX-2)x(kTileY-2) block. These will be tiled across
150 // the screen in kTileX x kTileY tiles. The extra empty pixels on each side are for AA.
153 fRRects[0].setRect(SkRect::MakeWH(kTileX-2, kTileY-2));
154 fRRects[1].setOval(SkRect::MakeWH(kTileX-2, kTileY-2));
155 fRRects[2].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 10, 10);
156 fRRects[3].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 10, 5);
157 // small circular corners are an interesting test case for gpu clipping
158 fRRects[4].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 1, 1);
159 fRRects[5].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 0.5f, 0.5f);
160 fRRects[6].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 0.2f, 0.2f);
162 // The first complex case needs special handling since it is a square
163 fRRects[kNumSimpleCases].setRectRadii(SkRect::MakeWH(kTileY-2, kTileY-2), gRadii[0]);
164 for (size_t i = 1; i < SK_ARRAY_COUNT(gRadii); ++i) {
165 fRRects[kNumSimpleCases+i].setRectRadii(SkRect::MakeWH(kTileX-2, kTileY-2), gRadii[i]);
172 static constexpr int kImageWidth = 640;
173 static constexpr int kImageHeight = 480;
175 static constexpr int kTileX = 80;
176 static constexpr int kTileY = 40;
178 static constexpr int kNumSimpleCases = 7;
179 static constexpr int kNumComplexCases = 35;
180 static const SkVector gRadii[kNumComplexCases][4];
182 static constexpr int kNumRRects = kNumSimpleCases + kNumComplexCases;
183 SkRRect fRRects[kNumRRects];
185 typedef GM INHERITED;
188 // Radii for the various test cases. Order is UL, UR, LR, LL
189 const SkVector RRectGM::gRadii[kNumComplexCases][4] = {
191 { { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY } },
194 { { 8, 8 }, { 32, 32 }, { 8, 8 }, { 32, 32 } },
195 { { 16, 8 }, { 8, 16 }, { 16, 8 }, { 8, 16 } },
196 { { 0, 0 }, { 16, 16 }, { 8, 8 }, { 32, 32 } },
199 { { 30, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
200 { { 30, 15 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
201 { { 15, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
204 { { 0, 0 }, { 30, 30 }, { 0, 0 }, { 0, 0 } },
205 { { 0, 0 }, { 30, 15 }, { 0, 0 }, { 0, 0 } },
206 { { 0, 0 }, { 15, 30 }, { 0, 0 }, { 0, 0 } },
209 { { 0, 0 }, { 0, 0 }, { 30, 30 }, { 0, 0 } },
210 { { 0, 0 }, { 0, 0 }, { 30, 15 }, { 0, 0 } },
211 { { 0, 0 }, { 0, 0 }, { 15, 30 }, { 0, 0 } },
214 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 30 } },
215 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 15 } },
216 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 15, 30 } },
219 { { 0, 0 }, { 100, 400 }, { 0, 0 }, { 0, 0 } },
220 { { 0, 0 }, { 400, 400 }, { 0, 0 }, { 0, 0 } },
221 { { 400, 400 }, { 400, 400 }, { 400, 400 }, { 400, 400 } },
223 // circular corner tabs
224 { { 0, 0 }, { 20, 20 }, { 20, 20 }, { 0, 0 } },
225 { { 20, 20 }, { 20, 20 }, { 0, 0 }, { 0, 0 } },
226 { { 0, 0 }, { 0, 0 }, { 20, 20 }, { 20, 20 } },
227 { { 20, 20 }, { 0, 0 }, { 0, 0 }, { 20, 20 } },
229 // small radius circular corner tabs
230 { { 0, 0 }, { 0.2f, 0.2f }, { 0.2f, 0.2f }, { 0, 0 } },
231 { { 0.3f, 0.3f }, { 0.3f, .3f }, { 0, 0 }, { 0, 0 } },
233 // single circular corner cases
234 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 15, 15 } },
235 { { 0, 0 }, { 0, 0 }, { 15, 15 }, { 0, 0 } },
236 { { 0, 0 }, { 15, 15 }, { 0, 0 }, { 0, 0 } },
237 { { 15, 15 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
239 // nine patch elliptical
240 { { 5, 7 }, { 8, 7 }, { 8, 12 }, { 5, 12 } },
241 { { 0, 7 }, { 8, 7 }, { 8, 12 }, { 0, 12 } },
243 // nine patch elliptical, small radii
244 { { 0.4f, 7 }, { 8, 7 }, { 8, 12 }, { 0.4f, 12 } },
245 { { 0.4f, 0.4f }, { 8, 0.4f }, { 8, 12 }, { 0.4f, 12 } },
246 { { 20, 0.4f }, { 18, 0.4f }, { 18, 0.4f }, { 20, 0.4f } },
247 { { 0.3f, 0.4f }, { 0.3f, 0.4f }, { 0.3f, 0.4f }, { 0.3f, 0.4f } },
251 ///////////////////////////////////////////////////////////////////////////////
253 DEF_GM( return new RRectGM(RRectGM::kAA_Draw_Type); )
254 DEF_GM( return new RRectGM(RRectGM::kBW_Draw_Type); )
255 DEF_GM( return new RRectGM(RRectGM::kAA_Clip_Type); )
256 DEF_GM( return new RRectGM(RRectGM::kBW_Clip_Type); )
258 DEF_GM( return new RRectGM(RRectGM::kEffect_Type); )