Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
path_stroke_with_zero_length.cpp
Go to the documentation of this file.
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/gm.h"
15#include "include/core/SkPath.h"
16#include "include/core/SkRect.h"
25
26// GM to test combinations of stroking zero length paths with different caps and other settings
27// Variables:
28// * Antialiasing: On, Off
29// * Caps: Butt, Round, Square
30// * Stroke width: 0, 0.9, 1, 1.1, 15, 25
31// * Path form: M, ML, MLZ, MZ
32// * Path contours: 1 or 2
33// * Path verbs: Line, Quad, Cubic, Conic
34//
35// Each test is drawn to a 50x20 offscreen surface, and expected to produce some number (0 - 2) of
36// visible pieces of cap geometry. These are counted by scanning horizontally for peaks (blobs).
37
38static void draw_path_cell(SkCanvas* canvas,
40 int expectedCaps) {
41 static const SkColor kFailureRed = 0x7F7F0000;
42 static const SkColor kFailureYellow = 0x7F7F7F00;
43 static const SkColor kSuccessGreen = 0x7F007f00;
44
45 int w = surface->width(), h = surface->height();
46
47 // Read the pixels back
50 pmap.alloc(info);
51 if (!surface->readPixels(pmap, 0, 0)) {
52 return;
53 }
54
55 // To account for rasterization differences, we scan the middle two rows [y, y+1] of the image
56 SkASSERT(h % 2 == 0);
57 int y = (h - 1) / 2;
58
59 bool inBlob = false;
60 int numBlobs = 0;
61 for (int x = 0; x < w; ++x) {
62 // We drew white-on-black. We can look for any non-zero value. Just check red.
63 // And we care if either row is non-zero, so just add them to simplify everything.
64 uint32_t v = SkGetPackedR32(*pmap.addr32(x, y)) + SkGetPackedR32(*pmap.addr32(x, y + 1));
65
66 if (!inBlob && v) {
67 ++numBlobs;
68 }
69 inBlob = SkToBool(v);
70 }
71
73
74 if (numBlobs == expectedCaps) {
75 result.setColor(kSuccessGreen); // Green
76 } else if (numBlobs > expectedCaps) {
77 result.setColor(kFailureYellow); // Yellow -- more geometry than expected
78 } else {
79 result.setColor(kFailureRed); // Red -- missing some geometry
80 }
81
82 auto img = surface->makeImageSnapshot();
83 canvas->drawImage(img, 0, 0);
84 canvas->drawRect(SkRect::MakeWH(w, h), result);
85}
86
92
93static const SkScalar kWidths[] = { 0.0f, 0.9f, 1.0f, 1.1f, 15.0f, 25.0f };
94
95// Full set of path structures for single contour case (each primitive with and without a close)
96static const char* kAllVerbs[] = {
97 nullptr,
98 "z ",
99 "l 0 0 ",
100 "l 0 0 z ",
101 "q 0 0 0 0 ",
102 "q 0 0 0 0 z ",
103 "c 0 0 0 0 0 0 ",
104 "c 0 0 0 0 0 0 z ",
105 "a 0 0 0 0 0 0 0 ",
106 "a 0 0 0 0 0 0 0 z "
107};
108
109// Reduced set of path structures for double contour case, to keep total number of cases down
110static const char* kSomeVerbs[] = {
111 nullptr,
112 "z ",
113 "l 0 0 ",
114 "l 0 0 z ",
115 "q 0 0 0 0 ",
116 "q 0 0 0 0 z ",
117};
118
119static const int kCellWidth = 50;
120static const int kCellHeight = 20;
121static const int kCellPad = 2;
122
123static const int kNumRows = std::size(kCaps) * std::size(kWidths);
124static const int kNumColumns = std::size(kAllVerbs);
127
128static const int kDblContourNumColums = std::size(kSomeVerbs) * std::size(kSomeVerbs);
130
132 SkString* errorMsg) {
133 canvas->translate(kCellPad, kCellPad);
134
136 auto surface = canvas->makeSurface(info);
137 if (!surface) {
139 }
140
142 paint.setColor(SK_ColorWHITE);
143 paint.setAntiAlias(aa);
145
146 for (auto cap : kCaps) {
147 for (auto width : kWidths) {
148 paint.setStrokeCap(cap);
149 paint.setStrokeWidth(width);
150 canvas->save();
151
152 for (auto verb : kAllVerbs) {
153 SkString pathStr;
154 pathStr.appendf("M %f %f ", (kCellWidth - 1) * 0.5f, (kCellHeight - 1) * 0.5f);
155 if (verb) {
156 pathStr.append(verb);
157 }
158
159 SkPath path;
160 SkParsePath::FromSVGString(pathStr.c_str(), &path);
161
162 surface->getCanvas()->clear(SK_ColorTRANSPARENT);
163 surface->getCanvas()->drawPath(path, paint);
164
165 // All cases should draw one cap, except for butt capped, and dangling moves
166 // (without a verb or close), which shouldn't draw anything.
167 int expectedCaps = ((SkPaint::kButt_Cap == cap) || !verb) ? 0 : 1;
168
169 draw_path_cell(canvas, surface.get(), expectedCaps);
170 canvas->translate(kCellWidth + kCellPad, 0);
171 }
172 canvas->restore();
173 canvas->translate(0, kCellHeight + kCellPad);
174 }
175 }
176
178}
179
180DEF_SIMPLE_GM_BG_CAN_FAIL(zero_length_paths_aa, canvas, errorMsg,
182 return draw_zero_length_capped_paths(canvas, true, errorMsg);
183}
184
185DEF_SIMPLE_GM_BG_CAN_FAIL(zero_length_paths_bw, canvas, errorMsg,
187 return draw_zero_length_capped_paths(canvas, false, errorMsg);
188}
189
191 SkString* errorMsg) {
192 auto rContext = canvas->recordingContext();
193 auto dContext = GrAsDirectContext(rContext);
194
195 if (!dContext && rContext) {
196 *errorMsg = "Not supported in DDL mode";
198 }
199 canvas->translate(kCellPad, kCellPad);
200
202 auto surface = canvas->makeSurface(info);
203 if (!surface) {
205 }
206
208 paint.setColor(SK_ColorWHITE);
209 paint.setAntiAlias(aa);
211
212 for (auto cap : kCaps) {
213 for (auto width : kWidths) {
214 paint.setStrokeCap(cap);
215 paint.setStrokeWidth(width);
216 canvas->save();
217
218 for (auto firstVerb : kSomeVerbs) {
219 for (auto secondVerb : kSomeVerbs) {
220 int expectedCaps = 0;
221
222 SkString pathStr;
223 pathStr.append("M 9.5 9.5 ");
224 if (firstVerb) {
225 pathStr.append(firstVerb);
226 ++expectedCaps;
227 }
228 pathStr.append("M 40.5 9.5 ");
229 if (secondVerb) {
230 pathStr.append(secondVerb);
231 ++expectedCaps;
232 }
233
234 SkPath path;
235 SkParsePath::FromSVGString(pathStr.c_str(), &path);
236
237 surface->getCanvas()->clear(SK_ColorTRANSPARENT);
238 surface->getCanvas()->drawPath(path, paint);
239
240 if (SkPaint::kButt_Cap == cap) {
241 expectedCaps = 0;
242 }
243
244 draw_path_cell(canvas, surface.get(), expectedCaps);
245 canvas->translate(kCellWidth + kCellPad, 0);
246 }
247 }
248 canvas->restore();
249 canvas->translate(0, kCellHeight + kCellPad);
250 }
251 }
252
254}
255
256DEF_SIMPLE_GM_BG_CAN_FAIL(zero_length_paths_dbl_aa, canvas, errorMsg,
258 return draw_zero_length_capped_paths_dbl_contour(canvas, true, errorMsg);
259}
260
261DEF_SIMPLE_GM_BG_CAN_FAIL(zero_length_paths_dbl_bw, canvas, errorMsg,
263 return draw_zero_length_capped_paths_dbl_contour(canvas, false, errorMsg);
264}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
static GrDirectContext * GrAsDirectContext(GrContext_Base *base)
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SkGetPackedR32(packed)
Definition SkColorPriv.h:93
uint32_t SkColor
Definition SkColor.h:37
constexpr SkColor SK_ColorTRANSPARENT
Definition SkColor.h:99
constexpr SkColor SK_ColorBLACK
Definition SkColor.h:103
constexpr SkColor SK_ColorWHITE
Definition SkColor.h:122
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
void alloc(const SkImageInfo &)
void drawRect(const SkRect &rect, const SkPaint &paint)
void restore()
Definition SkCanvas.cpp:465
void translate(SkScalar dx, SkScalar dy)
sk_sp< SkSurface > makeSurface(const SkImageInfo &info, const SkSurfaceProps *props=nullptr)
virtual GrRecordingContext * recordingContext() const
int save()
Definition SkCanvas.cpp:451
SkImageInfo imageInfo() const
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition SkCanvas.h:1528
@ kRound_Cap
adds circle
Definition SkPaint.h:335
@ kButt_Cap
no stroke extension
Definition SkPaint.h:334
@ kSquare_Cap
adds square
Definition SkPaint.h:336
void setColor(SkColor color)
Definition SkPaint.cpp:119
@ kStroke_Style
set to stroke geometry
Definition SkPaint.h:194
static bool FromSVGString(const char str[], SkPath *)
const uint32_t * addr32() const
Definition SkPixmap.h:352
void append(const char text[])
Definition SkString.h:203
const char * c_str() const
Definition SkString.h:133
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
Definition SkString.cpp:550
const Paint & paint
VkSurfaceKHR surface
Definition main.cc:49
float SkScalar
Definition extension.cpp:12
GAsyncResult * result
#define DEF_SIMPLE_GM_BG_CAN_FAIL(NAME, CANVAS, ERR_MSG, W, H, BGCOLOR)
Definition gm.h:64
double y
double x
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
DrawResult
Definition gm.h:104
static skiagm::DrawResult draw_zero_length_capped_paths_dbl_contour(SkCanvas *canvas, bool aa, SkString *errorMsg)
static skiagm::DrawResult draw_zero_length_capped_paths(SkCanvas *canvas, bool aa, SkString *errorMsg)
static const int kNumRows
static const int kTotalWidth
static const SkPaint::Cap kCaps[]
static const int kNumColumns
static const int kDblContourTotalWidth
static const char * kAllVerbs[]
static const int kTotalHeight
static const int kDblContourNumColums
static const int kCellWidth
static const SkScalar kWidths[]
static const char * kSomeVerbs[]
static const int kCellHeight
static void draw_path_cell(SkCanvas *canvas, SkSurface *surface, int expectedCaps)
static const int kCellPad
SkScalar w
SkScalar h
int32_t width
SkImageInfo makeWH(int newWidth, int newHeight) const
static SkImageInfo MakeN32Premul(int width, int height)
static constexpr SkRect MakeWH(float w, float h)
Definition SkRect.h:609