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