Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2015 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 "SkAnimTimer.h"
     11 #include "SkCanvas.h"
     12 #include "SkPathMeasure.h"
     13 #include "SkRandom.h"
     14 
     15 class AddArcGM : public skiagm::GM {
     16 public:
     17     AddArcGM() : fRotate(0) {}
     18 
     19 protected:
     20     SkString onShortName() override { return SkString("addarc"); }
     21 
     22     SkISize onISize() override { return SkISize::Make(1040, 1040); }
     23 
     24     void onDraw(SkCanvas* canvas) override {
     25         canvas->translate(20, 20);
     26 
     27         SkRect r = SkRect::MakeWH(1000, 1000);
     28 
     29         SkPaint paint;
     30         paint.setAntiAlias(true);
     31         paint.setStyle(SkPaint::kStroke_Style);
     32         paint.setStrokeWidth(15);
     33 
     34         const SkScalar inset = paint.getStrokeWidth() + 4;
     35         const SkScalar sweepAngle = 345;
     36         SkRandom rand;
     37 
     38         SkScalar sign = 1;
     39         while (r.width() > paint.getStrokeWidth() * 3) {
     40             paint.setColor(sk_tool_utils::color_to_565(rand.nextU() | (0xFF << 24)));
     41             SkScalar startAngle = rand.nextUScalar1() * 360;
     42 
     43             SkScalar speed = SkScalarSqrt(16 / r.width()) * 0.5f;
     44             startAngle += fRotate * 360 * speed * sign;
     45 
     46             SkPath path;
     47             path.addArc(r, startAngle, sweepAngle);
     48             canvas->drawPath(path, paint);
     49 
     50             r.inset(inset, inset);
     51             sign = -sign;
     52         }
     53     }
     54 
     55     bool onAnimate(const SkAnimTimer& timer) override {
     56         fRotate = timer.scaled(1, 360);
     57         return true;
     58     }
     59 
     60 private:
     61     SkScalar fRotate;
     62     typedef skiagm::GM INHERITED;
     63 };
     64 DEF_GM( return new AddArcGM; )
     65 
     66 ///////////////////////////////////////////////////
     67 
     68 #define R   400
     69 
     70 class AddArcMeasGM : public skiagm::GM {
     71 public:
     72     AddArcMeasGM() {}
     73 
     74 protected:
     75     SkString onShortName() override { return SkString("addarc_meas"); }
     76 
     77     SkISize onISize() override { return SkISize::Make(2*R + 40, 2*R + 40); }
     78 
     79     void onDraw(SkCanvas* canvas) override {
     80         canvas->translate(R + 20, R + 20);
     81 
     82         SkPaint paint;
     83         paint.setAntiAlias(true);
     84         paint.setStyle(SkPaint::kStroke_Style);
     85 
     86         SkPaint measPaint;
     87         measPaint.setAntiAlias(true);
     88         measPaint.setColor(SK_ColorRED);
     89 
     90         const SkRect oval = SkRect::MakeLTRB(-R, -R, R, R);
     91         canvas->drawOval(oval, paint);
     92 
     93         for (SkScalar deg = 0; deg < 360; deg += 10) {
     94             const SkScalar rad = SkDegreesToRadians(deg);
     95             SkScalar rx = SkScalarCos(rad) * R;
     96             SkScalar ry = SkScalarSin(rad) * R;
     97 
     98             canvas->drawLine(0, 0, rx, ry, paint);
     99 
    100             SkPath path;
    101             path.addArc(oval, 0, deg);
    102             SkPathMeasure meas(path, false);
    103             SkScalar arcLen = rad * R;
    104             SkPoint pos;
    105             if (meas.getPosTan(arcLen, &pos, nullptr)) {
    106                 canvas->drawLine(0, 0, pos.x(), pos.y(), measPaint);
    107             }
    108         }
    109     }
    110 
    111 private:
    112     typedef skiagm::GM INHERITED;
    113 };
    114 DEF_GM( return new AddArcMeasGM; )
    115 
    116 ///////////////////////////////////////////////////
    117 
    118 // Emphasize drawing a stroked oval (containing conics) and then scaling the results up,
    119 // to ensure that we compute the stroke taking the CTM into account
    120 //
    121 class StrokeCircleGM : public skiagm::GM {
    122 public:
    123     StrokeCircleGM() : fRotate(0) {}
    124 
    125 protected:
    126     SkString onShortName() override { return SkString("strokecircle"); }
    127 
    128     SkISize onISize() override { return SkISize::Make(520, 520); }
    129 
    130     void onDraw(SkCanvas* canvas) override {
    131         canvas->scale(20, 20);
    132         canvas->translate(13, 13);
    133 
    134         SkPaint paint;
    135         paint.setAntiAlias(true);
    136         paint.setStyle(SkPaint::kStroke_Style);
    137         paint.setStrokeWidth(SK_Scalar1 / 2);
    138 
    139         const SkScalar delta = paint.getStrokeWidth() * 3 / 2;
    140         SkRect r = SkRect::MakeXYWH(-12, -12, 24, 24);
    141         SkRandom rand;
    142 
    143         SkScalar sign = 1;
    144         while (r.width() > paint.getStrokeWidth() * 2) {
    145             SkAutoCanvasRestore acr(canvas, true);
    146             canvas->rotate(fRotate * sign);
    147 
    148             paint.setColor(sk_tool_utils::color_to_565(rand.nextU() | (0xFF << 24)));
    149             canvas->drawOval(r, paint);
    150             r.inset(delta, delta);
    151             sign = -sign;
    152         }
    153     }
    154 
    155     bool onAnimate(const SkAnimTimer& timer) override {
    156         fRotate = timer.scaled(60, 360);
    157         return true;
    158     }
    159 
    160 private:
    161     SkScalar fRotate;
    162 
    163     typedef skiagm::GM INHERITED;
    164 };
    165 DEF_GM( return new StrokeCircleGM; )
    166 
    167 //////////////////////
    168 
    169 // Fill circles and rotate them to test our Analytic Anti-Aliasing.
    170 // This test is based on StrokeCircleGM.
    171 class FillCircleGM : public skiagm::GM {
    172 public:
    173     FillCircleGM() : fRotate(0) {}
    174 
    175 protected:
    176     SkString onShortName() override { return SkString("fillcircle"); }
    177 
    178     SkISize onISize() override { return SkISize::Make(520, 520); }
    179 
    180     void onDraw(SkCanvas* canvas) override {
    181         canvas->scale(20, 20);
    182         canvas->translate(13, 13);
    183 
    184         SkPaint paint;
    185         paint.setAntiAlias(true);
    186         paint.setStyle(SkPaint::kStroke_Style);
    187         paint.setStrokeWidth(SK_Scalar1 / 2);
    188 
    189         const SkScalar strokeWidth = paint.getStrokeWidth();
    190         const SkScalar delta = strokeWidth * 3 / 2;
    191         SkRect r = SkRect::MakeXYWH(-12, -12, 24, 24);
    192         SkRandom rand;
    193 
    194         // Reset style to fill. We only need stroke stype for producing delta and strokeWidth
    195         paint.setStyle(SkPaint::kFill_Style);
    196 
    197         SkScalar sign = 1;
    198         while (r.width() > strokeWidth * 2) {
    199             SkAutoCanvasRestore acr(canvas, true);
    200             canvas->rotate(fRotate * sign);
    201             paint.setColor(sk_tool_utils::color_to_565(rand.nextU() | (0xFF << 24)));
    202             canvas->drawOval(r, paint);
    203             r.inset(delta, delta);
    204             sign = -sign;
    205         }
    206     }
    207 
    208     bool onAnimate(const SkAnimTimer& timer) override {
    209         fRotate = timer.scaled(60, 360);
    210         return true;
    211     }
    212 
    213 private:
    214     SkScalar fRotate;
    215 
    216     typedef skiagm::GM INHERITED;
    217 };
    218 DEF_GM( return new FillCircleGM; )
    219 
    220 //////////////////////
    221 
    222 static void html_canvas_arc(SkPath* path, SkScalar x, SkScalar y, SkScalar r, SkScalar start,
    223                             SkScalar end, bool ccw, bool callArcTo) {
    224     SkRect bounds = { x - r, y - r, x + r, y + r };
    225     SkScalar sweep = ccw ? end - start : start - end;
    226     if (callArcTo)
    227         path->arcTo(bounds, start, sweep, false);
    228     else
    229         path->addArc(bounds, start, sweep);
    230 }
    231 
    232 // Lifted from canvas-arc-circumference-fill-diffs.html
    233 class ManyArcsGM : public skiagm::GM {
    234 public:
    235     ManyArcsGM() {}
    236 
    237 protected:
    238     SkString onShortName() override { return SkString("manyarcs"); }
    239 
    240     SkISize onISize() override { return SkISize::Make(620, 330); }
    241 
    242     void onDraw(SkCanvas* canvas) override {
    243         SkPaint paint;
    244         paint.setAntiAlias(true);
    245         paint.setStyle(SkPaint::kStroke_Style);
    246 
    247         canvas->translate(10, 10);
    248 
    249         // 20 angles.
    250         SkScalar sweepAngles[] = {
    251                            -123.7f, -2.3f, -2, -1, -0.3f, -0.000001f, 0, 0.000001f, 0.3f, 0.7f,
    252                            1, 1.3f, 1.5f, 1.7f, 1.99999f, 2, 2.00001f, 2.3f, 4.3f, 3934723942837.3f
    253         };
    254         for (size_t i = 0; i < SK_ARRAY_COUNT(sweepAngles); ++i) {
    255             sweepAngles[i] *= 180;
    256         }
    257 
    258         SkScalar startAngles[] = { -1, -0.5f, 0, 0.5f };
    259         for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) {
    260             startAngles[i] *= 180;
    261         }
    262 
    263         bool anticlockwise = false;
    264         SkScalar sign = 1;
    265         for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles) * 2; ++i) {
    266             if (i == SK_ARRAY_COUNT(startAngles)) {
    267                 anticlockwise = true;
    268                 sign = -1;
    269             }
    270             SkScalar startAngle = startAngles[i % SK_ARRAY_COUNT(startAngles)] * sign;
    271             canvas->save();
    272             for (size_t j = 0; j < SK_ARRAY_COUNT(sweepAngles); ++j) {
    273                 SkPath path;
    274                 path.moveTo(0, 2);
    275                 html_canvas_arc(&path, 18, 15, 10, startAngle, startAngle + (sweepAngles[j] * sign),
    276                                 anticlockwise, true);
    277                 path.lineTo(0, 28);
    278                 canvas->drawPath(path, paint);
    279                 canvas->translate(30, 0);
    280             }
    281             canvas->restore();
    282             canvas->translate(0, 40);
    283         }
    284     }
    285 
    286 private:
    287     typedef skiagm::GM INHERITED;
    288 };
    289 DEF_GM( return new ManyArcsGM; )
    290 
    291 // Lifted from https://bugs.chromium.org/p/chromium/issues/detail?id=640031
    292 class TinyAngleBigRadiusArcsGM : public skiagm::GM {
    293 public:
    294     TinyAngleBigRadiusArcsGM() {}
    295 
    296 protected:
    297     SkString onShortName() override { return SkString("tinyanglearcs"); }
    298 
    299     SkISize onISize() override { return SkISize::Make(620, 330); }
    300 
    301     void onDraw(SkCanvas* canvas) override {
    302         SkPaint paint;
    303         paint.setAntiAlias(true);
    304         paint.setStyle(SkPaint::kStroke_Style);
    305 
    306         canvas->translate(50, 50);
    307 
    308         SkScalar outerRadius = 100000.0f;
    309         SkScalar innerRadius = outerRadius - 20.0f;
    310         SkScalar centerX = 50;
    311         SkScalar centerY = outerRadius;
    312         SkScalar startAngles[] = { 1.5f * SK_ScalarPI , 1.501f * SK_ScalarPI  };
    313         SkScalar sweepAngle = 10.0f / outerRadius;
    314 
    315         for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) {
    316             SkPath path;
    317             SkScalar endAngle = startAngles[i] + sweepAngle;
    318             path.moveTo(centerX + innerRadius * sk_float_cos(startAngles[i]),
    319                         centerY + innerRadius * sk_float_sin(startAngles[i]));
    320             path.lineTo(centerX + outerRadius * sk_float_cos(startAngles[i]),
    321                         centerY + outerRadius * sk_float_sin(startAngles[i]));
    322             // A combination of tiny sweepAngle + large radius, we should draw a line.
    323             html_canvas_arc(&path, centerX, outerRadius, outerRadius,
    324                             startAngles[i] * 180 / SK_ScalarPI, endAngle * 180 / SK_ScalarPI,
    325                             true, true);
    326             path.lineTo(centerX + innerRadius * sk_float_cos(endAngle),
    327                         centerY + innerRadius * sk_float_sin(endAngle));
    328             html_canvas_arc(&path, centerX, outerRadius, innerRadius,
    329                             endAngle * 180 / SK_ScalarPI, startAngles[i] * 180 / SK_ScalarPI,
    330                             true, false);
    331             canvas->drawPath(path, paint);
    332             canvas->translate(20, 0);
    333         }
    334     }
    335 
    336 private:
    337     typedef skiagm::GM INHERITED;
    338 };
    339 DEF_GM( return new TinyAngleBigRadiusArcsGM; )
    340