/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "modules/svg/include/SkSVGUse.h" #include "include/core/SkCanvas.h" #include "include/core/SkScalar.h" #include "include/private/base/SkDebug.h" #include "modules/svg/include/SkSVGAttributeParser.h" #include "modules/svg/include/SkSVGRenderContext.h" SkSVGUse::SkSVGUse() : INHERITED(SkSVGTag::kUse) {} void SkSVGUse::appendChild(sk_sp) { SkDEBUGF("cannot append child nodes to this element.\n"); } bool SkSVGUse::parseAndSetAttribute(const char* n, const char* v) { return INHERITED::parseAndSetAttribute(n, v) || this->setX(SkSVGAttributeParser::parse("x", n, v)) || this->setY(SkSVGAttributeParser::parse("y", n, v)) || this->setHref(SkSVGAttributeParser::parse("xlink:href", n, v)); } bool SkSVGUse::onPrepareToRender(SkSVGRenderContext* ctx) const { if (fHref.iri().isEmpty() || !INHERITED::onPrepareToRender(ctx)) { return false; } if (fX.value() || fY.value()) { // Restored when the local SkSVGRenderContext leaves scope. ctx->saveOnce(); ctx->canvas()->translate(fX.value(), fY.value()); } // TODO: width/height override for targets. return true; } void SkSVGUse::onRender(const SkSVGRenderContext& ctx) const { const auto ref = ctx.findNodeById(fHref); if (!ref) { return; } ref->render(ctx); } SkPath SkSVGUse::onAsPath(const SkSVGRenderContext& ctx) const { const auto ref = ctx.findNodeById(fHref); if (!ref) { return SkPath(); } return ref->asPath(ctx); } SkRect SkSVGUse::onObjectBoundingBox(const SkSVGRenderContext& ctx) const { const auto ref = ctx.findNodeById(fHref); if (!ref) { return SkRect::MakeEmpty(); } 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; }