blob: 0f7b081fd77c2f46dcaff95f1f1e8a53a3477aee [file] [log] [blame]
commit-bot@chromium.org59167052013-11-09 01:37:30 +00001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
9#include "include/core/SkCanvas.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040010#include "include/core/SkPaint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/core/SkPath.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040012#include "include/core/SkScalar.h"
13#include "include/core/SkSize.h"
14#include "include/core/SkString.h"
15#include "include/core/SkTypes.h"
commit-bot@chromium.org59167052013-11-09 01:37:30 +000016
17namespace skiagm {
18
19// This GM tests a grab-bag of non-closed paths. All these paths look like
20// closed rects, but they don't call path.close(). Depending on the stroke
21// settings these slightly different paths give widely different results.
22class NonClosedPathsGM: public GM {
23public:
24 NonClosedPathsGM() {}
25
26 enum ClosureType {
27 TotallyNonClosed, // The last point doesn't coincide with the first one in the contour.
28 // The path looks not closed at all.
29
30 FakeCloseCorner, // The last point coincides with the first one at a corner.
31 // The path looks closed, but final rendering has 2 ends with cap.
32
33 FakeCloseMiddle, // The last point coincides with the first one in the middle of a line.
34 // The path looks closed, and the final rendering looks closed too.
35
36 kClosureTypeCount
37 };
38
39protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +000040
mtklein36352bf2015-03-25 18:17:31 -070041 SkString onShortName() override {
commit-bot@chromium.org59167052013-11-09 01:37:30 +000042 return SkString("nonclosedpaths");
43 }
44
45 // 12 * 18 + 3 cases, every case is 100 * 100 pixels.
mtklein36352bf2015-03-25 18:17:31 -070046 SkISize onISize() override {
commit-bot@chromium.org59167052013-11-09 01:37:30 +000047 return SkISize::Make(1220, 1920);
48 }
49
50 // Use rect-like geometry for non-closed path, for right angles make it
51 // easier to show the visual difference of lineCap and lineJoin.
52 static void MakePath(SkPath* path, ClosureType type) {
53 if (FakeCloseMiddle == type) {
54 path->moveTo(30, 50);
55 path->lineTo(30, 30);
56 } else {
57 path->moveTo(30, 30);
58 }
59 path->lineTo(70, 30);
60 path->lineTo(70, 70);
61 path->lineTo(30, 70);
62 path->lineTo(30, 50);
63 if (FakeCloseCorner == type) {
64 path->lineTo(30, 30);
65 }
66 }
67
68 // Set the location for the current test on the canvas
69 static void SetLocation(SkCanvas* canvas, int counter, int lineNum) {
70 SkScalar x = SK_Scalar1 * 100 * (counter % lineNum) + 10 + SK_Scalar1 / 4;
71 SkScalar y = SK_Scalar1 * 100 * (counter / lineNum) + 10 + 3 * SK_Scalar1 / 4;
72 canvas->translate(x, y);
73 }
74
mtklein36352bf2015-03-25 18:17:31 -070075 void onDraw(SkCanvas* canvas) override {
commit-bot@chromium.org59167052013-11-09 01:37:30 +000076 // Stroke widths are:
77 // 0(may use hairline rendering), 10(common case for stroke-style)
78 // 40 and 50(>= geometry width/height, make the contour filled in fact)
mtkleindbfd7ab2016-09-01 11:24:54 -070079 constexpr int kStrokeWidth[] = {0, 10, 40, 50};
reed@google.com7fa2a652014-01-27 13:42:58 +000080 int numWidths = SK_ARRAY_COUNT(kStrokeWidth);
commit-bot@chromium.org59167052013-11-09 01:37:30 +000081
mtkleindbfd7ab2016-09-01 11:24:54 -070082 constexpr SkPaint::Style kStyle[] = {
commit-bot@chromium.org59167052013-11-09 01:37:30 +000083 SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style
84 };
85
mtkleindbfd7ab2016-09-01 11:24:54 -070086 constexpr SkPaint::Cap kCap[] = {
commit-bot@chromium.org59167052013-11-09 01:37:30 +000087 SkPaint::kButt_Cap, SkPaint::kRound_Cap, SkPaint::kSquare_Cap
88 };
89
mtkleindbfd7ab2016-09-01 11:24:54 -070090 constexpr SkPaint::Join kJoin[] = {
commit-bot@chromium.org59167052013-11-09 01:37:30 +000091 SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join
92 };
93
mtkleindbfd7ab2016-09-01 11:24:54 -070094 constexpr ClosureType kType[] = {
commit-bot@chromium.org59167052013-11-09 01:37:30 +000095 TotallyNonClosed, FakeCloseCorner, FakeCloseMiddle
96 };
97
98 int counter = 0;
99 SkPaint paint;
100 paint.setAntiAlias(true);
101
102 // For stroke style painter and fill-and-stroke style painter
103 for (size_t type = 0; type < kClosureTypeCount; ++type) {
104 for (size_t style = 0; style < SK_ARRAY_COUNT(kStyle); ++style) {
105 for (size_t cap = 0; cap < SK_ARRAY_COUNT(kCap); ++cap) {
106 for (size_t join = 0; join < SK_ARRAY_COUNT(kJoin); ++join) {
reed@google.com7fa2a652014-01-27 13:42:58 +0000107 for (int width = 0; width < numWidths; ++width) {
commit-bot@chromium.org59167052013-11-09 01:37:30 +0000108 canvas->save();
109 SetLocation(canvas, counter, SkPaint::kJoinCount * numWidths);
110
111 SkPath path;
112 MakePath(&path, kType[type]);
113
114 paint.setStyle(kStyle[style]);
115 paint.setStrokeCap(kCap[cap]);
116 paint.setStrokeJoin(kJoin[join]);
117 paint.setStrokeWidth(SkIntToScalar(kStrokeWidth[width]));
118
119 canvas->drawPath(path, paint);
120 canvas->restore();
121 ++counter;
122 }
123 }
124 }
125 }
126 }
127
128 // For fill style painter
129 paint.setStyle(SkPaint::kFill_Style);
130 for (size_t type = 0; type < kClosureTypeCount; ++type) {
131 canvas->save();
132 SetLocation(canvas, counter, SkPaint::kJoinCount * numWidths);
133
134 SkPath path;
135 MakePath(&path, kType[type]);
136
137 canvas->drawPath(path, paint);
138 canvas->restore();
139 ++counter;
140 }
141 }
142
143private:
144 typedef GM INHERITED;
145};
146
147//////////////////////////////////////////////////////////////////////////////
148
149DEF_GM(return new NonClosedPathsGM;)
150
151}