diff options
author | Alexander Midlash <amidlash@amazon.com> | 2018-03-06 17:21:28 -0800 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-03-07 02:25:30 +0000 |
commit | 77e3afc908f5f1e79180beb558b163fcf1cdf8ac (patch) | |
tree | cee37923028b99c7a83c00a9eea9e7dda9d98b24 /tests/SVGDeviceTest.cpp | |
parent | c5cf762177c5708a5efa39f95b086c751e03e2e4 (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.cpp | 189 |
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 |