aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests/SVGDeviceTest.cpp
diff options
context:
space:
mode:
authorGravatar Alexander Midlash <amidlash@amazon.com>2018-03-06 17:21:28 -0800
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-03-07 02:25:30 +0000
commit77e3afc908f5f1e79180beb558b163fcf1cdf8ac (patch)
treecee37923028b99c7a83c00a9eea9e7dda9d98b24 /tests/SVGDeviceTest.cpp
parentc5cf762177c5708a5efa39f95b086c751e03e2e4 (diff)
[SkSVGDevice] Add support for image shaders.
Below is an example of the generated svg for an image shader that repeats in the x direction only: <svg stroke="none" x="9" y="153" width="50" height="30"> <defs> <pattern id="pattern_1_19" patternUnits="userSpaceOnUse" patternContentUnits="userSpaceOnUse" width="31" height="100%" x="0" y="0"> <image id="img_2_19" x="0" y="0" width="31" height="30" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="data:image/png;base64,LONG_B64_STRING_HERE"></image> </pattern> </defs> <rect fill="url(#pattern_1_19)" stroke="none" x="0" y="0" width="100%" height="100%"></rect> </svg> Matching the height of the pattern with the height of the container prevents it from repeating in the y direction. R=fmalita@chromium.org Bug: skia::7681 Change-Id: I43e4f19acda4bd40c7a8b5259d67c26a108d6f67 Reviewed-on: https://skia-review.googlesource.com/111420 Commit-Queue: Florin Malita <fmalita@chromium.org> Reviewed-by: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'tests/SVGDeviceTest.cpp')
-rw-r--r--tests/SVGDeviceTest.cpp189
1 files changed, 184 insertions, 5 deletions
diff --git a/tests/SVGDeviceTest.cpp b/tests/SVGDeviceTest.cpp
index 7044559d83..bdd832c43b 100644
--- a/tests/SVGDeviceTest.cpp
+++ b/tests/SVGDeviceTest.cpp
@@ -5,23 +5,27 @@
* found in the LICENSE file.
*/
-#include "SkTypes.h"
-
-#ifdef SK_XML
+#include "SkBitmap.h"
#include "SkCanvas.h"
-#include "SkData.h"
#include "SkDOM.h"
+#include "SkData.h"
+#include "SkImage.h"
+#include "SkImageShader.h"
#include "SkParse.h"
-#include "SkStream.h"
#include "SkSVGCanvas.h"
+#include "SkShader.h"
+#include "SkStream.h"
#include "SkXMLWriter.h"
#include "Test.h"
#include <string.h>
+#ifdef SK_XML
+
namespace {
+
void check_text_node(skiatest::Reporter* reporter,
const SkDOM& dom,
const SkDOM::Node* root,
@@ -149,4 +153,179 @@ DEF_TEST(SVGDevice_whitespace_pos, reporter) {
}
}
+
+void SetImageShader(SkPaint* paint, int imageWidth, int imageHeight, SkShader::TileMode xTile,
+ SkShader::TileMode yTile) {
+ auto surface = SkSurface::MakeRasterN32Premul(imageWidth, imageHeight);
+ paint->setShader(SkImageShader::Make(surface->makeImageSnapshot(), xTile, yTile, nullptr));
+}
+
+// Attempt to find the three nodes on which we have expectations:
+// the pattern node, the image within that pattern, and the rect which
+// uses the pattern as a fill.
+// returns false if not all nodes are found.
+bool FindImageShaderNodes(skiatest::Reporter* reporter, const SkDOM* dom, const SkDOM::Node* root,
+ const SkDOM::Node** patternOut, const SkDOM::Node** imageOut,
+ const SkDOM::Node** rectOut) {
+ if (root == nullptr || dom == nullptr) {
+ ERRORF(reporter, "root element not found");
+ return false;
+ }
+
+
+ const SkDOM::Node* rect = dom->getFirstChild(root, "rect");
+ if (rect == nullptr) {
+ ERRORF(reporter, "rect not found");
+ return false;
+ }
+ *rectOut = rect;
+
+ const SkDOM::Node* defs = dom->getFirstChild(root, "defs");
+ if (defs == nullptr) {
+ ERRORF(reporter, "defs not found");
+ return false;
+ }
+
+ const SkDOM::Node* pattern = dom->getFirstChild(defs, "pattern");
+ if (pattern == nullptr) {
+ ERRORF(reporter, "pattern not found");
+ return false;
+ }
+ *patternOut = pattern;
+
+ const SkDOM::Node* image = dom->getFirstChild(pattern, "image");
+ if (image == nullptr) {
+ ERRORF(reporter, "image not found");
+ return false;
+ }
+ *imageOut = image;
+
+ return true;
+}
+
+void ImageShaderTestSetup(SkDOM* dom, SkPaint* paint, int imageWidth, int imageHeight,
+ int rectWidth, int rectHeight, SkShader::TileMode xTile,
+ SkShader::TileMode yTile) {
+ SetImageShader(paint, imageWidth, imageHeight, xTile, yTile);
+ SkXMLParserWriter writer(dom->beginParsing());
+ std::unique_ptr<SkCanvas> svgCanvas = SkSVGCanvas::Make(SkRect::MakeWH(100, 100), &writer);
+
+ SkRect bounds{0, 0, SkIntToScalar(rectWidth), SkIntToScalar(rectHeight)};
+ svgCanvas->drawRect(bounds, *paint);
+}
+
+
+DEF_TEST(SVGDevice_image_shader_norepeat, reporter) {
+ SkDOM dom;
+ SkPaint paint;
+ int imageWidth = 3, imageHeight = 3;
+ int rectWidth = 10, rectHeight = 10;
+ ImageShaderTestSetup(&dom, &paint, imageWidth, imageHeight, rectWidth, rectHeight,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+
+ const SkDOM::Node* root = dom.finishParsing();
+
+ const SkDOM::Node *patternNode, *imageNode, *rectNode;
+ bool structureAppropriate =
+ FindImageShaderNodes(reporter, &dom, root, &patternNode, &imageNode, &rectNode);
+ REPORTER_ASSERT(reporter, structureAppropriate);
+
+ // the image should always maintain its size.
+ REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "width")) == imageWidth);
+ REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "height")) == imageHeight);
+
+ // making the pattern as large as the container prevents
+ // it from repeating.
+ REPORTER_ASSERT(reporter, strcmp(dom.findAttr(patternNode, "width"), "100%") == 0);
+ REPORTER_ASSERT(reporter, strcmp(dom.findAttr(patternNode, "height"), "100%") == 0);
+}
+
+DEF_TEST(SVGDevice_image_shader_tilex, reporter) {
+ SkDOM dom;
+ SkPaint paint;
+ int imageWidth = 3, imageHeight = 3;
+ int rectWidth = 10, rectHeight = 10;
+ ImageShaderTestSetup(&dom, &paint, imageWidth, imageHeight, rectWidth, rectHeight,
+ SkShader::kRepeat_TileMode, SkShader::kClamp_TileMode);
+
+ const SkDOM::Node* root = dom.finishParsing();
+ const SkDOM::Node* innerSvg = dom.getFirstChild(root, "svg");
+ if (innerSvg == nullptr) {
+ ERRORF(reporter, "inner svg element not found");
+ return;
+ }
+
+ const SkDOM::Node *patternNode, *imageNode, *rectNode;
+ bool structureAppropriate =
+ FindImageShaderNodes(reporter, &dom, innerSvg, &patternNode, &imageNode, &rectNode);
+ REPORTER_ASSERT(reporter, structureAppropriate);
+
+ // the imageNode should always maintain its size.
+ REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "width")) == imageWidth);
+ REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "height")) == imageHeight);
+
+ // if the patternNode width matches the imageNode width,
+ // it will repeat in along the x axis.
+ REPORTER_ASSERT(reporter, atoi(dom.findAttr(patternNode, "width")) == imageWidth);
+ REPORTER_ASSERT(reporter, strcmp(dom.findAttr(patternNode, "height"), "100%") == 0);
+}
+
+DEF_TEST(SVGDevice_image_shader_tiley, reporter) {
+ SkDOM dom;
+ SkPaint paint;
+ int imageNodeWidth = 3, imageNodeHeight = 3;
+ int rectNodeWidth = 10, rectNodeHeight = 10;
+ ImageShaderTestSetup(&dom, &paint, imageNodeWidth, imageNodeHeight, rectNodeWidth,
+ rectNodeHeight, SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode);
+
+ const SkDOM::Node* root = dom.finishParsing();
+ const SkDOM::Node* innerSvg = dom.getFirstChild(root, "svg");
+ if (innerSvg == nullptr) {
+ ERRORF(reporter, "inner svg element not found");
+ return;
+ }
+
+ const SkDOM::Node *patternNode, *imageNode, *rectNode;
+ bool structureAppropriate =
+ FindImageShaderNodes(reporter, &dom, innerSvg, &patternNode, &imageNode, &rectNode);
+ REPORTER_ASSERT(reporter, structureAppropriate);
+
+ // the imageNode should always maintain its size.
+ REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "width")) == imageNodeWidth);
+ REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "height")) == imageNodeHeight);
+
+ // making the patternNode as large as the container prevents
+ // it from repeating.
+ REPORTER_ASSERT(reporter, strcmp(dom.findAttr(patternNode, "width"), "100%") == 0);
+ REPORTER_ASSERT(reporter, atoi(dom.findAttr(patternNode, "height")) == imageNodeHeight);
+}
+
+DEF_TEST(SVGDevice_image_shader_tileboth, reporter) {
+ SkDOM dom;
+ SkPaint paint;
+ int imageWidth = 3, imageHeight = 3;
+ int rectWidth = 10, rectHeight = 10;
+ ImageShaderTestSetup(&dom, &paint, imageWidth, imageHeight, rectWidth, rectHeight,
+ SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
+
+ const SkDOM::Node* root = dom.finishParsing();
+
+ const SkDOM::Node *patternNode, *imageNode, *rectNode;
+ const SkDOM::Node* innerSvg = dom.getFirstChild(root, "svg");
+ if (innerSvg == nullptr) {
+ ERRORF(reporter, "inner svg element not found");
+ return;
+ }
+ bool structureAppropriate =
+ FindImageShaderNodes(reporter, &dom, innerSvg, &patternNode, &imageNode, &rectNode);
+ REPORTER_ASSERT(reporter, structureAppropriate);
+
+ // the imageNode should always maintain its size.
+ REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "width")) == imageWidth);
+ REPORTER_ASSERT(reporter, atoi(dom.findAttr(imageNode, "height")) == imageHeight);
+
+ REPORTER_ASSERT(reporter, atoi(dom.findAttr(patternNode, "width")) == imageWidth);
+ REPORTER_ASSERT(reporter, atoi(dom.findAttr(patternNode, "height")) == imageHeight);
+}
+
#endif