[svg] Support preserveAspectRatio for images
https://www.w3.org/TR/SVG11/struct.html#ImageElement
https://www.w3.org/TR/SVG11/coords.html#PreserveAspectRatioAttribute
We already had a function to compute the appropriate matrix, and since
we can share the functionality with other elements that establish a new
viewport (including svg, symbol, and a few others), this CL moves the
function to the SVG node base class.
Relevant test for images is struct-image-06.
Bug: skia:10842
Change-Id: I5d6261210d03959e28d0bd7189da7f4ea53abc03
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/366398
Commit-Queue: Tyler Denniston <tdenniston@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
diff --git a/modules/svg/src/SkSVGImage.cpp b/modules/svg/src/SkSVGImage.cpp
index d872378..6dec0e8 100644
--- a/modules/svg/src/SkSVGImage.cpp
+++ b/modules/svg/src/SkSVGImage.cpp
@@ -19,7 +19,9 @@
this->setY(SkSVGAttributeParser::parse<SkSVGLength>("y", n, v)) ||
this->setWidth(SkSVGAttributeParser::parse<SkSVGLength>("width", n, v)) ||
this->setHeight(SkSVGAttributeParser::parse<SkSVGLength>("height", n, v)) ||
- this->setHref(SkSVGAttributeParser::parse<SkSVGIRI>("xlink:href", n, v));
+ this->setHref(SkSVGAttributeParser::parse<SkSVGIRI>("xlink:href", n, v)) ||
+ this->setPreserveAspectRatio(SkSVGAttributeParser::parse<SkSVGPreserveAspectRatio>(
+ "preserveAspectRatio", n, v));
}
bool SkSVGImage::onPrepareToRender(SkSVGRenderContext* ctx) const {
@@ -52,6 +54,12 @@
return imageAsset ? imageAsset->getFrameData(0).image : nullptr;
}
+SkRect SkSVGImage::resolveImageRect(const SkRect& viewBox, const SkRect& viewPort) const {
+ const SkMatrix m = ComputeViewboxMatrix(viewBox, viewPort, fPreserveAspectRatio);
+ // Map and place at x, y specified by image attributes
+ return m.mapRect(viewBox).makeOffset(viewPort.fLeft, viewPort.fTop);
+}
+
void SkSVGImage::onRender(const SkSVGRenderContext& ctx) const {
const auto& rp = ctx.resourceProvider();
SkASSERT(rp);
@@ -63,10 +71,15 @@
return;
}
- // TODO: preserveAspectRatio support
+ // Per spec: x, w, width, height attributes establish the new viewport.
const SkSVGLengthContext& lctx = ctx.lengthContext();
- const SkRect rect = lctx.resolveRect(fX, fY, fWidth, fHeight);
- ctx.canvas()->drawImageRect(image, rect, SkSamplingOptions(SkFilterMode::kLinear));
+ const SkRect viewPort = lctx.resolveRect(fX, fY, fWidth, fHeight);
+ // Per spec: raster content has implicit viewbox of '0 0 width height'.
+ const SkRect viewBox = SkRect::Make(image->bounds());
+
+ ctx.canvas()->drawImageRect(image,
+ this->resolveImageRect(viewBox, viewPort),
+ SkSamplingOptions(SkFilterMode::kLinear));
}
SkPath SkSVGImage::onAsPath(const SkSVGRenderContext&) const { return {}; }