Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkSVGPattern.cpp
Go to the documentation of this file.
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
9
16
18
19bool SkSVGPattern::parseAndSetAttribute(const char* name, const char* value) {
21 this->setX(SkSVGAttributeParser::parse<SkSVGLength>("x", name, value)) ||
22 this->setY(SkSVGAttributeParser::parse<SkSVGLength>("y", name, value)) ||
23 this->setWidth(SkSVGAttributeParser::parse<SkSVGLength>("width", name, value)) ||
24 this->setHeight(SkSVGAttributeParser::parse<SkSVGLength>("height", name, value)) ||
25 this->setPatternTransform(SkSVGAttributeParser::parse<SkSVGTransformType>(
26 "patternTransform", name, value)) ||
27 this->setHref(SkSVGAttributeParser::parse<SkSVGIRI>("xlink:href", name, value));
28}
29
30const SkSVGPattern* SkSVGPattern::hrefTarget(const SkSVGRenderContext& ctx) const {
31 if (fHref.iri().isEmpty()) {
32 return nullptr;
33 }
34
35 const auto href = ctx.findNodeById(fHref);
36 if (!href || href->tag() != SkSVGTag::kPattern) {
37 return nullptr;
38 }
39
40 return static_cast<const SkSVGPattern*>(href.get());
41}
42
43template <typename T>
45 if (!dst.isValid()) {
46 dst = src;
47 return 1;
48 }
49
50 return 0;
51}
52
53/* https://www.w3.org/TR/SVG11/pservers.html#PatternElementHrefAttribute
54 *
55 * Any attributes which are defined on the referenced element which are not defined on this element
56 * are inherited by this element. If this element has no children, and the referenced element does
57 * (possibly due to its own ‘xlink:href’ attribute), then this element inherits the children from
58 * the referenced element. Inheritance can be indirect to an arbitrary level; thus, if the
59 * referenced element inherits attributes or children due to its own ‘xlink:href’ attribute, then
60 * the current element can inherit those attributes or children.
61 */
62const SkSVGPattern* SkSVGPattern::resolveHref(const SkSVGRenderContext& ctx,
63 PatternAttributes* attrs) const {
64 const SkSVGPattern *currentNode = this,
65 *contentNode = this;
66 do {
67 // Bitwise OR to avoid short-circuiting.
68 const bool didInherit =
69 inherit_if_needed(currentNode->fX , attrs->fX) |
70 inherit_if_needed(currentNode->fY , attrs->fY) |
71 inherit_if_needed(currentNode->fWidth , attrs->fWidth) |
72 inherit_if_needed(currentNode->fHeight , attrs->fHeight) |
73 inherit_if_needed(currentNode->fPatternTransform, attrs->fPatternTransform);
74
75 if (!contentNode->hasChildren()) {
76 contentNode = currentNode;
77 }
78
79 if (contentNode->hasChildren() && !didInherit) {
80 // All attributes have been resolved, and a valid content node has been found.
81 // We can terminate the href chain early.
82 break;
83 }
84
85 // TODO: reference loop mitigation.
86 currentNode = currentNode->hrefTarget(ctx);
87 } while (currentNode);
88
89 return contentNode;
90}
91
93 PatternAttributes attrs;
94 const auto* contentNode = this->resolveHref(ctx, &attrs);
95
96 const auto tile = ctx.lengthContext().resolveRect(
97 attrs.fX.isValid() ? *attrs.fX : SkSVGLength(0),
98 attrs.fY.isValid() ? *attrs.fY : SkSVGLength(0),
99 attrs.fWidth.isValid() ? *attrs.fWidth : SkSVGLength(0),
100 attrs.fHeight.isValid() ? *attrs.fHeight : SkSVGLength(0));
101
102 if (tile.isEmpty()) {
103 return false;
104 }
105
106 const SkMatrix* patternTransform = attrs.fPatternTransform.isValid()
107 ? attrs.fPatternTransform.get()
108 : nullptr;
109
110 SkPictureRecorder recorder;
111 SkSVGRenderContext recordingContext(ctx, recorder.beginRecording(tile));
112
113 // Cannot call into INHERITED:: because SkSVGHiddenContainer skips rendering.
114 contentNode->SkSVGContainer::onRender(recordingContext);
115
116 paint->setShader(recorder.finishRecordingAsPicture()->makeShader(
120 patternTransform,
121 &tile));
122 return true;
123}
SkSVGTag
Definition SkSVGNode.h:23
int inherit_if_needed(const SkTLazy< T > &src, SkTLazy< T > &dst)
SkScalar get(int index) const
Definition SkMatrix.h:392
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
sk_sp< SkPicture > finishRecordingAsPicture()
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, SkFilterMode mode, const SkMatrix *localMatrix, const SkRect *tileRect) const
SkRect resolveRect(const SkSVGLength &x, const SkSVGLength &y, const SkSVGLength &w, const SkSVGLength &h) const
virtual bool parseAndSetAttribute(const char *name, const char *value)
Definition SkSVGNode.cpp:90
bool onAsPaint(const SkSVGRenderContext &, SkPaint *) const override
bool parseAndSetAttribute(const char *, const char *) override
BorrowedNode findNodeById(const SkSVGIRI &) const
const SkSVGLengthContext & lengthContext() const
const Paint & paint
uint8_t value
const char * name
Definition fuchsia.cc:50