xref: /aosp_15_r20/external/skia/tests/SVGDeviceTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2015 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
9*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_XML
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorFilter.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathEffect.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTextBlob.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTileMode.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkDashPathEffect.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/svg/SkSVGCanvas.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/utils/SkParse.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkImageShader.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/svg/SkSVGDevice.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/xml/SkDOM.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/xml/SkXMLWriter.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h"
32*c8dee2aaSAndroid Build Coastguard Worker 
33*c8dee2aaSAndroid Build Coastguard Worker #include <string>
34*c8dee2aaSAndroid Build Coastguard Worker 
35*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
36*c8dee2aaSAndroid Build Coastguard Worker 
37*c8dee2aaSAndroid Build Coastguard Worker #define ABORT_TEST(r, cond, ...)                                   \
38*c8dee2aaSAndroid Build Coastguard Worker     do {                                                           \
39*c8dee2aaSAndroid Build Coastguard Worker         if (cond) {                                                \
40*c8dee2aaSAndroid Build Coastguard Worker             REPORT_FAILURE(r, #cond, SkStringPrintf(__VA_ARGS__)); \
41*c8dee2aaSAndroid Build Coastguard Worker             return;                                                \
42*c8dee2aaSAndroid Build Coastguard Worker         }                                                          \
43*c8dee2aaSAndroid Build Coastguard Worker     } while (0)
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker 
MakeDOMCanvas(SkDOM * dom,uint32_t flags=0)46*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<SkCanvas> MakeDOMCanvas(SkDOM* dom, uint32_t flags = 0) {
47*c8dee2aaSAndroid Build Coastguard Worker     auto svgDevice = SkSVGDevice::Make(SkISize::Make(100, 100),
48*c8dee2aaSAndroid Build Coastguard Worker                                        std::make_unique<SkXMLParserWriter>(dom->beginParsing()),
49*c8dee2aaSAndroid Build Coastguard Worker                                        flags);
50*c8dee2aaSAndroid Build Coastguard Worker     return svgDevice ? std::make_unique<SkCanvas>(svgDevice)
51*c8dee2aaSAndroid Build Coastguard Worker                      : nullptr;
52*c8dee2aaSAndroid Build Coastguard Worker }
53*c8dee2aaSAndroid Build Coastguard Worker 
54*c8dee2aaSAndroid Build Coastguard Worker namespace {
55*c8dee2aaSAndroid Build Coastguard Worker 
56*c8dee2aaSAndroid Build Coastguard Worker 
check_text_node(skiatest::Reporter * reporter,const SkDOM & dom,const SkDOM::Node * root,const SkPoint & offset,unsigned scalarsPerPos,const char * txt,const char * expected)57*c8dee2aaSAndroid Build Coastguard Worker void check_text_node(skiatest::Reporter* reporter,
58*c8dee2aaSAndroid Build Coastguard Worker                      const SkDOM& dom,
59*c8dee2aaSAndroid Build Coastguard Worker                      const SkDOM::Node* root,
60*c8dee2aaSAndroid Build Coastguard Worker                      const SkPoint& offset,
61*c8dee2aaSAndroid Build Coastguard Worker                      unsigned scalarsPerPos,
62*c8dee2aaSAndroid Build Coastguard Worker                      const char* txt,
63*c8dee2aaSAndroid Build Coastguard Worker                      const char* expected) {
64*c8dee2aaSAndroid Build Coastguard Worker     if (root == nullptr) {
65*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "root element not found.");
66*c8dee2aaSAndroid Build Coastguard Worker         return;
67*c8dee2aaSAndroid Build Coastguard Worker     }
68*c8dee2aaSAndroid Build Coastguard Worker 
69*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* textElem = dom.getFirstChild(root, "text");
70*c8dee2aaSAndroid Build Coastguard Worker     if (textElem == nullptr) {
71*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "<text> element not found.");
72*c8dee2aaSAndroid Build Coastguard Worker         return;
73*c8dee2aaSAndroid Build Coastguard Worker     }
74*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, dom.getType(textElem) == SkDOM::kElement_Type);
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* textNode= dom.getFirstChild(textElem);
77*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, textNode != nullptr);
78*c8dee2aaSAndroid Build Coastguard Worker     if (textNode != nullptr) {
79*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, dom.getType(textNode) == SkDOM::kText_Type);
80*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, strcmp(expected, dom.getName(textNode)) == 0);
81*c8dee2aaSAndroid Build Coastguard Worker     }
82*c8dee2aaSAndroid Build Coastguard Worker 
83*c8dee2aaSAndroid Build Coastguard Worker     int textLen = SkToInt(strlen(expected));
84*c8dee2aaSAndroid Build Coastguard Worker 
85*c8dee2aaSAndroid Build Coastguard Worker     const char* x = dom.findAttr(textElem, "x");
86*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, x != nullptr);
87*c8dee2aaSAndroid Build Coastguard Worker     if (x != nullptr) {
88*c8dee2aaSAndroid Build Coastguard Worker         int xposCount = textLen;
89*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, SkParse::Count(x) == xposCount);
90*c8dee2aaSAndroid Build Coastguard Worker 
91*c8dee2aaSAndroid Build Coastguard Worker         AutoTMalloc<SkScalar> xpos(xposCount);
92*c8dee2aaSAndroid Build Coastguard Worker         SkParse::FindScalars(x, xpos.get(), xposCount);
93*c8dee2aaSAndroid Build Coastguard Worker         if (scalarsPerPos < 1) {
94*c8dee2aaSAndroid Build Coastguard Worker             // For default-positioned text, we cannot make any assumptions regarding
95*c8dee2aaSAndroid Build Coastguard Worker             // the first glyph position when the string has leading whitespace (to be stripped).
96*c8dee2aaSAndroid Build Coastguard Worker             if (txt[0] != ' ' && txt[0] != '\t') {
97*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, xpos[0] == offset.x());
98*c8dee2aaSAndroid Build Coastguard Worker             }
99*c8dee2aaSAndroid Build Coastguard Worker         } else {
100*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < xposCount; ++i) {
101*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, xpos[i] == SkIntToScalar(expected[i]));
102*c8dee2aaSAndroid Build Coastguard Worker             }
103*c8dee2aaSAndroid Build Coastguard Worker         }
104*c8dee2aaSAndroid Build Coastguard Worker     }
105*c8dee2aaSAndroid Build Coastguard Worker 
106*c8dee2aaSAndroid Build Coastguard Worker     const char* y = dom.findAttr(textElem, "y");
107*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, y != nullptr);
108*c8dee2aaSAndroid Build Coastguard Worker     if (y != nullptr) {
109*c8dee2aaSAndroid Build Coastguard Worker         int yposCount = (scalarsPerPos < 2) ? 1 : textLen;
110*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, SkParse::Count(y) == yposCount);
111*c8dee2aaSAndroid Build Coastguard Worker 
112*c8dee2aaSAndroid Build Coastguard Worker         AutoTMalloc<SkScalar> ypos(yposCount);
113*c8dee2aaSAndroid Build Coastguard Worker         SkParse::FindScalars(y, ypos.get(), yposCount);
114*c8dee2aaSAndroid Build Coastguard Worker         if (scalarsPerPos < 2) {
115*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, ypos[0] == offset.y());
116*c8dee2aaSAndroid Build Coastguard Worker         } else {
117*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < yposCount; ++i) {
118*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, ypos[i] == 150 - SkIntToScalar(expected[i]));
119*c8dee2aaSAndroid Build Coastguard Worker             }
120*c8dee2aaSAndroid Build Coastguard Worker         }
121*c8dee2aaSAndroid Build Coastguard Worker     }
122*c8dee2aaSAndroid Build Coastguard Worker }
123*c8dee2aaSAndroid Build Coastguard Worker 
test_whitespace_pos(skiatest::Reporter * reporter,const char * txt,const char * expected)124*c8dee2aaSAndroid Build Coastguard Worker void test_whitespace_pos(skiatest::Reporter* reporter,
125*c8dee2aaSAndroid Build Coastguard Worker                          const char* txt,
126*c8dee2aaSAndroid Build Coastguard Worker                          const char* expected) {
127*c8dee2aaSAndroid Build Coastguard Worker     size_t len = strlen(txt);
128*c8dee2aaSAndroid Build Coastguard Worker 
129*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
130*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
131*c8dee2aaSAndroid Build Coastguard Worker     SkFont font = ToolUtils::DefaultPortableFont();
132*c8dee2aaSAndroid Build Coastguard Worker     SkPoint offset = SkPoint::Make(10, 20);
133*c8dee2aaSAndroid Build Coastguard Worker 
134*c8dee2aaSAndroid Build Coastguard Worker     {
135*c8dee2aaSAndroid Build Coastguard Worker         MakeDOMCanvas(&dom)->drawSimpleText(txt, len, SkTextEncoding::kUTF8,
136*c8dee2aaSAndroid Build Coastguard Worker                                             offset.x(), offset.y(), font, paint);
137*c8dee2aaSAndroid Build Coastguard Worker     }
138*c8dee2aaSAndroid Build Coastguard Worker     check_text_node(reporter, dom, dom.finishParsing(), offset, 0, txt, expected);
139*c8dee2aaSAndroid Build Coastguard Worker 
140*c8dee2aaSAndroid Build Coastguard Worker     {
141*c8dee2aaSAndroid Build Coastguard Worker         AutoTMalloc<SkScalar> xpos(len);
142*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < SkToInt(len); ++i) {
143*c8dee2aaSAndroid Build Coastguard Worker             xpos[i] = SkIntToScalar(txt[i]);
144*c8dee2aaSAndroid Build Coastguard Worker         }
145*c8dee2aaSAndroid Build Coastguard Worker 
146*c8dee2aaSAndroid Build Coastguard Worker         auto blob = SkTextBlob::MakeFromPosTextH(txt, len, &xpos[0], offset.y(), font);
147*c8dee2aaSAndroid Build Coastguard Worker         MakeDOMCanvas(&dom)->drawTextBlob(blob, 0, 0, paint);
148*c8dee2aaSAndroid Build Coastguard Worker     }
149*c8dee2aaSAndroid Build Coastguard Worker     check_text_node(reporter, dom, dom.finishParsing(), offset, 1, txt, expected);
150*c8dee2aaSAndroid Build Coastguard Worker 
151*c8dee2aaSAndroid Build Coastguard Worker     {
152*c8dee2aaSAndroid Build Coastguard Worker         AutoTMalloc<SkPoint> pos(len);
153*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < SkToInt(len); ++i) {
154*c8dee2aaSAndroid Build Coastguard Worker             pos[i] = SkPoint::Make(SkIntToScalar(txt[i]), 150 - SkIntToScalar(txt[i]));
155*c8dee2aaSAndroid Build Coastguard Worker         }
156*c8dee2aaSAndroid Build Coastguard Worker 
157*c8dee2aaSAndroid Build Coastguard Worker         auto blob = SkTextBlob::MakeFromPosText(txt, len, &pos[0], font);
158*c8dee2aaSAndroid Build Coastguard Worker         MakeDOMCanvas(&dom)->drawTextBlob(blob, 0, 0, paint);
159*c8dee2aaSAndroid Build Coastguard Worker     }
160*c8dee2aaSAndroid Build Coastguard Worker     check_text_node(reporter, dom, dom.finishParsing(), offset, 2, txt, expected);
161*c8dee2aaSAndroid Build Coastguard Worker }
162*c8dee2aaSAndroid Build Coastguard Worker 
163*c8dee2aaSAndroid Build Coastguard Worker } // namespace
164*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_whitespace_pos,reporter)165*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_whitespace_pos, reporter) {
166*c8dee2aaSAndroid Build Coastguard Worker     static const struct {
167*c8dee2aaSAndroid Build Coastguard Worker         const char* tst_in;
168*c8dee2aaSAndroid Build Coastguard Worker         const char* tst_out;
169*c8dee2aaSAndroid Build Coastguard Worker     } tests[] = {
170*c8dee2aaSAndroid Build Coastguard Worker         { "abcd"      , "abcd" },
171*c8dee2aaSAndroid Build Coastguard Worker         { "ab cd"     , "ab cd" },
172*c8dee2aaSAndroid Build Coastguard Worker         { "ab \t\t cd", "ab cd" },
173*c8dee2aaSAndroid Build Coastguard Worker         { " abcd"     , "abcd" },
174*c8dee2aaSAndroid Build Coastguard Worker         { "  abcd"    , "abcd" },
175*c8dee2aaSAndroid Build Coastguard Worker         { " \t\t abcd", "abcd" },
176*c8dee2aaSAndroid Build Coastguard Worker         { "abcd "     , "abcd " }, // we allow one trailing whitespace char
177*c8dee2aaSAndroid Build Coastguard Worker         { "abcd  "    , "abcd " }, // because it makes no difference and
178*c8dee2aaSAndroid Build Coastguard Worker         { "abcd\t  "  , "abcd " }, // simplifies the implementation
179*c8dee2aaSAndroid Build Coastguard Worker         { "\t\t  \t ab \t\t  \t cd \t\t   \t  ", "ab cd " },
180*c8dee2aaSAndroid Build Coastguard Worker     };
181*c8dee2aaSAndroid Build Coastguard Worker 
182*c8dee2aaSAndroid Build Coastguard Worker     for (unsigned i = 0; i < std::size(tests); ++i) {
183*c8dee2aaSAndroid Build Coastguard Worker         test_whitespace_pos(reporter, tests[i].tst_in, tests[i].tst_out);
184*c8dee2aaSAndroid Build Coastguard Worker     }
185*c8dee2aaSAndroid Build Coastguard Worker }
186*c8dee2aaSAndroid Build Coastguard Worker 
SetImageShader(SkPaint * paint,int imageWidth,int imageHeight,SkTileMode xTile,SkTileMode yTile)187*c8dee2aaSAndroid Build Coastguard Worker void SetImageShader(SkPaint* paint, int imageWidth, int imageHeight, SkTileMode xTile,
188*c8dee2aaSAndroid Build Coastguard Worker                     SkTileMode yTile) {
189*c8dee2aaSAndroid Build Coastguard Worker     auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(imageWidth, imageHeight));
190*c8dee2aaSAndroid Build Coastguard Worker     paint->setShader(surface->makeImageSnapshot()->makeShader(xTile, yTile, SkSamplingOptions()));
191*c8dee2aaSAndroid Build Coastguard Worker }
192*c8dee2aaSAndroid Build Coastguard Worker 
193*c8dee2aaSAndroid Build Coastguard Worker // Attempt to find the three nodes on which we have expectations:
194*c8dee2aaSAndroid Build Coastguard Worker // the pattern node, the image within that pattern, and the rect which
195*c8dee2aaSAndroid Build Coastguard Worker // uses the pattern as a fill.
196*c8dee2aaSAndroid Build Coastguard Worker // returns false if not all nodes are found.
FindImageShaderNodes(skiatest::Reporter * reporter,const SkDOM * dom,const SkDOM::Node * root,const SkDOM::Node ** patternOut,const SkDOM::Node ** imageOut,const SkDOM::Node ** rectOut)197*c8dee2aaSAndroid Build Coastguard Worker bool FindImageShaderNodes(skiatest::Reporter* reporter, const SkDOM* dom, const SkDOM::Node* root,
198*c8dee2aaSAndroid Build Coastguard Worker                           const SkDOM::Node** patternOut, const SkDOM::Node** imageOut,
199*c8dee2aaSAndroid Build Coastguard Worker                           const SkDOM::Node** rectOut) {
200*c8dee2aaSAndroid Build Coastguard Worker     if (root == nullptr || dom == nullptr) {
201*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "root element not found");
202*c8dee2aaSAndroid Build Coastguard Worker         return false;
203*c8dee2aaSAndroid Build Coastguard Worker     }
204*c8dee2aaSAndroid Build Coastguard Worker 
205*c8dee2aaSAndroid Build Coastguard Worker 
206*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* rect = dom->getFirstChild(root, "rect");
207*c8dee2aaSAndroid Build Coastguard Worker     if (rect == nullptr) {
208*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "rect not found");
209*c8dee2aaSAndroid Build Coastguard Worker         return false;
210*c8dee2aaSAndroid Build Coastguard Worker     }
211*c8dee2aaSAndroid Build Coastguard Worker     *rectOut = rect;
212*c8dee2aaSAndroid Build Coastguard Worker 
213*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* defs = dom->getFirstChild(root, "defs");
214*c8dee2aaSAndroid Build Coastguard Worker     if (defs == nullptr) {
215*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "defs not found");
216*c8dee2aaSAndroid Build Coastguard Worker         return false;
217*c8dee2aaSAndroid Build Coastguard Worker     }
218*c8dee2aaSAndroid Build Coastguard Worker 
219*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* pattern = dom->getFirstChild(defs, "pattern");
220*c8dee2aaSAndroid Build Coastguard Worker     if (pattern == nullptr) {
221*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "pattern not found");
222*c8dee2aaSAndroid Build Coastguard Worker         return false;
223*c8dee2aaSAndroid Build Coastguard Worker     }
224*c8dee2aaSAndroid Build Coastguard Worker     *patternOut = pattern;
225*c8dee2aaSAndroid Build Coastguard Worker 
226*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* image = dom->getFirstChild(pattern, "image");
227*c8dee2aaSAndroid Build Coastguard Worker     if (image == nullptr) {
228*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "image not found");
229*c8dee2aaSAndroid Build Coastguard Worker         return false;
230*c8dee2aaSAndroid Build Coastguard Worker     }
231*c8dee2aaSAndroid Build Coastguard Worker     *imageOut = image;
232*c8dee2aaSAndroid Build Coastguard Worker 
233*c8dee2aaSAndroid Build Coastguard Worker     return true;
234*c8dee2aaSAndroid Build Coastguard Worker }
235*c8dee2aaSAndroid Build Coastguard Worker 
ImageShaderTestSetup(SkDOM * dom,SkPaint * paint,int imageWidth,int imageHeight,int rectWidth,int rectHeight,SkTileMode xTile,SkTileMode yTile)236*c8dee2aaSAndroid Build Coastguard Worker void ImageShaderTestSetup(SkDOM* dom, SkPaint* paint, int imageWidth, int imageHeight,
237*c8dee2aaSAndroid Build Coastguard Worker                           int rectWidth, int rectHeight, SkTileMode xTile, SkTileMode yTile) {
238*c8dee2aaSAndroid Build Coastguard Worker     SetImageShader(paint, imageWidth, imageHeight, xTile, yTile);
239*c8dee2aaSAndroid Build Coastguard Worker     auto svgCanvas = MakeDOMCanvas(dom);
240*c8dee2aaSAndroid Build Coastguard Worker 
241*c8dee2aaSAndroid Build Coastguard Worker     SkRect bounds{0, 0, SkIntToScalar(rectWidth), SkIntToScalar(rectHeight)};
242*c8dee2aaSAndroid Build Coastguard Worker     svgCanvas->drawRect(bounds, *paint);
243*c8dee2aaSAndroid Build Coastguard Worker }
244*c8dee2aaSAndroid Build Coastguard Worker 
245*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_image_shader_norepeat,reporter)246*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_image_shader_norepeat, reporter) {
247*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
248*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
249*c8dee2aaSAndroid Build Coastguard Worker     int imageWidth = 3, imageHeight = 3;
250*c8dee2aaSAndroid Build Coastguard Worker     int rectWidth = 10, rectHeight = 10;
251*c8dee2aaSAndroid Build Coastguard Worker     ImageShaderTestSetup(&dom, &paint, imageWidth, imageHeight, rectWidth, rectHeight,
252*c8dee2aaSAndroid Build Coastguard Worker                          SkTileMode::kClamp, SkTileMode::kClamp);
253*c8dee2aaSAndroid Build Coastguard Worker 
254*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* root = dom.finishParsing();
255*c8dee2aaSAndroid Build Coastguard Worker 
256*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node *patternNode, *imageNode, *rectNode;
257*c8dee2aaSAndroid Build Coastguard Worker     bool structureAppropriate =
258*c8dee2aaSAndroid Build Coastguard Worker             FindImageShaderNodes(reporter, &dom, root, &patternNode, &imageNode, &rectNode);
259*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, structureAppropriate);
260*c8dee2aaSAndroid Build Coastguard Worker 
261*c8dee2aaSAndroid Build Coastguard Worker     // the image should always maintain its size.
262*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "width")) == imageWidth);
263*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "height")) == imageHeight);
264*c8dee2aaSAndroid Build Coastguard Worker 
265*c8dee2aaSAndroid Build Coastguard Worker     // making the pattern as large as the container prevents
266*c8dee2aaSAndroid Build Coastguard Worker     // it from repeating.
267*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strcmp(dom.findAttr(patternNode, "width"), "100%") == 0);
268*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strcmp(dom.findAttr(patternNode, "height"), "100%") == 0);
269*c8dee2aaSAndroid Build Coastguard Worker }
270*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_image_shader_tilex,reporter)271*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_image_shader_tilex, reporter) {
272*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
273*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
274*c8dee2aaSAndroid Build Coastguard Worker     int imageWidth = 3, imageHeight = 3;
275*c8dee2aaSAndroid Build Coastguard Worker     int rectWidth = 10, rectHeight = 10;
276*c8dee2aaSAndroid Build Coastguard Worker     ImageShaderTestSetup(&dom, &paint, imageWidth, imageHeight, rectWidth, rectHeight,
277*c8dee2aaSAndroid Build Coastguard Worker                          SkTileMode::kRepeat, SkTileMode::kClamp);
278*c8dee2aaSAndroid Build Coastguard Worker 
279*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* root = dom.finishParsing();
280*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* innerSvg = dom.getFirstChild(root, "svg");
281*c8dee2aaSAndroid Build Coastguard Worker     if (innerSvg == nullptr) {
282*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "inner svg element not found");
283*c8dee2aaSAndroid Build Coastguard Worker         return;
284*c8dee2aaSAndroid Build Coastguard Worker     }
285*c8dee2aaSAndroid Build Coastguard Worker 
286*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node *patternNode, *imageNode, *rectNode;
287*c8dee2aaSAndroid Build Coastguard Worker     bool structureAppropriate =
288*c8dee2aaSAndroid Build Coastguard Worker             FindImageShaderNodes(reporter, &dom, innerSvg, &patternNode, &imageNode, &rectNode);
289*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, structureAppropriate);
290*c8dee2aaSAndroid Build Coastguard Worker 
291*c8dee2aaSAndroid Build Coastguard Worker     // the imageNode should always maintain its size.
292*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "width")) == imageWidth);
293*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "height")) == imageHeight);
294*c8dee2aaSAndroid Build Coastguard Worker 
295*c8dee2aaSAndroid Build Coastguard Worker     // if the patternNode width matches the imageNode width,
296*c8dee2aaSAndroid Build Coastguard Worker     // it will repeat in along the x axis.
297*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, atoi(dom.findAttr(patternNode, "width")) == imageWidth);
298*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strcmp(dom.findAttr(patternNode, "height"), "100%") == 0);
299*c8dee2aaSAndroid Build Coastguard Worker }
300*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_image_shader_tiley,reporter)301*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_image_shader_tiley, reporter) {
302*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
303*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
304*c8dee2aaSAndroid Build Coastguard Worker     int imageNodeWidth = 3, imageNodeHeight = 3;
305*c8dee2aaSAndroid Build Coastguard Worker     int rectNodeWidth = 10, rectNodeHeight = 10;
306*c8dee2aaSAndroid Build Coastguard Worker     ImageShaderTestSetup(&dom, &paint, imageNodeWidth, imageNodeHeight, rectNodeWidth,
307*c8dee2aaSAndroid Build Coastguard Worker                          rectNodeHeight, SkTileMode::kClamp, SkTileMode::kRepeat);
308*c8dee2aaSAndroid Build Coastguard Worker 
309*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* root = dom.finishParsing();
310*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* innerSvg = dom.getFirstChild(root, "svg");
311*c8dee2aaSAndroid Build Coastguard Worker     if (innerSvg == nullptr) {
312*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "inner svg element not found");
313*c8dee2aaSAndroid Build Coastguard Worker         return;
314*c8dee2aaSAndroid Build Coastguard Worker     }
315*c8dee2aaSAndroid Build Coastguard Worker 
316*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node *patternNode, *imageNode, *rectNode;
317*c8dee2aaSAndroid Build Coastguard Worker     bool structureAppropriate =
318*c8dee2aaSAndroid Build Coastguard Worker             FindImageShaderNodes(reporter, &dom, innerSvg, &patternNode, &imageNode, &rectNode);
319*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, structureAppropriate);
320*c8dee2aaSAndroid Build Coastguard Worker 
321*c8dee2aaSAndroid Build Coastguard Worker     // the imageNode should always maintain its size.
322*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "width")) == imageNodeWidth);
323*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "height")) == imageNodeHeight);
324*c8dee2aaSAndroid Build Coastguard Worker 
325*c8dee2aaSAndroid Build Coastguard Worker     // making the patternNode as large as the container prevents
326*c8dee2aaSAndroid Build Coastguard Worker     // it from repeating.
327*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strcmp(dom.findAttr(patternNode, "width"), "100%") == 0);
328*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, atoi(dom.findAttr(patternNode, "height")) == imageNodeHeight);
329*c8dee2aaSAndroid Build Coastguard Worker }
330*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_image_shader_tileboth,reporter)331*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_image_shader_tileboth, reporter) {
332*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
333*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
334*c8dee2aaSAndroid Build Coastguard Worker     int imageWidth = 3, imageHeight = 3;
335*c8dee2aaSAndroid Build Coastguard Worker     int rectWidth = 10, rectHeight = 10;
336*c8dee2aaSAndroid Build Coastguard Worker     ImageShaderTestSetup(&dom, &paint, imageWidth, imageHeight, rectWidth, rectHeight,
337*c8dee2aaSAndroid Build Coastguard Worker                          SkTileMode::kRepeat, SkTileMode::kRepeat);
338*c8dee2aaSAndroid Build Coastguard Worker 
339*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* root = dom.finishParsing();
340*c8dee2aaSAndroid Build Coastguard Worker 
341*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node *patternNode, *imageNode, *rectNode;
342*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* innerSvg = dom.getFirstChild(root, "svg");
343*c8dee2aaSAndroid Build Coastguard Worker     if (innerSvg == nullptr) {
344*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "inner svg element not found");
345*c8dee2aaSAndroid Build Coastguard Worker         return;
346*c8dee2aaSAndroid Build Coastguard Worker     }
347*c8dee2aaSAndroid Build Coastguard Worker     bool structureAppropriate =
348*c8dee2aaSAndroid Build Coastguard Worker             FindImageShaderNodes(reporter, &dom, innerSvg, &patternNode, &imageNode, &rectNode);
349*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, structureAppropriate);
350*c8dee2aaSAndroid Build Coastguard Worker 
351*c8dee2aaSAndroid Build Coastguard Worker     // the imageNode should always maintain its size.
352*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "width")) == imageWidth);
353*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "height")) == imageHeight);
354*c8dee2aaSAndroid Build Coastguard Worker 
355*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, atoi(dom.findAttr(patternNode, "width")) == imageWidth);
356*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, atoi(dom.findAttr(patternNode, "height")) == imageHeight);
357*c8dee2aaSAndroid Build Coastguard Worker }
358*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_ColorFilters,reporter)359*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_ColorFilters, reporter) {
360*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
361*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
362*c8dee2aaSAndroid Build Coastguard Worker     paint.setColorFilter(SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcIn));
363*c8dee2aaSAndroid Build Coastguard Worker     {
364*c8dee2aaSAndroid Build Coastguard Worker         auto svgCanvas = MakeDOMCanvas(&dom);
365*c8dee2aaSAndroid Build Coastguard Worker         SkRect bounds{0, 0, SkIntToScalar(100), SkIntToScalar(100)};
366*c8dee2aaSAndroid Build Coastguard Worker         svgCanvas->drawRect(bounds, paint);
367*c8dee2aaSAndroid Build Coastguard Worker     }
368*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* rootElement = dom.finishParsing();
369*c8dee2aaSAndroid Build Coastguard Worker     ABORT_TEST(reporter, !rootElement, "root element not found");
370*c8dee2aaSAndroid Build Coastguard Worker 
371*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* filterElement = dom.getFirstChild(rootElement, "filter");
372*c8dee2aaSAndroid Build Coastguard Worker     ABORT_TEST(reporter, !filterElement, "filter element not found");
373*c8dee2aaSAndroid Build Coastguard Worker 
374*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* floodElement = dom.getFirstChild(filterElement, "feFlood");
375*c8dee2aaSAndroid Build Coastguard Worker     ABORT_TEST(reporter, !floodElement, "feFlood element not found");
376*c8dee2aaSAndroid Build Coastguard Worker 
377*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* compositeElement = dom.getFirstChild(filterElement, "feComposite");
378*c8dee2aaSAndroid Build Coastguard Worker     ABORT_TEST(reporter, !compositeElement, "feComposite element not found");
379*c8dee2aaSAndroid Build Coastguard Worker 
380*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strcmp(dom.findAttr(filterElement, "width"), "100%") == 0);
381*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strcmp(dom.findAttr(filterElement, "height"), "100%") == 0);
382*c8dee2aaSAndroid Build Coastguard Worker 
383*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter,
384*c8dee2aaSAndroid Build Coastguard Worker                     strcmp(dom.findAttr(floodElement, "flood-color"), "red") == 0);
385*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, atoi(dom.findAttr(floodElement, "flood-opacity")) == 1);
386*c8dee2aaSAndroid Build Coastguard Worker 
387*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strcmp(dom.findAttr(compositeElement, "in"), "flood") == 0);
388*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strcmp(dom.findAttr(compositeElement, "operator"), "in") == 0);
389*c8dee2aaSAndroid Build Coastguard Worker }
390*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_textpath,reporter)391*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_textpath, reporter) {
392*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
393*c8dee2aaSAndroid Build Coastguard Worker     SkFont font = ToolUtils::DefaultPortableFont();
394*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
395*c8dee2aaSAndroid Build Coastguard Worker 
396*c8dee2aaSAndroid Build Coastguard Worker     auto check_text = [&](uint32_t flags, bool expect_path) {
397*c8dee2aaSAndroid Build Coastguard Worker         // By default, we emit <text> nodes.
398*c8dee2aaSAndroid Build Coastguard Worker         {
399*c8dee2aaSAndroid Build Coastguard Worker             auto svgCanvas = MakeDOMCanvas(&dom, flags);
400*c8dee2aaSAndroid Build Coastguard Worker             svgCanvas->drawString("foo", 100, 100, font, paint);
401*c8dee2aaSAndroid Build Coastguard Worker         }
402*c8dee2aaSAndroid Build Coastguard Worker         const auto* rootElement = dom.finishParsing();
403*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, rootElement, "root element not found");
404*c8dee2aaSAndroid Build Coastguard Worker         const auto* textElement = dom.getFirstChild(rootElement, "text");
405*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !!textElement == !expect_path, "unexpected text element");
406*c8dee2aaSAndroid Build Coastguard Worker         const auto* pathElement = dom.getFirstChild(rootElement, "path");
407*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !!pathElement == expect_path, "unexpected path element");
408*c8dee2aaSAndroid Build Coastguard Worker     };
409*c8dee2aaSAndroid Build Coastguard Worker 
410*c8dee2aaSAndroid Build Coastguard Worker     // By default, we emit <text> nodes.
411*c8dee2aaSAndroid Build Coastguard Worker     check_text(0, /*expect_path=*/false);
412*c8dee2aaSAndroid Build Coastguard Worker 
413*c8dee2aaSAndroid Build Coastguard Worker     // With kConvertTextToPaths_Flag, we emit <path> nodes.
414*c8dee2aaSAndroid Build Coastguard Worker     check_text(SkSVGCanvas::kConvertTextToPaths_Flag, /*expect_path=*/true);
415*c8dee2aaSAndroid Build Coastguard Worker 
416*c8dee2aaSAndroid Build Coastguard Worker     // We also use paths in the presence of path effects.
417*c8dee2aaSAndroid Build Coastguard Worker     SkScalar intervals[] = {10, 5};
418*c8dee2aaSAndroid Build Coastguard Worker     paint.setPathEffect(SkDashPathEffect::Make(intervals, std::size(intervals), 0));
419*c8dee2aaSAndroid Build Coastguard Worker     check_text(0, /*expect_path=*/true);
420*c8dee2aaSAndroid Build Coastguard Worker }
421*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_fill_stroke,reporter)422*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_fill_stroke, reporter) {
423*c8dee2aaSAndroid Build Coastguard Worker     struct {
424*c8dee2aaSAndroid Build Coastguard Worker         SkColor        color;
425*c8dee2aaSAndroid Build Coastguard Worker         SkPaint::Style style;
426*c8dee2aaSAndroid Build Coastguard Worker         const char*    expected_fill;
427*c8dee2aaSAndroid Build Coastguard Worker         const char*    expected_stroke;
428*c8dee2aaSAndroid Build Coastguard Worker     } gTests[] = {
429*c8dee2aaSAndroid Build Coastguard Worker         { SK_ColorBLACK, SkPaint::kFill_Style  , nullptr, nullptr },
430*c8dee2aaSAndroid Build Coastguard Worker         { SK_ColorBLACK, SkPaint::kStroke_Style, "none" , "black" },
431*c8dee2aaSAndroid Build Coastguard Worker         { SK_ColorRED  , SkPaint::kFill_Style  , "red"  , nullptr },
432*c8dee2aaSAndroid Build Coastguard Worker         { SK_ColorRED  , SkPaint::kStroke_Style, "none" , "red"   },
433*c8dee2aaSAndroid Build Coastguard Worker     };
434*c8dee2aaSAndroid Build Coastguard Worker 
435*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& tst : gTests) {
436*c8dee2aaSAndroid Build Coastguard Worker         SkPaint p;
437*c8dee2aaSAndroid Build Coastguard Worker         p.setColor(tst.color);
438*c8dee2aaSAndroid Build Coastguard Worker         p.setStyle(tst.style);
439*c8dee2aaSAndroid Build Coastguard Worker 
440*c8dee2aaSAndroid Build Coastguard Worker         SkDOM dom;
441*c8dee2aaSAndroid Build Coastguard Worker         {
442*c8dee2aaSAndroid Build Coastguard Worker             MakeDOMCanvas(&dom)->drawRect(SkRect::MakeWH(100, 100), p);
443*c8dee2aaSAndroid Build Coastguard Worker         }
444*c8dee2aaSAndroid Build Coastguard Worker 
445*c8dee2aaSAndroid Build Coastguard Worker         const auto* root = dom.finishParsing();
446*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, root, "root element not found");
447*c8dee2aaSAndroid Build Coastguard Worker         const auto* rect = dom.getFirstChild(root, "rect");
448*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, rect, "rect element not found");
449*c8dee2aaSAndroid Build Coastguard Worker         const auto* fill = dom.findAttr(rect, "fill");
450*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !!fill == !!tst.expected_fill);
451*c8dee2aaSAndroid Build Coastguard Worker         if (fill) {
452*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, strcmp(fill, tst.expected_fill) == 0);
453*c8dee2aaSAndroid Build Coastguard Worker         }
454*c8dee2aaSAndroid Build Coastguard Worker         const auto* stroke = dom.findAttr(rect, "stroke");
455*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !!stroke == !!tst.expected_stroke);
456*c8dee2aaSAndroid Build Coastguard Worker         if (stroke) {
457*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, strcmp(stroke, tst.expected_stroke) == 0);
458*c8dee2aaSAndroid Build Coastguard Worker         }
459*c8dee2aaSAndroid Build Coastguard Worker     }
460*c8dee2aaSAndroid Build Coastguard Worker }
461*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_fill_opacity_black_fill,reporter)462*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_fill_opacity_black_fill, reporter) {
463*c8dee2aaSAndroid Build Coastguard Worker     struct {
464*c8dee2aaSAndroid Build Coastguard Worker         SkColor     color;
465*c8dee2aaSAndroid Build Coastguard Worker         const char* expected_fill_opacity;
466*c8dee2aaSAndroid Build Coastguard Worker     } gTests[] = {
467*c8dee2aaSAndroid Build Coastguard Worker         // Semi-transparent black
468*c8dee2aaSAndroid Build Coastguard Worker         {  SkColorSetARGB(0x33, 0x00, 0x00, 0x00), "0.2" },
469*c8dee2aaSAndroid Build Coastguard Worker         // Opaque black
470*c8dee2aaSAndroid Build Coastguard Worker         {  SkColorSetARGB(0xFF, 0x00, 0x00, 0x00), nullptr },
471*c8dee2aaSAndroid Build Coastguard Worker     };
472*c8dee2aaSAndroid Build Coastguard Worker 
473*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& tst : gTests) {
474*c8dee2aaSAndroid Build Coastguard Worker         SkPaint p;
475*c8dee2aaSAndroid Build Coastguard Worker         p.setColor(tst.color);
476*c8dee2aaSAndroid Build Coastguard Worker         p.setStyle(SkPaint::kFill_Style);
477*c8dee2aaSAndroid Build Coastguard Worker 
478*c8dee2aaSAndroid Build Coastguard Worker         SkDOM dom;
479*c8dee2aaSAndroid Build Coastguard Worker         {
480*c8dee2aaSAndroid Build Coastguard Worker             auto svgCanvas = MakeDOMCanvas(&dom);
481*c8dee2aaSAndroid Build Coastguard Worker             SkRect bounds{0, 0, SkIntToScalar(100), SkIntToScalar(100)};
482*c8dee2aaSAndroid Build Coastguard Worker             svgCanvas->drawRect(bounds, p);
483*c8dee2aaSAndroid Build Coastguard Worker         }
484*c8dee2aaSAndroid Build Coastguard Worker 
485*c8dee2aaSAndroid Build Coastguard Worker         const SkDOM::Node* rootElement = dom.finishParsing();
486*c8dee2aaSAndroid Build Coastguard Worker         ABORT_TEST(reporter, !rootElement, "root element not found");
487*c8dee2aaSAndroid Build Coastguard Worker 
488*c8dee2aaSAndroid Build Coastguard Worker         const SkDOM::Node* rectElement = dom.getFirstChild(rootElement, "rect");
489*c8dee2aaSAndroid Build Coastguard Worker         ABORT_TEST(reporter, !rectElement, "rect element not found");
490*c8dee2aaSAndroid Build Coastguard Worker         const auto* fill_opacity = dom.findAttr(rectElement, "fill-opacity");
491*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !!fill_opacity == !!tst.expected_fill_opacity);
492*c8dee2aaSAndroid Build Coastguard Worker         if (fill_opacity) {
493*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, strcmp(fill_opacity, tst.expected_fill_opacity) == 0);
494*c8dee2aaSAndroid Build Coastguard Worker         }
495*c8dee2aaSAndroid Build Coastguard Worker     }
496*c8dee2aaSAndroid Build Coastguard Worker }
497*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_fill_rect_hex,reporter)498*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_fill_rect_hex, reporter) {
499*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
500*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
501*c8dee2aaSAndroid Build Coastguard Worker     paint.setColor(SK_ColorBLUE);
502*c8dee2aaSAndroid Build Coastguard Worker     {
503*c8dee2aaSAndroid Build Coastguard Worker         auto svgCanvas = MakeDOMCanvas(&dom);
504*c8dee2aaSAndroid Build Coastguard Worker         SkRect bounds{0, 0, SkIntToScalar(100), SkIntToScalar(100)};
505*c8dee2aaSAndroid Build Coastguard Worker         svgCanvas->drawRect(bounds, paint);
506*c8dee2aaSAndroid Build Coastguard Worker     }
507*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* rootElement = dom.finishParsing();
508*c8dee2aaSAndroid Build Coastguard Worker     ABORT_TEST(reporter, !rootElement, "root element not found");
509*c8dee2aaSAndroid Build Coastguard Worker 
510*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* rectElement = dom.getFirstChild(rootElement, "rect");
511*c8dee2aaSAndroid Build Coastguard Worker     ABORT_TEST(reporter, !rectElement, "rect element not found");
512*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strcmp(dom.findAttr(rectElement, "fill"), "blue") == 0);
513*c8dee2aaSAndroid Build Coastguard Worker }
514*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_fill_rect_custom_hex,reporter)515*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_fill_rect_custom_hex, reporter) {
516*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
517*c8dee2aaSAndroid Build Coastguard Worker     {
518*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
519*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(0xFFAABCDE);
520*c8dee2aaSAndroid Build Coastguard Worker         auto svgCanvas = MakeDOMCanvas(&dom);
521*c8dee2aaSAndroid Build Coastguard Worker         SkRect bounds{0, 0, SkIntToScalar(100), SkIntToScalar(100)};
522*c8dee2aaSAndroid Build Coastguard Worker         svgCanvas->drawRect(bounds, paint);
523*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(0xFFAABBCC);
524*c8dee2aaSAndroid Build Coastguard Worker         svgCanvas->drawRect(bounds, paint);
525*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(0xFFAA1123);
526*c8dee2aaSAndroid Build Coastguard Worker         svgCanvas->drawRect(bounds, paint);
527*c8dee2aaSAndroid Build Coastguard Worker     }
528*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* rootElement = dom.finishParsing();
529*c8dee2aaSAndroid Build Coastguard Worker     ABORT_TEST(reporter, !rootElement, "root element not found");
530*c8dee2aaSAndroid Build Coastguard Worker 
531*c8dee2aaSAndroid Build Coastguard Worker     // Test 0xAABCDE filled rect.
532*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* rectElement = dom.getFirstChild(rootElement, "rect");
533*c8dee2aaSAndroid Build Coastguard Worker     ABORT_TEST(reporter, !rectElement, "rect element not found");
534*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strcmp(dom.findAttr(rectElement, "fill"), "#AABCDE") == 0);
535*c8dee2aaSAndroid Build Coastguard Worker 
536*c8dee2aaSAndroid Build Coastguard Worker     // Test 0xAABBCC filled rect.
537*c8dee2aaSAndroid Build Coastguard Worker     rectElement = dom.getNextSibling(rectElement, "rect");
538*c8dee2aaSAndroid Build Coastguard Worker     ABORT_TEST(reporter, !rectElement, "rect element not found");
539*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strcmp(dom.findAttr(rectElement, "fill"), "#ABC") == 0);
540*c8dee2aaSAndroid Build Coastguard Worker 
541*c8dee2aaSAndroid Build Coastguard Worker     // Test 0xFFAA1123 filled rect. Make sure it does not turn into #A123.
542*c8dee2aaSAndroid Build Coastguard Worker     rectElement = dom.getNextSibling(rectElement, "rect");
543*c8dee2aaSAndroid Build Coastguard Worker     ABORT_TEST(reporter, !rectElement, "rect element not found");
544*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strcmp(dom.findAttr(rectElement, "fill"), "#AA1123") == 0);
545*c8dee2aaSAndroid Build Coastguard Worker }
546*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_fill_stroke_rect_hex,reporter)547*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_fill_stroke_rect_hex, reporter) {
548*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
549*c8dee2aaSAndroid Build Coastguard Worker     {
550*c8dee2aaSAndroid Build Coastguard Worker         auto svgCanvas = MakeDOMCanvas(&dom);
551*c8dee2aaSAndroid Build Coastguard Worker         SkRect bounds{0, 0, SkIntToScalar(100), SkIntToScalar(100)};
552*c8dee2aaSAndroid Build Coastguard Worker 
553*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
554*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(0xFF00BBAC);
555*c8dee2aaSAndroid Build Coastguard Worker         svgCanvas->drawRect(bounds, paint);
556*c8dee2aaSAndroid Build Coastguard Worker         paint.setStyle(SkPaint::kStroke_Style);
557*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(0xFF123456);
558*c8dee2aaSAndroid Build Coastguard Worker         paint.setStrokeWidth(1);
559*c8dee2aaSAndroid Build Coastguard Worker         svgCanvas->drawRect(bounds, paint);
560*c8dee2aaSAndroid Build Coastguard Worker     }
561*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* rootElement = dom.finishParsing();
562*c8dee2aaSAndroid Build Coastguard Worker     ABORT_TEST(reporter, !rootElement, "root element not found");
563*c8dee2aaSAndroid Build Coastguard Worker 
564*c8dee2aaSAndroid Build Coastguard Worker     const SkDOM::Node* rectNode = dom.getFirstChild(rootElement, "rect");
565*c8dee2aaSAndroid Build Coastguard Worker     ABORT_TEST(reporter, !rectNode, "rect element not found");
566*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strcmp(dom.findAttr(rectNode, "fill"), "#00BBAC") == 0);
567*c8dee2aaSAndroid Build Coastguard Worker 
568*c8dee2aaSAndroid Build Coastguard Worker     rectNode = dom.getNextSibling(rectNode, "rect");
569*c8dee2aaSAndroid Build Coastguard Worker     ABORT_TEST(reporter, !rectNode, "rect element not found");
570*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strcmp(dom.findAttr(rectNode, "stroke"), "#123456") == 0);
571*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strcmp(dom.findAttr(rectNode, "stroke-width"), "1") == 0);
572*c8dee2aaSAndroid Build Coastguard Worker }
573*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_rect_with_path_effect,reporter)574*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_rect_with_path_effect, reporter) {
575*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
576*c8dee2aaSAndroid Build Coastguard Worker 
577*c8dee2aaSAndroid Build Coastguard Worker     SkScalar intervals[] = {0, 20};
578*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkPathEffect> pathEffect = SkDashPathEffect::Make(intervals, 2, 0);
579*c8dee2aaSAndroid Build Coastguard Worker 
580*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
581*c8dee2aaSAndroid Build Coastguard Worker     paint.setPathEffect(pathEffect);
582*c8dee2aaSAndroid Build Coastguard Worker 
583*c8dee2aaSAndroid Build Coastguard Worker     {
584*c8dee2aaSAndroid Build Coastguard Worker         auto svgCanvas = MakeDOMCanvas(&dom);
585*c8dee2aaSAndroid Build Coastguard Worker         svgCanvas->drawRect(SkRect::MakeXYWH(0, 0, 100, 100), paint);
586*c8dee2aaSAndroid Build Coastguard Worker     }
587*c8dee2aaSAndroid Build Coastguard Worker 
588*c8dee2aaSAndroid Build Coastguard Worker     const auto* rootElement = dom.finishParsing();
589*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rootElement, "root element not found");
590*c8dee2aaSAndroid Build Coastguard Worker     const auto* pathElement = dom.getFirstChild(rootElement, "path");
591*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pathElement, "path element not found");
592*c8dee2aaSAndroid Build Coastguard Worker }
593*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_rrect_with_path_effect,reporter)594*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_rrect_with_path_effect, reporter) {
595*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
596*c8dee2aaSAndroid Build Coastguard Worker 
597*c8dee2aaSAndroid Build Coastguard Worker     SkScalar intervals[] = {0, 20};
598*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkPathEffect> pathEffect = SkDashPathEffect::Make(intervals, 2, 0);
599*c8dee2aaSAndroid Build Coastguard Worker 
600*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
601*c8dee2aaSAndroid Build Coastguard Worker     paint.setPathEffect(pathEffect);
602*c8dee2aaSAndroid Build Coastguard Worker 
603*c8dee2aaSAndroid Build Coastguard Worker     {
604*c8dee2aaSAndroid Build Coastguard Worker         auto svgCanvas = MakeDOMCanvas(&dom);
605*c8dee2aaSAndroid Build Coastguard Worker         svgCanvas->drawRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(0, 0, 100, 100), 10, 10), paint);
606*c8dee2aaSAndroid Build Coastguard Worker     }
607*c8dee2aaSAndroid Build Coastguard Worker 
608*c8dee2aaSAndroid Build Coastguard Worker     const auto* rootElement = dom.finishParsing();
609*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rootElement, "root element not found");
610*c8dee2aaSAndroid Build Coastguard Worker     const auto* pathElement = dom.getFirstChild(rootElement, "path");
611*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pathElement, "path element not found");
612*c8dee2aaSAndroid Build Coastguard Worker }
613*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_oval_with_path_effect,reporter)614*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_oval_with_path_effect, reporter) {
615*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
616*c8dee2aaSAndroid Build Coastguard Worker 
617*c8dee2aaSAndroid Build Coastguard Worker     SkScalar intervals[] = {0, 20};
618*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkPathEffect> pathEffect = SkDashPathEffect::Make(intervals, 2, 0);
619*c8dee2aaSAndroid Build Coastguard Worker 
620*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
621*c8dee2aaSAndroid Build Coastguard Worker     paint.setPathEffect(pathEffect);
622*c8dee2aaSAndroid Build Coastguard Worker 
623*c8dee2aaSAndroid Build Coastguard Worker     {
624*c8dee2aaSAndroid Build Coastguard Worker         auto svgCanvas = MakeDOMCanvas(&dom);
625*c8dee2aaSAndroid Build Coastguard Worker         svgCanvas->drawOval(SkRect::MakeXYWH(0, 0, 100, 100), paint);
626*c8dee2aaSAndroid Build Coastguard Worker     }
627*c8dee2aaSAndroid Build Coastguard Worker 
628*c8dee2aaSAndroid Build Coastguard Worker     const auto* rootElement = dom.finishParsing();
629*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rootElement, "root element not found");
630*c8dee2aaSAndroid Build Coastguard Worker     const auto* pathElement = dom.getFirstChild(rootElement, "path");
631*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pathElement, "path element not found");
632*c8dee2aaSAndroid Build Coastguard Worker }
633*c8dee2aaSAndroid Build Coastguard Worker 
634*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_path_effect,reporter)635*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_path_effect, reporter) {
636*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
637*c8dee2aaSAndroid Build Coastguard Worker 
638*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
639*c8dee2aaSAndroid Build Coastguard Worker     paint.setColor(SK_ColorRED);
640*c8dee2aaSAndroid Build Coastguard Worker     paint.setStyle(SkPaint::kStroke_Style);
641*c8dee2aaSAndroid Build Coastguard Worker     paint.setStrokeWidth(10);
642*c8dee2aaSAndroid Build Coastguard Worker     paint.setStrokeCap(SkPaint::kRound_Cap);
643*c8dee2aaSAndroid Build Coastguard Worker 
644*c8dee2aaSAndroid Build Coastguard Worker     // Produces a line of three red dots.
645*c8dee2aaSAndroid Build Coastguard Worker     SkScalar intervals[] = {0, 20};
646*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkPathEffect> pathEffect = SkDashPathEffect::Make(intervals, 2, 0);
647*c8dee2aaSAndroid Build Coastguard Worker     paint.setPathEffect(pathEffect);
648*c8dee2aaSAndroid Build Coastguard Worker     SkPoint points[] = {{50, 15}, {100, 15}, {150, 15} };
649*c8dee2aaSAndroid Build Coastguard Worker     {
650*c8dee2aaSAndroid Build Coastguard Worker         auto svgCanvas = MakeDOMCanvas(&dom);
651*c8dee2aaSAndroid Build Coastguard Worker         svgCanvas->drawPoints(SkCanvas::kLines_PointMode, 3, points, paint);
652*c8dee2aaSAndroid Build Coastguard Worker     }
653*c8dee2aaSAndroid Build Coastguard Worker     const auto* rootElement = dom.finishParsing();
654*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rootElement, "root element not found");
655*c8dee2aaSAndroid Build Coastguard Worker     const auto* pathElement = dom.getFirstChild(rootElement, "path");
656*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pathElement, "path element not found");
657*c8dee2aaSAndroid Build Coastguard Worker 
658*c8dee2aaSAndroid Build Coastguard Worker     // The SVG path to draw the three dots is a complex list of instructions.
659*c8dee2aaSAndroid Build Coastguard Worker     // To avoid test brittleness, we don't attempt to match the entire path.
660*c8dee2aaSAndroid Build Coastguard Worker     // Instead, we simply confirm there are three (M)ove instructions, one per
661*c8dee2aaSAndroid Build Coastguard Worker     // dot.  If path effects were not being honored, we would expect only one
662*c8dee2aaSAndroid Build Coastguard Worker     // Move instruction, to the starting position, before drawing a continuous
663*c8dee2aaSAndroid Build Coastguard Worker     // straight line.
664*c8dee2aaSAndroid Build Coastguard Worker     const auto* d = dom.findAttr(pathElement, "d");
665*c8dee2aaSAndroid Build Coastguard Worker     int mCount = 0;
666*c8dee2aaSAndroid Build Coastguard Worker     const char* pos;
667*c8dee2aaSAndroid Build Coastguard Worker     for (pos = d; *pos != '\0'; pos++) {
668*c8dee2aaSAndroid Build Coastguard Worker       mCount += (*pos == 'M') ? 1 : 0;
669*c8dee2aaSAndroid Build Coastguard Worker     }
670*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, mCount == 3);
671*c8dee2aaSAndroid Build Coastguard Worker }
672*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_relative_path_encoding,reporter)673*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_relative_path_encoding, reporter) {
674*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
675*c8dee2aaSAndroid Build Coastguard Worker     {
676*c8dee2aaSAndroid Build Coastguard Worker         auto svgCanvas = MakeDOMCanvas(&dom, SkSVGCanvas::kRelativePathEncoding_Flag);
677*c8dee2aaSAndroid Build Coastguard Worker         SkPath path;
678*c8dee2aaSAndroid Build Coastguard Worker         path.moveTo(100, 50);
679*c8dee2aaSAndroid Build Coastguard Worker         path.lineTo(200, 50);
680*c8dee2aaSAndroid Build Coastguard Worker         path.lineTo(200, 150);
681*c8dee2aaSAndroid Build Coastguard Worker         path.close();
682*c8dee2aaSAndroid Build Coastguard Worker 
683*c8dee2aaSAndroid Build Coastguard Worker         svgCanvas->drawPath(path, SkPaint());
684*c8dee2aaSAndroid Build Coastguard Worker     }
685*c8dee2aaSAndroid Build Coastguard Worker 
686*c8dee2aaSAndroid Build Coastguard Worker     const auto* rootElement = dom.finishParsing();
687*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rootElement, "root element not found");
688*c8dee2aaSAndroid Build Coastguard Worker     const auto* pathElement = dom.getFirstChild(rootElement, "path");
689*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pathElement, "path element not found");
690*c8dee2aaSAndroid Build Coastguard Worker     const auto* d = dom.findAttr(pathElement, "d");
691*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !strcmp(d, "m100 50l100 0l0 100l-100 -100Z"));
692*c8dee2aaSAndroid Build Coastguard Worker }
693*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_color_shader,reporter)694*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_color_shader, reporter) {
695*c8dee2aaSAndroid Build Coastguard Worker     SkDOM dom;
696*c8dee2aaSAndroid Build Coastguard Worker     {
697*c8dee2aaSAndroid Build Coastguard Worker         auto svgCanvas = MakeDOMCanvas(&dom);
698*c8dee2aaSAndroid Build Coastguard Worker 
699*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
700*c8dee2aaSAndroid Build Coastguard Worker         paint.setShader(SkShaders::Color(0xffffff00));
701*c8dee2aaSAndroid Build Coastguard Worker 
702*c8dee2aaSAndroid Build Coastguard Worker         svgCanvas->drawCircle(100, 100, 100, paint);
703*c8dee2aaSAndroid Build Coastguard Worker     }
704*c8dee2aaSAndroid Build Coastguard Worker 
705*c8dee2aaSAndroid Build Coastguard Worker     const auto* rootElement = dom.finishParsing();
706*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, rootElement, "root element not found");
707*c8dee2aaSAndroid Build Coastguard Worker     const auto* ellipseElement = dom.getFirstChild(rootElement, "ellipse");
708*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, ellipseElement, "ellipse element not found");
709*c8dee2aaSAndroid Build Coastguard Worker     const auto* fill = dom.findAttr(ellipseElement, "fill");
710*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, fill, "fill attribute not found");
711*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !strcmp(fill, "yellow"));
712*c8dee2aaSAndroid Build Coastguard Worker }
713*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SVGDevice_parse_minmax,reporter)714*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SVGDevice_parse_minmax, reporter) {
715*c8dee2aaSAndroid Build Coastguard Worker     auto check = [&](int64_t n, bool expected) {
716*c8dee2aaSAndroid Build Coastguard Worker         const auto str = std::to_string(n);
717*c8dee2aaSAndroid Build Coastguard Worker 
718*c8dee2aaSAndroid Build Coastguard Worker         int val;
719*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, SkToBool(SkParse::FindS32(str.c_str(), &val)) == expected);
720*c8dee2aaSAndroid Build Coastguard Worker         if (expected) {
721*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, val == n);
722*c8dee2aaSAndroid Build Coastguard Worker         }
723*c8dee2aaSAndroid Build Coastguard Worker     };
724*c8dee2aaSAndroid Build Coastguard Worker 
725*c8dee2aaSAndroid Build Coastguard Worker     check(std::numeric_limits<int>::max(), true);
726*c8dee2aaSAndroid Build Coastguard Worker     check(std::numeric_limits<int>::min(), true);
727*c8dee2aaSAndroid Build Coastguard Worker     check(static_cast<int64_t>(std::numeric_limits<int>::max()) + 1, false);
728*c8dee2aaSAndroid Build Coastguard Worker     check(static_cast<int64_t>(std::numeric_limits<int>::min()) - 1, false);
729*c8dee2aaSAndroid Build Coastguard Worker }
730*c8dee2aaSAndroid Build Coastguard Worker 
731*c8dee2aaSAndroid Build Coastguard Worker #endif
732