| /* |
| * Copyright 2016 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/core/SkCanvas.h" |
| #include "modules/svg/include/SkSVGRenderContext.h" |
| #include "modules/svg/include/SkSVGSVG.h" |
| #include "modules/svg/include/SkSVGValue.h" |
| |
| void SkSVGSVG::renderNode(const SkSVGRenderContext& ctx, const SkSVGIRI& iri) const { |
| SkSVGRenderContext localContext(ctx, this); |
| SkSVGRenderContext::BorrowedNode node = localContext.findNodeById(iri); |
| if (!node) { |
| return; |
| } |
| |
| if (this->onPrepareToRender(&localContext)) { |
| if (this == node.get()) { |
| this->onRender(ctx); |
| } else { |
| node->render(localContext); |
| } |
| } |
| } |
| |
| bool SkSVGSVG::onPrepareToRender(SkSVGRenderContext* ctx) const { |
| // x/y are ignored for outermost svg elements |
| const auto x = fType == Type::kInner ? fX : SkSVGLength(0); |
| const auto y = fType == Type::kInner ? fY : SkSVGLength(0); |
| |
| auto viewPortRect = ctx->lengthContext().resolveRect(x, y, fWidth, fHeight); |
| auto contentMatrix = SkMatrix::Translate(viewPortRect.x(), viewPortRect.y()); |
| auto viewPort = SkSize::Make(viewPortRect.width(), viewPortRect.height()); |
| |
| if (fViewBox.isValid()) { |
| const SkRect& viewBox = *fViewBox; |
| |
| // An empty viewbox disables rendering. |
| if (viewBox.isEmpty()) { |
| return false; |
| } |
| |
| // A viewBox overrides the intrinsic viewport. |
| viewPort = SkSize::Make(viewBox.width(), viewBox.height()); |
| |
| contentMatrix.preConcat(ComputeViewboxMatrix(viewBox, viewPortRect, fPreserveAspectRatio)); |
| } |
| |
| if (!contentMatrix.isIdentity()) { |
| ctx->saveOnce(); |
| ctx->canvas()->concat(contentMatrix); |
| } |
| |
| if (viewPort != ctx->lengthContext().viewPort()) { |
| ctx->writableLengthContext()->setViewPort(viewPort); |
| } |
| |
| return this->INHERITED::onPrepareToRender(ctx); |
| } |
| |
| void SkSVGSVG::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) { |
| switch (attr) { |
| case SkSVGAttribute::kX: |
| if (const auto* x = v.as<SkSVGLengthValue>()) { |
| this->setX(*x); |
| } |
| break; |
| case SkSVGAttribute::kY: |
| if (const auto* y = v.as<SkSVGLengthValue>()) { |
| this->setY(*y); |
| } |
| break; |
| case SkSVGAttribute::kWidth: |
| if (const auto* w = v.as<SkSVGLengthValue>()) { |
| this->setWidth(*w); |
| } |
| break; |
| case SkSVGAttribute::kHeight: |
| if (const auto* h = v.as<SkSVGLengthValue>()) { |
| this->setHeight(*h); |
| } |
| break; |
| case SkSVGAttribute::kViewBox: |
| if (const auto* vb = v.as<SkSVGViewBoxValue>()) { |
| this->setViewBox(*vb); |
| } |
| break; |
| case SkSVGAttribute::kPreserveAspectRatio: |
| if (const auto* par = v.as<SkSVGPreserveAspectRatioValue>()) { |
| this->setPreserveAspectRatio(*par); |
| } |
| break; |
| default: |
| this->INHERITED::onSetAttribute(attr, v); |
| } |
| } |
| |
| // https://www.w3.org/TR/SVG11/coords.html#IntrinsicSizing |
| SkSize SkSVGSVG::intrinsicSize(const SkSVGLengthContext& lctx) const { |
| // Percentage values do not provide an intrinsic size. |
| if (fWidth.unit() == SkSVGLength::Unit::kPercentage || |
| fHeight.unit() == SkSVGLength::Unit::kPercentage) { |
| return SkSize::Make(0, 0); |
| } |
| |
| return SkSize::Make(lctx.resolve(fWidth, SkSVGLengthContext::LengthType::kHorizontal), |
| lctx.resolve(fHeight, SkSVGLengthContext::LengthType::kVertical)); |
| } |