1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2016 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h" 9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h" 10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h" 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRRect.h" 16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h" 17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h" 18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h" 19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h" 20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h" 21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h" 22*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h" 23*c8dee2aaSAndroid Build Coastguard Worker 24*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private; 25*c8dee2aaSAndroid Build Coastguard Worker 26*c8dee2aaSAndroid Build Coastguard Worker namespace skiagm { 27*c8dee2aaSAndroid Build Coastguard Worker 28*c8dee2aaSAndroid Build Coastguard Worker /* 29*c8dee2aaSAndroid Build Coastguard Worker * This is the base class for two GMs that cover various corner cases with primitive Skia shapes 30*c8dee2aaSAndroid Build Coastguard Worker * (zero radius, near-zero radius, inner shape overlap, etc.) It uses an xfermode of darken to help 31*c8dee2aaSAndroid Build Coastguard Worker * double-blended and/or dropped pixels stand out. 32*c8dee2aaSAndroid Build Coastguard Worker */ 33*c8dee2aaSAndroid Build Coastguard Worker class ShapesGM : public GM { 34*c8dee2aaSAndroid Build Coastguard Worker protected: ShapesGM(const char * name,bool antialias)35*c8dee2aaSAndroid Build Coastguard Worker ShapesGM(const char* name, bool antialias) : fName(name), fAntialias(antialias) { 36*c8dee2aaSAndroid Build Coastguard Worker if (!antialias) { 37*c8dee2aaSAndroid Build Coastguard Worker fName.append("_bw"); 38*c8dee2aaSAndroid Build Coastguard Worker } 39*c8dee2aaSAndroid Build Coastguard Worker } 40*c8dee2aaSAndroid Build Coastguard Worker getName() const41*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override { return fName; } getISize()42*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return SkISize::Make(500, 500); } 43*c8dee2aaSAndroid Build Coastguard Worker onOnceBeforeDraw()44*c8dee2aaSAndroid Build Coastguard Worker void onOnceBeforeDraw() override { 45*c8dee2aaSAndroid Build Coastguard Worker fShapes.push_back().setOval(SkRect::MakeXYWH(-5, 25, 200, 100)); 46*c8dee2aaSAndroid Build Coastguard Worker fRotations.push_back(21); 47*c8dee2aaSAndroid Build Coastguard Worker 48*c8dee2aaSAndroid Build Coastguard Worker fShapes.push_back().setRect(SkRect::MakeXYWH(95, 75, 125, 100)); 49*c8dee2aaSAndroid Build Coastguard Worker fRotations.push_back(94); 50*c8dee2aaSAndroid Build Coastguard Worker 51*c8dee2aaSAndroid Build Coastguard Worker fShapes.push_back().setRectXY(SkRect::MakeXYWH(0, 75, 150, 100), 1e-5f, 1e-5f); 52*c8dee2aaSAndroid Build Coastguard Worker fRotations.push_back(132); 53*c8dee2aaSAndroid Build Coastguard Worker 54*c8dee2aaSAndroid Build Coastguard Worker fShapes.push_back().setRectXY(SkRect::MakeXYWH(15, -20, 100, 100), 20, 15); 55*c8dee2aaSAndroid Build Coastguard Worker fRotations.push_back(282); 56*c8dee2aaSAndroid Build Coastguard Worker 57*c8dee2aaSAndroid Build Coastguard Worker fSimpleShapeCount = fShapes.size(); 58*c8dee2aaSAndroid Build Coastguard Worker 59*c8dee2aaSAndroid Build Coastguard Worker fShapes.push_back().setNinePatch(SkRect::MakeXYWH(140, -50, 90, 110), 10, 5, 25, 35); 60*c8dee2aaSAndroid Build Coastguard Worker fRotations.push_back(0); 61*c8dee2aaSAndroid Build Coastguard Worker 62*c8dee2aaSAndroid Build Coastguard Worker fShapes.push_back().setNinePatch(SkRect::MakeXYWH(160, -60, 60, 90), 10, 60, 50, 30); 63*c8dee2aaSAndroid Build Coastguard Worker fRotations.push_back(-35); 64*c8dee2aaSAndroid Build Coastguard Worker 65*c8dee2aaSAndroid Build Coastguard Worker fShapes.push_back().setNinePatch(SkRect::MakeXYWH(220, -120, 60, 90), 1, 89, 59, 1); 66*c8dee2aaSAndroid Build Coastguard Worker fRotations.push_back(65); 67*c8dee2aaSAndroid Build Coastguard Worker 68*c8dee2aaSAndroid Build Coastguard Worker SkVector radii[4] = {{4, 6}, {12, 8}, {24, 16}, {32, 48}}; 69*c8dee2aaSAndroid Build Coastguard Worker fShapes.push_back().setRectRadii(SkRect::MakeXYWH(150, -129, 80, 160), radii); 70*c8dee2aaSAndroid Build Coastguard Worker fRotations.push_back(265); 71*c8dee2aaSAndroid Build Coastguard Worker 72*c8dee2aaSAndroid Build Coastguard Worker SkVector radii2[4] = {{0, 0}, {80, 60}, {0, 0}, {80, 60}}; 73*c8dee2aaSAndroid Build Coastguard Worker fShapes.push_back().setRectRadii(SkRect::MakeXYWH(180, -30, 80, 60), radii2); 74*c8dee2aaSAndroid Build Coastguard Worker fRotations.push_back(295); 75*c8dee2aaSAndroid Build Coastguard Worker 76*c8dee2aaSAndroid Build Coastguard Worker fPaint.setAntiAlias(fAntialias); 77*c8dee2aaSAndroid Build Coastguard Worker } 78*c8dee2aaSAndroid Build Coastguard Worker onDraw(SkCanvas * canvas)79*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override { 80*c8dee2aaSAndroid Build Coastguard Worker canvas->clear(SK_ColorWHITE); 81*c8dee2aaSAndroid Build Coastguard Worker 82*c8dee2aaSAndroid Build Coastguard Worker canvas->save(); 83*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(canvas->imageInfo().width() / 2.f, canvas->imageInfo().height() / 2.f); 84*c8dee2aaSAndroid Build Coastguard Worker this->drawShapes(canvas); 85*c8dee2aaSAndroid Build Coastguard Worker canvas->restore(); 86*c8dee2aaSAndroid Build Coastguard Worker } 87*c8dee2aaSAndroid Build Coastguard Worker 88*c8dee2aaSAndroid Build Coastguard Worker virtual void drawShapes(SkCanvas* canvas) const = 0; 89*c8dee2aaSAndroid Build Coastguard Worker 90*c8dee2aaSAndroid Build Coastguard Worker protected: 91*c8dee2aaSAndroid Build Coastguard Worker SkString fName; 92*c8dee2aaSAndroid Build Coastguard Worker bool fAntialias; 93*c8dee2aaSAndroid Build Coastguard Worker SkPaint fPaint; 94*c8dee2aaSAndroid Build Coastguard Worker TArray<SkRRect> fShapes; 95*c8dee2aaSAndroid Build Coastguard Worker TArray<SkScalar> fRotations; 96*c8dee2aaSAndroid Build Coastguard Worker int fSimpleShapeCount; 97*c8dee2aaSAndroid Build Coastguard Worker 98*c8dee2aaSAndroid Build Coastguard Worker private: 99*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = GM; 100*c8dee2aaSAndroid Build Coastguard Worker }; 101*c8dee2aaSAndroid Build Coastguard Worker 102*c8dee2aaSAndroid Build Coastguard Worker class SimpleShapesGM : public ShapesGM { 103*c8dee2aaSAndroid Build Coastguard Worker public: SimpleShapesGM(bool antialias)104*c8dee2aaSAndroid Build Coastguard Worker SimpleShapesGM(bool antialias) : INHERITED("simpleshapes", antialias) {} 105*c8dee2aaSAndroid Build Coastguard Worker 106*c8dee2aaSAndroid Build Coastguard Worker private: drawShapes(SkCanvas * canvas) const107*c8dee2aaSAndroid Build Coastguard Worker void drawShapes(SkCanvas* canvas) const override { 108*c8dee2aaSAndroid Build Coastguard Worker SkRandom rand(2); 109*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fShapes.size(); i++) { 110*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint(fPaint); 111*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(rand.nextU() & ~0x808080); 112*c8dee2aaSAndroid Build Coastguard Worker paint.setAlphaf(0.5f); // Use alpha to detect double blends. 113*c8dee2aaSAndroid Build Coastguard Worker const SkRRect& shape = fShapes[i]; 114*c8dee2aaSAndroid Build Coastguard Worker canvas->save(); 115*c8dee2aaSAndroid Build Coastguard Worker canvas->rotate(fRotations[i]); 116*c8dee2aaSAndroid Build Coastguard Worker switch (shape.getType()) { 117*c8dee2aaSAndroid Build Coastguard Worker case SkRRect::kRect_Type: 118*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(shape.rect(), paint); 119*c8dee2aaSAndroid Build Coastguard Worker break; 120*c8dee2aaSAndroid Build Coastguard Worker case SkRRect::kOval_Type: 121*c8dee2aaSAndroid Build Coastguard Worker canvas->drawOval(shape.rect(), paint); 122*c8dee2aaSAndroid Build Coastguard Worker break; 123*c8dee2aaSAndroid Build Coastguard Worker default: 124*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRRect(shape, paint); 125*c8dee2aaSAndroid Build Coastguard Worker break; 126*c8dee2aaSAndroid Build Coastguard Worker } 127*c8dee2aaSAndroid Build Coastguard Worker canvas->restore(); 128*c8dee2aaSAndroid Build Coastguard Worker } 129*c8dee2aaSAndroid Build Coastguard Worker } 130*c8dee2aaSAndroid Build Coastguard Worker 131*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = ShapesGM; 132*c8dee2aaSAndroid Build Coastguard Worker }; 133*c8dee2aaSAndroid Build Coastguard Worker 134*c8dee2aaSAndroid Build Coastguard Worker class InnerShapesGM : public ShapesGM { 135*c8dee2aaSAndroid Build Coastguard Worker public: InnerShapesGM(bool antialias)136*c8dee2aaSAndroid Build Coastguard Worker InnerShapesGM(bool antialias) : INHERITED("innershapes", antialias) {} 137*c8dee2aaSAndroid Build Coastguard Worker 138*c8dee2aaSAndroid Build Coastguard Worker private: drawShapes(SkCanvas * canvas) const139*c8dee2aaSAndroid Build Coastguard Worker void drawShapes(SkCanvas* canvas) const override { 140*c8dee2aaSAndroid Build Coastguard Worker SkRandom rand; 141*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fShapes.size(); i++) { 142*c8dee2aaSAndroid Build Coastguard Worker const SkRRect& outer = fShapes[i]; 143*c8dee2aaSAndroid Build Coastguard Worker const SkRRect& inner = fShapes[(i * 7 + 11) % fSimpleShapeCount]; 144*c8dee2aaSAndroid Build Coastguard Worker float s = 0.95f * std::min(outer.rect().width() / inner.rect().width(), 145*c8dee2aaSAndroid Build Coastguard Worker outer.rect().height() / inner.rect().height()); 146*c8dee2aaSAndroid Build Coastguard Worker SkMatrix innerXform; 147*c8dee2aaSAndroid Build Coastguard Worker float dx = (rand.nextF() - 0.5f) * (outer.rect().width() - s * inner.rect().width()); 148*c8dee2aaSAndroid Build Coastguard Worker float dy = (rand.nextF() - 0.5f) * (outer.rect().height() - s * inner.rect().height()); 149*c8dee2aaSAndroid Build Coastguard Worker // Fixup inner rects so they don't reach outside the outer rect. 150*c8dee2aaSAndroid Build Coastguard Worker switch (i) { 151*c8dee2aaSAndroid Build Coastguard Worker case 0: 152*c8dee2aaSAndroid Build Coastguard Worker s *= .85f; 153*c8dee2aaSAndroid Build Coastguard Worker break; 154*c8dee2aaSAndroid Build Coastguard Worker case 8: 155*c8dee2aaSAndroid Build Coastguard Worker s *= .4f; 156*c8dee2aaSAndroid Build Coastguard Worker dx = dy = 0; 157*c8dee2aaSAndroid Build Coastguard Worker break; 158*c8dee2aaSAndroid Build Coastguard Worker case 5: 159*c8dee2aaSAndroid Build Coastguard Worker s *= .75f; 160*c8dee2aaSAndroid Build Coastguard Worker dx = dy = 0; 161*c8dee2aaSAndroid Build Coastguard Worker break; 162*c8dee2aaSAndroid Build Coastguard Worker case 6: 163*c8dee2aaSAndroid Build Coastguard Worker s *= .65f; 164*c8dee2aaSAndroid Build Coastguard Worker dx = -5; 165*c8dee2aaSAndroid Build Coastguard Worker dy = 10; 166*c8dee2aaSAndroid Build Coastguard Worker break; 167*c8dee2aaSAndroid Build Coastguard Worker } 168*c8dee2aaSAndroid Build Coastguard Worker innerXform.setTranslate(outer.rect().centerX() + dx, outer.rect().centerY() + dy); 169*c8dee2aaSAndroid Build Coastguard Worker if (s < 1) { 170*c8dee2aaSAndroid Build Coastguard Worker innerXform.preScale(s, s); 171*c8dee2aaSAndroid Build Coastguard Worker } 172*c8dee2aaSAndroid Build Coastguard Worker innerXform.preTranslate(-inner.rect().centerX(), -inner.rect().centerY()); 173*c8dee2aaSAndroid Build Coastguard Worker SkRRect xformedInner; 174*c8dee2aaSAndroid Build Coastguard Worker inner.transform(innerXform, &xformedInner); 175*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint(fPaint); 176*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(rand.nextU() & ~0x808080); 177*c8dee2aaSAndroid Build Coastguard Worker paint.setAlphaf(0.5f); // Use alpha to detect double blends. 178*c8dee2aaSAndroid Build Coastguard Worker canvas->save(); 179*c8dee2aaSAndroid Build Coastguard Worker canvas->rotate(fRotations[i]); 180*c8dee2aaSAndroid Build Coastguard Worker canvas->drawDRRect(outer, xformedInner, paint); 181*c8dee2aaSAndroid Build Coastguard Worker canvas->restore(); 182*c8dee2aaSAndroid Build Coastguard Worker } 183*c8dee2aaSAndroid Build Coastguard Worker } 184*c8dee2aaSAndroid Build Coastguard Worker 185*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = ShapesGM; 186*c8dee2aaSAndroid Build Coastguard Worker }; 187*c8dee2aaSAndroid Build Coastguard Worker 188*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////// 189*c8dee2aaSAndroid Build Coastguard Worker 190*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new SimpleShapesGM(true); ) 191*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new SimpleShapesGM(false); ) 192*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new InnerShapesGM(true); ) 193*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new InnerShapesGM(false); ) 194*c8dee2aaSAndroid Build Coastguard Worker 195*c8dee2aaSAndroid Build Coastguard Worker } // namespace skiagm 196