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 "experimental/svg/model/SkSVGUse.h"
9 
10 #include "experimental/svg/model/SkSVGRenderContext.h"
11 #include "experimental/svg/model/SkSVGValue.h"
12 #include "include/core/SkCanvas.h"
13 
SkSVGUse()14 SkSVGUse::SkSVGUse() : INHERITED(SkSVGTag::kUse) {}
15 
appendChild(sk_sp<SkSVGNode>)16 void SkSVGUse::appendChild(sk_sp<SkSVGNode>) {
17     SkDebugf("cannot append child nodes to this element.\n");
18 }
19 
setHref(const SkSVGStringType & href)20 void SkSVGUse::setHref(const SkSVGStringType& href) {
21     fHref = href;
22 }
23 
setX(const SkSVGLength & x)24 void SkSVGUse::setX(const SkSVGLength& x) {
25     fX = x;
26 }
27 
setY(const SkSVGLength & y)28 void SkSVGUse::setY(const SkSVGLength& y) {
29     fY = y;
30 }
31 
onSetAttribute(SkSVGAttribute attr,const SkSVGValue & v)32 void SkSVGUse::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
33     switch (attr) {
34     case SkSVGAttribute::kHref:
35         if (const auto* href = v.as<SkSVGStringValue>()) {
36             this->setHref(*href);
37         }
38         break;
39     case SkSVGAttribute::kX:
40         if (const auto* x = v.as<SkSVGLengthValue>()) {
41             this->setX(*x);
42         }
43         break;
44     case SkSVGAttribute::kY:
45         if (const auto* y = v.as<SkSVGLengthValue>()) {
46             this->setY(*y);
47         }
48         break;
49     default:
50         this->INHERITED::onSetAttribute(attr, v);
51     }
52 }
53 
onPrepareToRender(SkSVGRenderContext * ctx) const54 bool SkSVGUse::onPrepareToRender(SkSVGRenderContext* ctx) const {
55     if (fHref.value().isEmpty() || !INHERITED::onPrepareToRender(ctx)) {
56         return false;
57     }
58 
59     if (fX.value() || fY.value()) {
60         // Restored when the local SkSVGRenderContext leaves scope.
61         ctx->saveOnce();
62         ctx->canvas()->translate(fX.value(), fY.value());
63     }
64 
65     // TODO: width/height override for <svg> targets.
66 
67     return true;
68 }
69 
onRender(const SkSVGRenderContext & ctx) const70 void SkSVGUse::onRender(const SkSVGRenderContext& ctx) const {
71     const auto* ref = ctx.findNodeById(fHref);
72     if (!ref) {
73         return;
74     }
75 
76     ref->render(ctx);
77 }
78 
onAsPath(const SkSVGRenderContext & ctx) const79 SkPath SkSVGUse::onAsPath(const SkSVGRenderContext& ctx) const {
80     const auto* ref = ctx.findNodeById(fHref);
81     if (!ref) {
82         return SkPath();
83     }
84 
85     return ref->asPath(ctx);
86 }
87