[svg] Fix <use> bounds calculation
Previously we were using fX and fY as the top left of the returned
bounds. We need instead to offset the referenced node's bounds by fX,
fY.
While I was here I updated the attribute parsing to the new form and
changed the type of fHref from SkSVGString to SkSVGIRI.
Change-Id: I4bfb91bca62e47f5dabfbb4aad48cbb301a7ea36
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/354118
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Tyler Denniston <tdenniston@google.com>
diff --git a/modules/svg/include/SkSVGUse.h b/modules/svg/include/SkSVGUse.h
index 6c524e3..93c2d20 100644
--- a/modules/svg/include/SkSVGUse.h
+++ b/modules/svg/include/SkSVGUse.h
@@ -21,13 +21,11 @@
void appendChild(sk_sp<SkSVGNode>) override;
- void setHref(const SkSVGStringType&);
- void setX(const SkSVGLength&);
- void setY(const SkSVGLength&);
+ SVG_ATTR(X , SkSVGLength, SkSVGLength(0))
+ SVG_ATTR(Y , SkSVGLength, SkSVGLength(0))
+ SVG_ATTR(Href, SkSVGIRI , SkSVGIRI())
protected:
- void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
-
bool onPrepareToRender(SkSVGRenderContext*) const override;
void onRender(const SkSVGRenderContext&) const override;
SkPath onAsPath(const SkSVGRenderContext&) const override;
@@ -36,9 +34,7 @@
private:
SkSVGUse();
- SkSVGStringType fHref;
- SkSVGLength fX = SkSVGLength(0);
- SkSVGLength fY = SkSVGLength(0);
+ bool parseAndSetAttribute(const char*, const char*) override;
using INHERITED = SkSVGTransformableNode;
};
diff --git a/modules/svg/src/SkSVGUse.cpp b/modules/svg/src/SkSVGUse.cpp
index bf4457c..6d80f0a 100644
--- a/modules/svg/src/SkSVGUse.cpp
+++ b/modules/svg/src/SkSVGUse.cpp
@@ -17,42 +17,15 @@
SkDebugf("cannot append child nodes to this element.\n");
}
-void SkSVGUse::setHref(const SkSVGStringType& href) {
- fHref = href;
-}
-
-void SkSVGUse::setX(const SkSVGLength& x) {
- fX = x;
-}
-
-void SkSVGUse::setY(const SkSVGLength& y) {
- fY = y;
-}
-
-void SkSVGUse::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
- switch (attr) {
- case SkSVGAttribute::kHref:
- if (const auto* href = v.as<SkSVGStringValue>()) {
- this->setHref(*href);
- }
- break;
- case SkSVGAttribute::kX:
- if (const auto* x = v.as<SkSVGLengthValue>()) {
- this->setX(*x);
- }
- break;
- case SkSVGAttribute::kY:
- if (const auto* y = v.as<SkSVGLengthValue>()) {
- this->setY(*y);
- }
- break;
- default:
- this->INHERITED::onSetAttribute(attr, v);
- }
+bool SkSVGUse::parseAndSetAttribute(const char* n, const char* v) {
+ return INHERITED::parseAndSetAttribute(n, v) ||
+ this->setX(SkSVGAttributeParser::parse<SkSVGLength>("x", n, v)) ||
+ this->setY(SkSVGAttributeParser::parse<SkSVGLength>("y", n, v)) ||
+ this->setHref(SkSVGAttributeParser::parse<SkSVGIRI>("xlink:href", n, v));
}
bool SkSVGUse::onPrepareToRender(SkSVGRenderContext* ctx) const {
- if (fHref.isEmpty() || !INHERITED::onPrepareToRender(ctx)) {
+ if (fHref.fIRI.isEmpty() || !INHERITED::onPrepareToRender(ctx)) {
return false;
}
@@ -68,7 +41,7 @@
}
void SkSVGUse::onRender(const SkSVGRenderContext& ctx) const {
- const auto ref = ctx.findNodeById(fHref);
+ const auto ref = ctx.findNodeById(fHref.fIRI);
if (!ref) {
return;
}
@@ -77,7 +50,7 @@
}
SkPath SkSVGUse::onAsPath(const SkSVGRenderContext& ctx) const {
- const auto ref = ctx.findNodeById(fHref);
+ const auto ref = ctx.findNodeById(fHref.fIRI);
if (!ref) {
return SkPath();
}
@@ -86,13 +59,17 @@
}
SkRect SkSVGUse::onObjectBoundingBox(const SkSVGRenderContext& ctx) const {
- const auto ref = ctx.findNodeById(fHref);
+ const auto ref = ctx.findNodeById(fHref.fIRI);
if (!ref) {
return SkRect::MakeEmpty();
}
- const SkRect bounds = ref->objectBoundingBox(ctx);
- const SkScalar x = ctx.lengthContext().resolve(fX, SkSVGLengthContext::LengthType::kHorizontal);
- const SkScalar y = ctx.lengthContext().resolve(fY, SkSVGLengthContext::LengthType::kVertical);
- return SkRect::MakeXYWH(x, y, bounds.width(), bounds.height());
+ const SkSVGLengthContext& lctx = ctx.lengthContext();
+ const SkScalar x = lctx.resolve(fX, SkSVGLengthContext::LengthType::kHorizontal);
+ const SkScalar y = lctx.resolve(fY, SkSVGLengthContext::LengthType::kVertical);
+
+ SkRect bounds = ref->objectBoundingBox(ctx);
+ bounds.offset(x, y);
+
+ return bounds;
}