1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2018 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/SkMatrix.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h" 16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h" 17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h" 18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h" 19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h" 20*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h" 21*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h" 22*c8dee2aaSAndroid Build Coastguard Worker 23*c8dee2aaSAndroid Build Coastguard Worker #include <array> 24*c8dee2aaSAndroid Build Coastguard Worker #include <vector> 25*c8dee2aaSAndroid Build Coastguard Worker 26*c8dee2aaSAndroid Build Coastguard Worker namespace skiagm { 27*c8dee2aaSAndroid Build Coastguard Worker 28*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kPadSize = 20; 29*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kBoxSize = 100; 30*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkPoint kJitters[] = {{0, 0}, {.5f, .5f}, {2/3.f, 1/3.f}}; 31*c8dee2aaSAndroid Build Coastguard Worker 32*c8dee2aaSAndroid Build Coastguard Worker // Tests various corners of different angles falling on the same pixel, particularly to ensure 33*c8dee2aaSAndroid Build Coastguard Worker // analytic AA is working properly. 34*c8dee2aaSAndroid Build Coastguard Worker class SharedCornersGM : public GM { 35*c8dee2aaSAndroid Build Coastguard Worker public: SharedCornersGM()36*c8dee2aaSAndroid Build Coastguard Worker SharedCornersGM() { this->setBGColor(ToolUtils::color_to_565(0xFF1A65D7)); } 37*c8dee2aaSAndroid Build Coastguard Worker 38*c8dee2aaSAndroid Build Coastguard Worker protected: getName() const39*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override { return SkString("sharedcorners"); } 40*c8dee2aaSAndroid Build Coastguard Worker getISize()41*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { 42*c8dee2aaSAndroid Build Coastguard Worker constexpr int numRows = 3 * 2; 43*c8dee2aaSAndroid Build Coastguard Worker constexpr int numCols = (1 + std::size(kJitters)) * 2; 44*c8dee2aaSAndroid Build Coastguard Worker return SkISize::Make(numCols * (kBoxSize + kPadSize) + kPadSize, 45*c8dee2aaSAndroid Build Coastguard Worker numRows * (kBoxSize + kPadSize) + kPadSize); 46*c8dee2aaSAndroid Build Coastguard Worker } 47*c8dee2aaSAndroid Build Coastguard Worker onOnceBeforeDraw()48*c8dee2aaSAndroid Build Coastguard Worker void onOnceBeforeDraw() override { 49*c8dee2aaSAndroid Build Coastguard Worker fFillPaint.setColor(SK_ColorWHITE); 50*c8dee2aaSAndroid Build Coastguard Worker fFillPaint.setAntiAlias(true); 51*c8dee2aaSAndroid Build Coastguard Worker 52*c8dee2aaSAndroid Build Coastguard Worker fWireFramePaint = fFillPaint; 53*c8dee2aaSAndroid Build Coastguard Worker fWireFramePaint.setStyle(SkPaint::kStroke_Style); 54*c8dee2aaSAndroid Build Coastguard Worker 55*c8dee2aaSAndroid Build Coastguard Worker } 56*c8dee2aaSAndroid Build Coastguard Worker onDraw(SkCanvas * canvas)57*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override { 58*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(kPadSize, kPadSize); 59*c8dee2aaSAndroid Build Coastguard Worker canvas->save(); 60*c8dee2aaSAndroid Build Coastguard Worker 61*c8dee2aaSAndroid Build Coastguard Worker // Adjacent rects. 62*c8dee2aaSAndroid Build Coastguard Worker this->drawTriangleBoxes(canvas, 63*c8dee2aaSAndroid Build Coastguard Worker {{0, 0}, {40, 0}, {80, 0}, {120, 0}, 64*c8dee2aaSAndroid Build Coastguard Worker {0, 20}, {40, 20}, {80, 20}, {120, 20}, 65*c8dee2aaSAndroid Build Coastguard Worker {40, 40}, {80, 40}, 66*c8dee2aaSAndroid Build Coastguard Worker {40, 60}, {80, 60}}, 67*c8dee2aaSAndroid Build Coastguard Worker {{{0, 1, 4}}, {{1, 5, 4}}, 68*c8dee2aaSAndroid Build Coastguard Worker {{5, 1, 6}}, {{1, 2, 6}}, 69*c8dee2aaSAndroid Build Coastguard Worker {{2, 3, 6}}, {{3, 7, 6}}, 70*c8dee2aaSAndroid Build Coastguard Worker {{8, 5, 9}}, {{5, 6, 9}}, 71*c8dee2aaSAndroid Build Coastguard Worker {{10, 8, 11}}, {{8, 9, 11}}}); 72*c8dee2aaSAndroid Build Coastguard Worker 73*c8dee2aaSAndroid Build Coastguard Worker // Obtuse angles. 74*c8dee2aaSAndroid Build Coastguard Worker this->drawTriangleBoxes(canvas, 75*c8dee2aaSAndroid Build Coastguard Worker {{ 0, 0}, {10, 0}, {20, 0}, 76*c8dee2aaSAndroid Build Coastguard Worker { 0, 2}, {20, 2}, 77*c8dee2aaSAndroid Build Coastguard Worker {10, 4}, 78*c8dee2aaSAndroid Build Coastguard Worker { 0, 6}, {20, 6}, 79*c8dee2aaSAndroid Build Coastguard Worker { 0, 8}, {10, 8}, {20, 8}}, 80*c8dee2aaSAndroid Build Coastguard Worker {{{3, 1, 4}}, {{4, 5, 3}}, {{6, 5, 7}}, {{7, 9, 6}}, 81*c8dee2aaSAndroid Build Coastguard Worker {{0, 1, 3}}, {{1, 2, 4}}, 82*c8dee2aaSAndroid Build Coastguard Worker {{3, 5, 6}}, {{5, 4, 7}}, 83*c8dee2aaSAndroid Build Coastguard Worker {{6, 9, 8}}, {{9, 7, 10}}}); 84*c8dee2aaSAndroid Build Coastguard Worker 85*c8dee2aaSAndroid Build Coastguard Worker canvas->restore(); 86*c8dee2aaSAndroid Build Coastguard Worker canvas->translate((kBoxSize + kPadSize) * 4, 0); 87*c8dee2aaSAndroid Build Coastguard Worker 88*c8dee2aaSAndroid Build Coastguard Worker // Right angles. 89*c8dee2aaSAndroid Build Coastguard Worker this->drawTriangleBoxes(canvas, 90*c8dee2aaSAndroid Build Coastguard Worker {{0, 0}, {-1, 0}, {0, -1}, {1, 0}, {0, 1}}, 91*c8dee2aaSAndroid Build Coastguard Worker {{{0, 1, 2}}, {{0, 2, 3}}, {{0, 3, 4}}, {{0, 4, 1}}}); 92*c8dee2aaSAndroid Build Coastguard Worker 93*c8dee2aaSAndroid Build Coastguard Worker // Acute angles. 94*c8dee2aaSAndroid Build Coastguard Worker SkRandom rand; 95*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkPoint> pts; 96*c8dee2aaSAndroid Build Coastguard Worker std::vector<std::array<int, 3>> indices; 97*c8dee2aaSAndroid Build Coastguard Worker SkScalar theta = 0; 98*c8dee2aaSAndroid Build Coastguard Worker pts.push_back({0, 0}); 99*c8dee2aaSAndroid Build Coastguard Worker while (theta < 2*SK_ScalarPI) { 100*c8dee2aaSAndroid Build Coastguard Worker pts.push_back({SkScalarCos(theta), SkScalarSin(theta)}); 101*c8dee2aaSAndroid Build Coastguard Worker if (pts.size() > 2) { 102*c8dee2aaSAndroid Build Coastguard Worker indices.push_back({{0, (int)pts.size() - 2, (int)pts.size() - 1}}); 103*c8dee2aaSAndroid Build Coastguard Worker } 104*c8dee2aaSAndroid Build Coastguard Worker theta += rand.nextRangeF(0, SK_ScalarPI/3); 105*c8dee2aaSAndroid Build Coastguard Worker } 106*c8dee2aaSAndroid Build Coastguard Worker indices.push_back({{0, (int)pts.size() - 1, 1}}); 107*c8dee2aaSAndroid Build Coastguard Worker this->drawTriangleBoxes(canvas, pts, indices); 108*c8dee2aaSAndroid Build Coastguard Worker } 109*c8dee2aaSAndroid Build Coastguard Worker drawTriangleBoxes(SkCanvas * canvas,const std::vector<SkPoint> & points,const std::vector<std::array<int,3>> & triangles)110*c8dee2aaSAndroid Build Coastguard Worker void drawTriangleBoxes(SkCanvas* canvas, const std::vector<SkPoint>& points, 111*c8dee2aaSAndroid Build Coastguard Worker const std::vector<std::array<int, 3>>& triangles) { 112*c8dee2aaSAndroid Build Coastguard Worker SkPath path; 113*c8dee2aaSAndroid Build Coastguard Worker path.setFillType(SkPathFillType::kEvenOdd); 114*c8dee2aaSAndroid Build Coastguard Worker path.setIsVolatile(true); 115*c8dee2aaSAndroid Build Coastguard Worker for (const std::array<int, 3>& triangle : triangles) { 116*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(points[triangle[0]]); 117*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(points[triangle[1]]); 118*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(points[triangle[2]]); 119*c8dee2aaSAndroid Build Coastguard Worker path.close(); 120*c8dee2aaSAndroid Build Coastguard Worker } 121*c8dee2aaSAndroid Build Coastguard Worker SkScalar scale = kBoxSize / std::max(path.getBounds().height(), path.getBounds().width()); 122*c8dee2aaSAndroid Build Coastguard Worker path.transform(SkMatrix::Scale(scale, scale)); 123*c8dee2aaSAndroid Build Coastguard Worker 124*c8dee2aaSAndroid Build Coastguard Worker this->drawRow(canvas, path); 125*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, kBoxSize + kPadSize); 126*c8dee2aaSAndroid Build Coastguard Worker 127*c8dee2aaSAndroid Build Coastguard Worker SkMatrix rot; 128*c8dee2aaSAndroid Build Coastguard Worker rot.setRotate(45, path.getBounds().centerX(), path.getBounds().centerY()); 129*c8dee2aaSAndroid Build Coastguard Worker path.transform(rot); 130*c8dee2aaSAndroid Build Coastguard Worker this->drawRow(canvas, path); 131*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, kBoxSize + kPadSize); 132*c8dee2aaSAndroid Build Coastguard Worker 133*c8dee2aaSAndroid Build Coastguard Worker rot.setRotate(-45 - 69.38111f, path.getBounds().centerX(), path.getBounds().centerY()); 134*c8dee2aaSAndroid Build Coastguard Worker path.transform(rot); 135*c8dee2aaSAndroid Build Coastguard Worker this->drawRow(canvas, path); 136*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, kBoxSize + kPadSize); 137*c8dee2aaSAndroid Build Coastguard Worker } 138*c8dee2aaSAndroid Build Coastguard Worker drawRow(SkCanvas * canvas,const SkPath & path)139*c8dee2aaSAndroid Build Coastguard Worker void drawRow(SkCanvas* canvas, const SkPath& path) { 140*c8dee2aaSAndroid Build Coastguard Worker SkAutoCanvasRestore acr(canvas, true); 141*c8dee2aaSAndroid Build Coastguard Worker const SkRect& bounds = path.getBounds(); 142*c8dee2aaSAndroid Build Coastguard Worker canvas->translate((kBoxSize - bounds.width()) / 2 - bounds.left(), 143*c8dee2aaSAndroid Build Coastguard Worker (kBoxSize - bounds.height()) / 2 - bounds.top()); 144*c8dee2aaSAndroid Build Coastguard Worker 145*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(path, fWireFramePaint); 146*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(kBoxSize + kPadSize, 0); 147*c8dee2aaSAndroid Build Coastguard Worker 148*c8dee2aaSAndroid Build Coastguard Worker for (SkPoint jitter : kJitters) { 149*c8dee2aaSAndroid Build Coastguard Worker { 150*c8dee2aaSAndroid Build Coastguard Worker SkAutoCanvasRestore acr2(canvas, true); 151*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(jitter.x(), jitter.y()); 152*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(path, fFillPaint); 153*c8dee2aaSAndroid Build Coastguard Worker } 154*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(kBoxSize + kPadSize, 0); 155*c8dee2aaSAndroid Build Coastguard Worker } 156*c8dee2aaSAndroid Build Coastguard Worker } 157*c8dee2aaSAndroid Build Coastguard Worker 158*c8dee2aaSAndroid Build Coastguard Worker SkPaint fWireFramePaint; 159*c8dee2aaSAndroid Build Coastguard Worker SkPaint fFillPaint; 160*c8dee2aaSAndroid Build Coastguard Worker }; 161*c8dee2aaSAndroid Build Coastguard Worker 162*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new SharedCornersGM;) 163*c8dee2aaSAndroid Build Coastguard Worker 164*c8dee2aaSAndroid Build Coastguard Worker } // namespace skiagm 165