xref: /third_party/skia/modules/svg/src/SkSVGSVG.cpp (revision cb93a386)
1/*
2 * Copyright 2016 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 "include/core/SkCanvas.h"
9#include "modules/svg/include/SkSVGRenderContext.h"
10#include "modules/svg/include/SkSVGSVG.h"
11#include "modules/svg/include/SkSVGValue.h"
12
13bool SkSVGSVG::onPrepareToRender(SkSVGRenderContext* ctx) const {
14    // x/y are ignored for outermost svg elements
15    const auto x = fType == Type::kInner ? fX : SkSVGLength(0);
16    const auto y = fType == Type::kInner ? fY : SkSVGLength(0);
17
18    auto viewPortRect  = ctx->lengthContext().resolveRectForSVG(x, y, fWidth, fHeight);
19    auto contentMatrix = SkMatrix::Translate(viewPortRect.x(), viewPortRect.y());
20    auto viewPort      = SkSize::Make(viewPortRect.width(), viewPortRect.height());
21
22    if (fViewBox.isValid()) {
23        const SkRect& viewBox = *fViewBox;
24
25        // An empty viewbox disables rendering.
26        if (viewBox.isEmpty()) {
27            return false;
28        }
29
30        // A viewBox overrides the intrinsic viewport.
31        viewPort = SkSize::Make(viewBox.width(), viewBox.height());
32
33        contentMatrix.preConcat(ComputeViewboxMatrix(viewBox, viewPortRect, fPreserveAspectRatio));
34    }
35
36    if (!contentMatrix.isIdentity()) {
37        ctx->saveOnce();
38        ctx->canvas()->concat(contentMatrix);
39    }
40
41    if (viewPort != ctx->lengthContext().viewPort()) {
42        ctx->writableLengthContext()->setViewPort(viewPort);
43    }
44
45    return this->INHERITED::onPrepareToRender(ctx);
46}
47
48void SkSVGSVG::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
49    switch (attr) {
50    case SkSVGAttribute::kX:
51        if (const auto* x = v.as<SkSVGLengthValue>()) {
52            this->setX(*x);
53        }
54        break;
55    case SkSVGAttribute::kY:
56        if (const auto* y = v.as<SkSVGLengthValue>()) {
57            this->setY(*y);
58        }
59        break;
60    case SkSVGAttribute::kWidth:
61        if (const auto* w = v.as<SkSVGLengthValue>()) {
62            this->setWidth(*w);
63        }
64        break;
65    case SkSVGAttribute::kHeight:
66        if (const auto* h = v.as<SkSVGLengthValue>()) {
67            this->setHeight(*h);
68        }
69        break;
70    case SkSVGAttribute::kViewBox:
71        if (const auto* vb = v.as<SkSVGViewBoxValue>()) {
72            this->setViewBox(*vb);
73        }
74        break;
75    case SkSVGAttribute::kPreserveAspectRatio:
76        if (const auto* par = v.as<SkSVGPreserveAspectRatioValue>()) {
77            this->setPreserveAspectRatio(*par);
78        }
79        break;
80    default:
81        this->INHERITED::onSetAttribute(attr, v);
82    }
83}
84
85// https://www.w3.org/TR/SVG11/coords.html#IntrinsicSizing
86SkSize SkSVGSVG::intrinsicSize(const SkSVGLengthContext& lctx) const {
87    // Percentage values do not provide an intrinsic size.
88    if (fWidth.unit() == SkSVGLength::Unit::kPercentage ||
89        fHeight.unit() == SkSVGLength::Unit::kPercentage) {
90        return SkSize::Make(0, 0);
91    }
92
93    return SkSize::Make(lctx.resolveForSVG(fWidth, SkSVGLengthContext::LengthType::kHorizontal),
94                        lctx.resolveForSVG(fHeight, SkSVGLengthContext::LengthType::kVertical));
95}
96