xref: /third_party/skia/gm/conicpaths.cpp (revision cb93a386)
1/*
2 * Copyright 2013 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/gm.h"
9#include "include/core/SkCanvas.h"
10#include "include/core/SkColor.h"
11#include "include/core/SkPaint.h"
12#include "include/core/SkPathBuilder.h"
13#include "include/core/SkPoint.h"
14#include "include/core/SkRect.h"
15#include "include/core/SkScalar.h"
16#include "include/core/SkSize.h"
17#include "include/core/SkString.h"
18#include "include/core/SkTypes.h"
19#include "include/private/SkFloatBits.h"
20#include "include/private/SkTArray.h"
21
22class ConicPathsGM : public skiagm::GM {
23protected:
24
25    SkString onShortName() override {
26        return SkString("conicpaths");
27    }
28
29    SkISize onISize() override {
30        return SkISize::Make(920, 960);
31    }
32
33    template <typename Proc> void append_path(Proc proc) {
34        SkPathBuilder b;
35        proc(&b);
36        fPaths.push_back(b.detach());
37    }
38
39    void onOnceBeforeDraw() override {
40        this->append_path([](SkPathBuilder* conicCircle) {
41            const SkScalar w = SkScalarSqrt(2)/2;
42            conicCircle->moveTo(0, 0);
43            conicCircle->conicTo(0, 50, 50, 50, w);
44            conicCircle->rConicTo(50, 0, 50, -50, w);
45            conicCircle->rConicTo(0, -50, -50, -50, w);
46            conicCircle->rConicTo(-50, 0, -50, 50, w);
47        });
48
49        this->append_path([](SkPathBuilder* hyperbola) {
50            hyperbola->moveTo(0, 0);
51            hyperbola->conicTo(0, 100, 100, 100, 2);
52        });
53
54        this->append_path([](SkPathBuilder* thinHyperbola) {
55            thinHyperbola->moveTo(0, 0);
56            thinHyperbola->conicTo(100, 100, 5, 0, 2);
57        });
58
59        this->append_path([](SkPathBuilder* veryThinHyperbola) {
60            veryThinHyperbola->moveTo(0, 0);
61            veryThinHyperbola->conicTo(100, 100, 1, 0, 2);
62        });
63
64        this->append_path([](SkPathBuilder* closedHyperbola) {
65            closedHyperbola->moveTo(0, 0);
66            closedHyperbola->conicTo(100, 100, 0, 0, 2);
67        });
68
69        this->append_path([](SkPathBuilder* nearParabola) {
70            // using 1 as weight defaults to using quadTo
71            nearParabola->moveTo(0, 0);
72            nearParabola->conicTo(0, 100, 100, 100, 0.999f);
73        });
74
75        this->append_path([](SkPathBuilder* thinEllipse) {
76            thinEllipse->moveTo(0, 0);
77            thinEllipse->conicTo(100, 100, 5, 0, SK_ScalarHalf);
78        });
79
80        this->append_path([](SkPathBuilder* veryThinEllipse) {
81            veryThinEllipse->moveTo(0, 0);
82            veryThinEllipse->conicTo(100, 100, 1, 0, SK_ScalarHalf);
83        });
84
85        this->append_path([](SkPathBuilder* closedEllipse) {
86            closedEllipse->moveTo(0,  0);
87            closedEllipse->conicTo(100, 100, 0, 0, SK_ScalarHalf);
88        });
89
90        {
91            SkPathBuilder b;
92            const SkScalar w = SkScalarSqrt(2)/2;
93            b.moveTo(2.1e+11f, -1.05e+11f);
94            b.conicTo(2.1e+11f, 0, 1.05e+11f, 0, w);
95            b.conicTo(0, 0, 0, -1.05e+11f, w);
96            b.conicTo(0, -2.1e+11f, 1.05e+11f, -2.1e+11f, w);
97            b.conicTo(2.1e+11f, -2.1e+11f, 2.1e+11f, -1.05e+11f, w);
98            fGiantCircle = b.detach();
99        }
100    }
101
102    void drawGiantCircle(SkCanvas* canvas) {
103        SkPaint paint;
104        canvas->drawPath(fGiantCircle, paint);
105    }
106
107    void onDraw(SkCanvas* canvas) override {
108        const SkAlpha kAlphaValue[] = { 0xFF, 0x40 };
109
110        const SkScalar margin = 15;
111        canvas->translate(margin, margin);
112
113        SkPaint paint;
114        for (int p = 0; p < fPaths.count(); ++p) {
115            canvas->save();
116            for (size_t a = 0; a < SK_ARRAY_COUNT(kAlphaValue); ++a) {
117                paint.setARGB(kAlphaValue[a], 0, 0, 0);
118                for (int aa = 0; aa < 2; ++aa) {
119                    paint.setAntiAlias(SkToBool(aa));
120                    for (int fh = 0; fh < 2; ++fh) {
121                        paint.setStroke(fh != 0);
122
123                        const SkRect& bounds = fPaths[p].getBounds();
124                        canvas->save();
125                        canvas->translate(-bounds.fLeft, -bounds.fTop);
126                        canvas->drawPath(fPaths[p], paint);
127                        canvas->restore();
128
129                        canvas->translate(110, 0);
130                    }
131                }
132            }
133            canvas->restore();
134            canvas->translate(0, 110);
135        }
136        canvas->restore();
137
138        this->drawGiantCircle(canvas);
139    }
140
141private:
142    SkTArray<SkPath> fPaths;
143    SkPath           fGiantCircle;
144    using INHERITED = skiagm::GM;
145};
146DEF_GM(return new ConicPathsGM;)
147
148//////////////////////////////////////////////////////////////////////////////
149
150/* arc should be on top of circle */
151DEF_SIMPLE_GM(arccirclegap, canvas, 250, 250) {
152    canvas->translate(50, 100);
153    SkPoint c = { 1052.5390625f, 506.8760978034711f };
154    SkScalar radius = 1096.702150363923f;
155    SkPaint paint;
156    paint.setAntiAlias(true);
157    paint.setStroke(true);
158    canvas->drawCircle(c, radius, paint);
159    SkPath path = SkPathBuilder().moveTo(288.88884710654133f, -280.26680862609f)
160                                 .arcTo({0, 0}, {-39.00216443306411f, 400.6058925796476f}, radius)
161                                 .detach();
162    paint.setColor(0xff007f00);
163    canvas->drawPath(path, paint);
164}
165
166/* circle should be antialiased */
167DEF_SIMPLE_GM(largecircle, canvas, 250, 250) {
168    canvas->translate(50, 100);
169    SkPoint c = { 1052.5390625f, 506.8760978034711f };
170    SkScalar radius = 1096.702150363923f;
171    SkPaint paint;
172    paint.setAntiAlias(true);
173    paint.setStroke(true);
174    canvas->drawCircle(c, radius, paint);
175}
176
177/* ovals should not be blurry */
178DEF_SIMPLE_GM(largeovals, canvas, 250, 250) {
179    // Test EllipseOp
180    SkRect r = SkRect::MakeXYWH(-520, -520, 5000, 4000);
181    SkPaint paint;
182    paint.setAntiAlias(true);
183    paint.setStroke(true);
184    paint.setStrokeWidth(100);
185    canvas->drawOval(r, paint);
186    r.offset(-15, -15);
187    paint.setColor(SK_ColorDKGRAY);
188    // we use stroke and fill to avoid falling into the SimpleFill path
189    paint.setStyle(SkPaint::kStrokeAndFill_Style);
190    paint.setStrokeWidth(1);
191    canvas->drawOval(r, paint);
192
193    // Test DIEllipseOp
194    canvas->rotate(1.0f);
195    r.offset(55, 55);
196    paint.setColor(SK_ColorGRAY);
197    paint.setStroke(true);
198    paint.setStrokeWidth(100);
199    canvas->drawOval(r, paint);
200    r.offset(-15, -15);
201    paint.setColor(SK_ColorLTGRAY);
202    paint.setStyle(SkPaint::kStrokeAndFill_Style);
203    paint.setStrokeWidth(1);
204    canvas->drawOval(r, paint);
205}
206
207DEF_SIMPLE_GM(crbug_640176, canvas, 250, 250) {
208    SkPathBuilder path;
209    path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000));  // 0, 0
210    path.lineTo(SkBits2Float(0x42cfd89a), SkBits2Float(0xc2700000));  // 103.923f, -60
211    path.lineTo(SkBits2Float(0x42cfd899), SkBits2Float(0xc2700006));  // 103.923f, -60
212    path.conicTo(SkBits2Float(0x42f00000), SkBits2Float(0xc2009d9c),
213            SkBits2Float(0x42f00001), SkBits2Float(0x00000000),
214            SkBits2Float(0x3f7746ea));  // 120, -32.1539f, 120, 0, 0.965926f
215
216    SkPaint paint;
217    paint.setAntiAlias(true);
218    canvas->translate(125, 125);
219    canvas->drawPath(path.detach(), paint);
220}
221