| /* | |
| * Copyright 2017 Google LLC | |
| * | |
| * 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/SkDebug.h" | |
| #include "modules/svg/include/SkSVGAttributeParser.h" | |
| #include "modules/svg/include/SkSVGRenderContext.h" | |
| SkSVGUse::SkSVGUse() : INHERITED(SkSVGTag::kUse) {} | |
| void SkSVGUse::appendChild(sk_sp<SkSVGNode>) { | |
| 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<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.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 <svg> 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::onTransformableObjectBoundingBox(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; | |
| } |