OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> | |
3 * Copyright (C) Research In Motion Limited 2010. All rights reserved. | |
4 * Copyright 2014 The Chromium Authors. All rights reserved. | |
5 * | |
6 * This library is free software; you can redistribute it and/or | |
7 * modify it under the terms of the GNU Library General Public | |
8 * License as published by the Free Software Foundation; either | |
9 * version 2 of the License, or (at your option) any later version. | |
10 * | |
11 * This library is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 * Library General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU Library General Public License | |
17 * along with this library; see the file COPYING.LIB. If not, write to | |
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
19 * Boston, MA 02110-1301, USA. | |
20 */ | |
21 | |
22 #include "config.h" | |
23 #include "core/rendering/svg/RenderSVGResourcePattern.h" | |
24 | |
25 #include "core/dom/ElementTraversal.h" | |
26 #include "core/layout/svg/SVGLayoutSupport.h" | |
27 #include "core/paint/SVGPaintContext.h" | |
28 #include "core/paint/TransformRecorder.h" | |
29 #include "core/svg/SVGFitToViewBox.h" | |
30 #include "core/svg/SVGPatternElement.h" | |
31 #include "platform/graphics/GraphicsContext.h" | |
32 #include "platform/graphics/paint/DisplayItemList.h" | |
33 #include "third_party/skia/include/core/SkPicture.h" | |
34 | |
35 namespace blink { | |
36 | |
37 struct PatternData { | |
38 WTF_MAKE_FAST_ALLOCATED; | |
39 public: | |
40 RefPtr<Pattern> pattern; | |
41 AffineTransform transform; | |
42 }; | |
43 | |
44 RenderSVGResourcePattern::RenderSVGResourcePattern(SVGPatternElement* node) | |
45 : RenderSVGResourcePaintServer(node) | |
46 , m_shouldCollectPatternAttributes(true) | |
47 #if ENABLE(OILPAN) | |
48 , m_attributesWrapper(PatternAttributesWrapper::create()) | |
49 #endif | |
50 { | |
51 } | |
52 | |
53 void RenderSVGResourcePattern::removeAllClientsFromCache(bool markForInvalidatio
n) | |
54 { | |
55 m_patternMap.clear(); | |
56 m_shouldCollectPatternAttributes = true; | |
57 markAllClientsForInvalidation(markForInvalidation ? PaintInvalidation : Pare
ntOnlyInvalidation); | |
58 } | |
59 | |
60 void RenderSVGResourcePattern::removeClientFromCache(LayoutObject* client, bool
markForInvalidation) | |
61 { | |
62 ASSERT(client); | |
63 m_patternMap.remove(client); | |
64 markClientForInvalidation(client, markForInvalidation ? PaintInvalidation :
ParentOnlyInvalidation); | |
65 } | |
66 | |
67 PatternData* RenderSVGResourcePattern::patternForRenderer(const LayoutObject& ob
ject) | |
68 { | |
69 ASSERT(!m_shouldCollectPatternAttributes); | |
70 | |
71 // FIXME: the double hash lookup is needed to guard against paint-time inval
idation | |
72 // (painting animated images may trigger layout invals which delete our map
entry). | |
73 // Hopefully that will be addressed at some point, and then we can optimize
the lookup. | |
74 if (PatternData* currentData = m_patternMap.get(&object)) | |
75 return currentData; | |
76 | |
77 return m_patternMap.set(&object, buildPatternData(object)).storedValue->valu
e.get(); | |
78 } | |
79 | |
80 PassOwnPtr<PatternData> RenderSVGResourcePattern::buildPatternData(const LayoutO
bject& object) | |
81 { | |
82 // If we couldn't determine the pattern content element root, stop here. | |
83 const PatternAttributes& attributes = this->attributes(); | |
84 if (!attributes.patternContentElement()) | |
85 return nullptr; | |
86 | |
87 // An empty viewBox disables rendering. | |
88 if (attributes.hasViewBox() && attributes.viewBox().isEmpty()) | |
89 return nullptr; | |
90 | |
91 ASSERT(element()); | |
92 // Compute tile metrics. | |
93 FloatRect clientBoundingBox = object.objectBoundingBox(); | |
94 FloatRect tileBounds = SVGLengthContext::resolveRectangle(element(), | |
95 attributes.patternUnits(), clientBoundingBox, | |
96 attributes.x(), attributes.y(), attributes.width(), attributes.height())
; | |
97 if (tileBounds.isEmpty()) | |
98 return nullptr; | |
99 | |
100 AffineTransform tileTransform; | |
101 if (attributes.hasViewBox()) { | |
102 if (attributes.viewBox().isEmpty()) | |
103 return nullptr; | |
104 tileTransform = SVGFitToViewBox::viewBoxToViewTransform(attributes.viewB
ox(), | |
105 attributes.preserveAspectRatio(), tileBounds.width(), tileBounds.hei
ght()); | |
106 } else { | |
107 // A viewbox overrides patternContentUnits, per spec. | |
108 if (attributes.patternContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJE
CTBOUNDINGBOX) | |
109 tileTransform.scale(clientBoundingBox.width(), clientBoundingBox.hei
ght()); | |
110 } | |
111 | |
112 OwnPtr<PatternData> patternData = adoptPtr(new PatternData); | |
113 patternData->pattern = Pattern::createPicturePattern(asPicture(tileBounds, t
ileTransform)); | |
114 | |
115 // Compute pattern space transformation. | |
116 patternData->transform.translate(tileBounds.x(), tileBounds.y()); | |
117 AffineTransform patternTransform = attributes.patternTransform(); | |
118 if (!patternTransform.isIdentity()) | |
119 patternData->transform = patternTransform * patternData->transform; | |
120 | |
121 return patternData.release(); | |
122 } | |
123 | |
124 SVGPaintServer RenderSVGResourcePattern::preparePaintServer(const LayoutObject&
object) | |
125 { | |
126 clearInvalidationMask(); | |
127 | |
128 SVGPatternElement* patternElement = toSVGPatternElement(element()); | |
129 if (!patternElement) | |
130 return SVGPaintServer::invalid(); | |
131 | |
132 if (m_shouldCollectPatternAttributes) { | |
133 patternElement->synchronizeAnimatedSVGAttribute(anyQName()); | |
134 | |
135 #if ENABLE(OILPAN) | |
136 m_attributesWrapper->set(PatternAttributes()); | |
137 #else | |
138 m_attributes = PatternAttributes(); | |
139 #endif | |
140 patternElement->collectPatternAttributes(mutableAttributes()); | |
141 m_shouldCollectPatternAttributes = false; | |
142 } | |
143 | |
144 // Spec: When the geometry of the applicable element has no width or height
and objectBoundingBox is specified, | |
145 // then the given effect (e.g. a gradient or a filter) will be ignored. | |
146 FloatRect objectBoundingBox = object.objectBoundingBox(); | |
147 if (attributes().patternUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDIN
GBOX && objectBoundingBox.isEmpty()) | |
148 return SVGPaintServer::invalid(); | |
149 | |
150 PatternData* patternData = patternForRenderer(object); | |
151 if (!patternData || !patternData->pattern) | |
152 return SVGPaintServer::invalid(); | |
153 | |
154 patternData->pattern->setPatternSpaceTransform(patternData->transform); | |
155 | |
156 return SVGPaintServer(patternData->pattern); | |
157 } | |
158 | |
159 PassRefPtr<const SkPicture> RenderSVGResourcePattern::asPicture(const FloatRect&
tileBounds, | |
160 const AffineTransform& tileTransform) const | |
161 { | |
162 ASSERT(!m_shouldCollectPatternAttributes); | |
163 | |
164 AffineTransform contentTransform; | |
165 if (attributes().patternContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECT
BOUNDINGBOX) | |
166 contentTransform = tileTransform; | |
167 | |
168 // Draw the content into a Picture. | |
169 OwnPtr<DisplayItemList> displayItemList; | |
170 if (RuntimeEnabledFeatures::slimmingPaintEnabled()) | |
171 displayItemList = DisplayItemList::create(); | |
172 GraphicsContext recordingContext(nullptr, displayItemList.get()); | |
173 recordingContext.beginRecording(FloatRect(FloatPoint(), tileBounds.size())); | |
174 | |
175 ASSERT(attributes().patternContentElement()); | |
176 RenderSVGResourceContainer* patternRenderer = | |
177 toRenderSVGResourceContainer(attributes().patternContentElement()->rende
rer()); | |
178 ASSERT(patternRenderer); | |
179 ASSERT(!patternRenderer->needsLayout()); | |
180 | |
181 SubtreeContentTransformScope contentTransformScope(contentTransform); | |
182 | |
183 { | |
184 TransformRecorder transformRecorder(recordingContext, patternRenderer->d
isplayItemClient(), tileTransform); | |
185 for (LayoutObject* child = patternRenderer->firstChild(); child; child =
child->nextSibling()) | |
186 SVGPaintContext::paintSubtree(&recordingContext, child); | |
187 } | |
188 | |
189 if (displayItemList) | |
190 displayItemList->replay(&recordingContext); | |
191 return recordingContext.endRecording(); | |
192 } | |
193 | |
194 } | |
OLD | NEW |