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