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