[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/SkSVGNode.cpp b/modules/svg/src/SkSVGNode.cpp
index ae3aef2..9f3a3e6 100644
--- a/modules/svg/src/SkSVGNode.cpp
+++ b/modules/svg/src/SkSVGNode.cpp
@@ -122,3 +122,57 @@
#undef PARSE_AND_SET
}
+
+// https://www.w3.org/TR/SVG11/coords.html#PreserveAspectRatioAttribute
+SkMatrix SkSVGNode::ComputeViewboxMatrix(const SkRect& viewBox,
+ const SkRect& viewPort,
+ SkSVGPreserveAspectRatio par) {
+ SkASSERT(!viewBox.isEmpty());
+ SkASSERT(!viewPort.isEmpty());
+
+ auto compute_scale = [&]() -> SkV2 {
+ const auto sx = viewPort.width() / viewBox.width(),
+ sy = viewPort.height() / viewBox.height();
+
+ if (par.fAlign == SkSVGPreserveAspectRatio::kNone) {
+ // none -> anisotropic scaling, regardless of fScale
+ return {sx, sy};
+ }
+
+ // isotropic scaling
+ const auto s = par.fScale == SkSVGPreserveAspectRatio::kMeet
+ ? std::min(sx, sy)
+ : std::max(sx, sy);
+ return {s, s};
+ };
+
+ auto compute_trans = [&](const SkV2& scale) -> SkV2 {
+ static constexpr float gAlignCoeffs[] = {
+ 0.0f, // Min
+ 0.5f, // Mid
+ 1.0f // Max
+ };
+
+ const size_t x_coeff = par.fAlign >> 0 & 0x03,
+ y_coeff = par.fAlign >> 2 & 0x03;
+
+ SkASSERT(x_coeff < SK_ARRAY_COUNT(gAlignCoeffs) &&
+ y_coeff < SK_ARRAY_COUNT(gAlignCoeffs));
+
+ const auto tx = -viewBox.x() * scale.x,
+ ty = -viewBox.y() * scale.y,
+ dx = viewPort.width() - viewBox.width() * scale.x,
+ dy = viewPort.height() - viewBox.height() * scale.y;
+
+ return {
+ tx + dx * gAlignCoeffs[x_coeff],
+ ty + dy * gAlignCoeffs[y_coeff]
+ };
+ };
+
+ const auto s = compute_scale(),
+ t = compute_trans(s);
+
+ return SkMatrix::Translate(t.x, t.y) *
+ SkMatrix::Scale(s.x, s.y);
+}