xref: /third_party/skia/modules/svg/src/SkSVGUse.cpp (revision cb93a386)
1/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "modules/svg/include/SkSVGUse.h"
9
10#include "include/core/SkCanvas.h"
11#include "modules/svg/include/SkSVGRenderContext.h"
12#include "modules/svg/include/SkSVGValue.h"
13
14SkSVGUse::SkSVGUse() : INHERITED(SkSVGTag::kUse) {}
15
16void SkSVGUse::appendChild(sk_sp<SkSVGNode>) {
17    SkDebugf("cannot append child nodes to this element.\n");
18}
19
20bool SkSVGUse::parseAndSetAttribute(const char* n, const char* v) {
21    return INHERITED::parseAndSetAttribute(n, v) ||
22           this->setX(SkSVGAttributeParser::parse<SkSVGLength>("x", n, v)) ||
23           this->setY(SkSVGAttributeParser::parse<SkSVGLength>("y", n, v)) ||
24           this->setHref(SkSVGAttributeParser::parse<SkSVGIRI>("xlink:href", n, v));
25}
26
27bool SkSVGUse::onPrepareToRender(SkSVGRenderContext* ctx) const {
28    if (fHref.iri().isEmpty() || !INHERITED::onPrepareToRender(ctx)) {
29        return false;
30    }
31
32    if (fX.value() || fY.value()) {
33        // Restored when the local SkSVGRenderContext leaves scope.
34        ctx->saveOnce();
35        ctx->canvas()->translate(fX.value(), fY.value());
36    }
37
38    // TODO: width/height override for <svg> targets.
39
40    return true;
41}
42
43void SkSVGUse::onRender(const SkSVGRenderContext& ctx) const {
44    const auto ref = ctx.findNodeById(fHref);
45    if (!ref) {
46        return;
47    }
48
49    ref->render(ctx);
50}
51
52SkPath SkSVGUse::onAsPath(const SkSVGRenderContext& ctx) const {
53    const auto ref = ctx.findNodeById(fHref);
54    if (!ref) {
55        return SkPath();
56    }
57
58    return ref->asPath(ctx);
59}
60
61SkRect SkSVGUse::onObjectBoundingBox(const SkSVGRenderContext& ctx) const {
62    const auto ref = ctx.findNodeById(fHref);
63    if (!ref) {
64        return SkRect::MakeEmpty();
65    }
66
67    const SkSVGLengthContext& lctx = ctx.lengthContext();
68    const SkScalar x = lctx.resolve(fX, SkSVGLengthContext::LengthType::kHorizontal);
69    const SkScalar y = lctx.resolve(fY, SkSVGLengthContext::LengthType::kVertical);
70
71    SkRect bounds = ref->objectBoundingBox(ctx);
72    bounds.offset(x, y);
73
74    return bounds;
75}
76