Remove unnecessary #include SVGResourcesCache.h in SVGDocumentExtensions.h; use forwa...
[WebKit-https.git] / Source / WebCore / rendering / svg / SVGRenderSupport.cpp
1 /*
2  * Copyright (C) 2007, 2008 Rob Buis <buis@kde.org>
3  * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
4  * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
5  * Copyright (C) 2009 Google, Inc.  All rights reserved.
6  * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
7  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24
25 #include "config.h"
26
27 #if ENABLE(SVG)
28 #include "SVGRenderSupport.h"
29
30 #include "FrameView.h"
31 #include "ImageBuffer.h"
32 #include "NodeRenderStyle.h"
33 #include "RenderLayer.h"
34 #include "RenderSVGPath.h"
35 #include "RenderSVGResource.h"
36 #include "RenderSVGResourceClipper.h"
37 #include "RenderSVGResourceFilter.h"
38 #include "RenderSVGResourceMarker.h"
39 #include "RenderSVGResourceMasker.h"
40 #include "RenderSVGRoot.h"
41 #include "SVGResources.h"
42 #include "SVGResourcesCache.h"
43 #include "SVGStyledElement.h"
44 #include "TransformState.h"
45 #include <wtf/UnusedParam.h>
46
47 namespace WebCore {
48
49 LayoutRect SVGRenderSupport::clippedOverflowRectForRepaint(const RenderObject* object, RenderBoxModelObject* repaintContainer)
50 {
51     // Return early for any cases where we don't actually paint
52     if (object->style()->visibility() != VISIBLE && !object->enclosingLayer()->hasVisibleContent())
53         return LayoutRect();
54
55     // Pass our local paint rect to computeRectForRepaint() which will
56     // map to parent coords and recurse up the parent chain.
57     LayoutRect repaintRect = enclosingLayoutRect(object->repaintRectInLocalCoordinates());
58     object->computeRectForRepaint(repaintContainer, repaintRect);
59     return repaintRect;
60 }
61
62 void SVGRenderSupport::computeRectForRepaint(const RenderObject* object, RenderBoxModelObject* repaintContainer, LayoutRect& repaintRect, bool fixed)
63 {
64     const SVGRenderStyle* svgStyle = object->style()->svgStyle();
65     if (const ShadowData* shadow = svgStyle->shadow())
66         shadow->adjustRectForShadow(repaintRect);
67     repaintRect.inflate(object->style()->outlineWidth());
68
69     // Translate to coords in our parent renderer, and then call computeRectForRepaint on our parent
70     repaintRect = object->localToParentTransform().mapRect(repaintRect);
71     object->parent()->computeRectForRepaint(repaintContainer, repaintRect, fixed);
72 }
73
74 void SVGRenderSupport::mapLocalToContainer(const RenderObject* object, RenderBoxModelObject* repaintContainer, TransformState& transformState, bool* wasFixed)
75 {
76     transformState.applyTransform(object->localToParentTransform());
77     object->parent()->mapLocalToContainer(repaintContainer, false, true, transformState, wasFixed);
78 }
79
80 bool SVGRenderSupport::prepareToRenderSVGContent(RenderObject* object, PaintInfo& paintInfo)
81 {
82     ASSERT(object);
83
84     RenderStyle* style = object->style();
85     ASSERT(style);
86
87     const SVGRenderStyle* svgStyle = style->svgStyle();
88     ASSERT(svgStyle);
89
90     // Setup transparency layers before setting up SVG resources!
91     float opacity = style->opacity();
92     const ShadowData* shadow = svgStyle->shadow();
93     if (opacity < 1 || shadow) {
94         FloatRect repaintRect = object->repaintRectInLocalCoordinates();
95
96         if (opacity < 1) {
97             paintInfo.context->clip(repaintRect);
98             paintInfo.context->beginTransparencyLayer(opacity);
99         }
100
101         if (shadow) {
102             paintInfo.context->clip(repaintRect);
103             paintInfo.context->setShadow(IntSize(shadow->x(), shadow->y()), shadow->blur(), shadow->color(), style->colorSpace());
104             paintInfo.context->beginTransparencyLayer(1);
105         }
106     }
107
108     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
109     if (!resources) {
110 #if ENABLE(FILTERS)
111         if (svgStyle->hasFilter())
112             return false;
113 #endif
114         return true;
115     }
116
117     if (RenderSVGResourceMasker* masker = resources->masker()) {
118         if (!masker->applyResource(object, style, paintInfo.context, ApplyToDefaultMode))
119             return false;
120     }
121
122     if (RenderSVGResourceClipper* clipper = resources->clipper()) {
123         if (!clipper->applyResource(object, style, paintInfo.context, ApplyToDefaultMode))
124             return false;
125     }
126
127 #if ENABLE(FILTERS)
128     if (RenderSVGResourceFilter* filter = resources->filter()) {
129         if (!filter->applyResource(object, style, paintInfo.context, ApplyToDefaultMode))
130             return false;
131     }
132 #endif
133
134     return true;
135 }
136
137 void SVGRenderSupport::finishRenderSVGContent(RenderObject* object, PaintInfo& paintInfo, GraphicsContext* savedContext)
138 {
139 #if !ENABLE(FILTERS)
140     UNUSED_PARAM(savedContext);
141 #endif
142
143     ASSERT(object);
144
145     const RenderStyle* style = object->style();
146     ASSERT(style);
147
148     const SVGRenderStyle* svgStyle = style->svgStyle();
149     ASSERT(svgStyle);
150
151 #if ENABLE(FILTERS)
152     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
153     if (resources) {
154         if (RenderSVGResourceFilter* filter = resources->filter()) {
155             filter->postApplyResource(object, paintInfo.context, ApplyToDefaultMode, /* path */0);
156             paintInfo.context = savedContext;
157         }
158     }
159 #endif
160
161     if (style->opacity() < 1)
162         paintInfo.context->endTransparencyLayer();
163
164     if (svgStyle->shadow())
165         paintInfo.context->endTransparencyLayer();
166 }
167
168 void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObject* container, FloatRect& objectBoundingBox, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox)
169 {
170     for (RenderObject* current = container->firstChild(); current; current = current->nextSibling()) {
171         if (current->isSVGHiddenContainer())
172             continue;
173
174         const AffineTransform& transform = current->localToParentTransform();
175         if (transform.isIdentity()) {
176             objectBoundingBox.unite(current->objectBoundingBox());
177             strokeBoundingBox.unite(current->strokeBoundingBox());
178             repaintBoundingBox.unite(current->repaintRectInLocalCoordinates());
179         } else {
180             objectBoundingBox.unite(transform.mapRect(current->objectBoundingBox()));
181             strokeBoundingBox.unite(transform.mapRect(current->strokeBoundingBox()));
182             repaintBoundingBox.unite(transform.mapRect(current->repaintRectInLocalCoordinates()));
183         }
184     }
185 }
186
187 bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo& paintInfo)
188 {
189     if (localTransform.isIdentity())
190         return localRepaintRect.intersects(paintInfo.rect);
191
192     return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect);
193 }
194
195 const RenderSVGRoot* SVGRenderSupport::findTreeRootObject(const RenderObject* start)
196 {
197     while (start && !start->isSVGRoot())
198         start = start->parent();
199
200     ASSERT(start);
201     ASSERT(start->isSVGRoot());
202     return toRenderSVGRoot(start);
203 }
204
205 static inline void invalidateResourcesOfChildren(RenderObject* start)
206 {
207     ASSERT(!start->needsLayout());
208     if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(start))
209         resources->removeClientFromCache(start, false);
210
211     for (RenderObject* child = start->firstChild(); child; child = child->nextSibling())
212         invalidateResourcesOfChildren(child);
213 }
214
215 void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout)
216 {
217     bool layoutSizeChanged = findTreeRootObject(start)->isLayoutSizeChanged();
218     HashSet<RenderObject*> notlayoutedObjects;
219
220     for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
221         bool needsLayout = selfNeedsLayout;
222
223         if (layoutSizeChanged) {
224             // When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths
225             if (SVGElement* element = child->node()->isSVGElement() ? static_cast<SVGElement*>(child->node()) : 0) {
226                 if (element->isStyled() && static_cast<SVGStyledElement*>(element)->hasRelativeLengths()) {
227                     // When the layout size changed and when using relative values tell the RenderSVGPath to update its Path object
228                     if (child->isSVGPath())
229                         toRenderSVGPath(child)->setNeedsPathUpdate();
230
231                     needsLayout = true;
232                 }
233             }
234         }
235
236         if (needsLayout) {
237             child->setNeedsLayout(true, false);
238             child->layout();
239         } else {
240             if (child->needsLayout())
241                 child->layout();
242             else if (layoutSizeChanged)
243                 notlayoutedObjects.add(child);
244         }
245
246         ASSERT(!child->needsLayout());
247     }
248
249     if (!layoutSizeChanged) {
250         ASSERT(notlayoutedObjects.isEmpty());
251         return;
252     }
253
254     // If the layout size changed, invalidate all resources of all children that didn't go through the layout() code path.
255     HashSet<RenderObject*>::iterator end = notlayoutedObjects.end();
256     for (HashSet<RenderObject*>::iterator it = notlayoutedObjects.begin(); it != end; ++it)
257         invalidateResourcesOfChildren(*it);
258 }
259
260 bool SVGRenderSupport::isOverflowHidden(const RenderObject* object)
261 {
262     // SVG doesn't support independent x/y overflow
263     ASSERT(object->style()->overflowX() == object->style()->overflowY());
264
265     // OSCROLL is never set for SVG - see CSSStyleSelector::adjustRenderStyle
266     ASSERT(object->style()->overflowX() != OSCROLL);
267
268     // RenderSVGRoot should never query for overflow state - it should always clip itself to the initial viewport size.
269     ASSERT(!object->isRoot());
270
271     return object->style()->overflowX() == OHIDDEN;
272 }
273
274 void SVGRenderSupport::intersectRepaintRectWithResources(const RenderObject* object, FloatRect& repaintRect)
275 {
276     ASSERT(object);
277
278     RenderStyle* style = object->style();
279     ASSERT(style);
280
281     const SVGRenderStyle* svgStyle = style->svgStyle();
282     ASSERT(svgStyle);
283
284     RenderObject* renderer = const_cast<RenderObject*>(object);
285     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer);
286     if (!resources) {
287         if (const ShadowData* shadow = svgStyle->shadow())
288             shadow->adjustRectForShadow(repaintRect);
289         return;
290     }
291
292 #if ENABLE(FILTERS)
293     if (RenderSVGResourceFilter* filter = resources->filter())
294         repaintRect = filter->resourceBoundingBox(renderer);
295 #endif
296
297     if (RenderSVGResourceClipper* clipper = resources->clipper())
298         repaintRect.intersect(clipper->resourceBoundingBox(renderer));
299
300     if (RenderSVGResourceMasker* masker = resources->masker())
301         repaintRect.intersect(masker->resourceBoundingBox(renderer));
302
303     if (const ShadowData* shadow = svgStyle->shadow())
304         shadow->adjustRectForShadow(repaintRect);
305 }
306
307 bool SVGRenderSupport::filtersForceContainerLayout(RenderObject* object)
308 {
309     // If any of this container's children need to be laid out, and a filter is applied
310     // to the container, we need to repaint the entire container.
311     if (!object->normalChildNeedsLayout())
312         return false;
313
314     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
315     if (!resources || !resources->filter())
316         return false;
317
318     return true;
319 }
320
321 bool SVGRenderSupport::pointInClippingArea(RenderObject* object, const FloatPoint& point)
322 {
323     ASSERT(object);
324
325     // We just take clippers into account to determine if a point is on the node. The Specification may
326     // change later and we also need to check maskers.
327     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
328     if (!resources)
329         return true;
330
331     if (RenderSVGResourceClipper* clipper = resources->clipper())
332         return clipper->hitTestClipContent(object->objectBoundingBox(), point);
333
334     return true;
335 }
336
337 void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const RenderStyle* style, const RenderObject* object)
338 {
339     ASSERT(context);
340     ASSERT(style);
341     ASSERT(object);
342     ASSERT(object->node());
343     ASSERT(object->node()->isSVGElement());
344
345     const SVGRenderStyle* svgStyle = style->svgStyle();
346     ASSERT(svgStyle);
347
348     SVGLengthContext lengthContext(static_cast<SVGElement*>(object->node()));
349     context->setStrokeThickness(svgStyle->strokeWidth().value(lengthContext));
350     context->setLineCap(svgStyle->capStyle());
351     context->setLineJoin(svgStyle->joinStyle());
352     if (svgStyle->joinStyle() == MiterJoin)
353         context->setMiterLimit(svgStyle->strokeMiterLimit());
354
355     const Vector<SVGLength>& dashes = svgStyle->strokeDashArray();
356     if (dashes.isEmpty())
357         context->setStrokeStyle(SolidStroke);
358     else {
359         DashArray dashArray;
360         const Vector<SVGLength>::const_iterator end = dashes.end();
361         for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it)
362             dashArray.append((*it).value(lengthContext));
363
364         context->setLineDash(dashArray, svgStyle->strokeDashOffset().value(lengthContext));
365     }
366 }
367
368 }
369
370 #endif