• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3                   2004, 2005, 2007, 2008 Rob Buis <buis@kde.org>
4                   2007 Eric Seidel <eric@webkit.org>
5     Copyright (C) 2009 Google, Inc.  All rights reserved.
6 
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Library General Public
9     License as published by the Free Software Foundation; either
10     version 2 of the License, or (at your option) any later version.
11 
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Library General Public License for more details.
16 
17     You should have received a copy of the GNU Library General Public License
18     aint with this library; see the file COPYING.LIB.  If not, write to
19     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20     Boston, MA 02110-1301, USA.
21 */
22 
23 #include "config.h"
24 
25 #if ENABLE(SVG)
26 #include "RenderSVGContainer.h"
27 
28 #include "AXObjectCache.h"
29 #include "FloatQuad.h"
30 #include "GraphicsContext.h"
31 #include "RenderView.h"
32 #include "SVGRenderSupport.h"
33 #include "SVGResourceFilter.h"
34 #include "SVGStyledElement.h"
35 #include "SVGURIReference.h"
36 
37 namespace WebCore {
38 
RenderSVGContainer(SVGStyledElement * node)39 RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node)
40     : RenderSVGModelObject(node)
41     , m_drawsContents(true)
42 {
43 }
44 
drawsContents() const45 bool RenderSVGContainer::drawsContents() const
46 {
47     return m_drawsContents;
48 }
49 
setDrawsContents(bool drawsContents)50 void RenderSVGContainer::setDrawsContents(bool drawsContents)
51 {
52     m_drawsContents = drawsContents;
53 }
54 
layout()55 void RenderSVGContainer::layout()
56 {
57     ASSERT(needsLayout());
58     ASSERT(!view()->layoutStateEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree.
59 
60     calcViewport(); // Allow RenderSVGViewportContainer to update its viewport
61 
62     LayoutRepainter repainter(*this, checkForRepaintDuringLayout() || selfWillPaint());
63     calculateLocalTransform(); // Allow RenderSVGTransformableContainer to update its transform
64 
65     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
66         // Only force our kids to layout if we're being asked to relayout as a result of a parent changing
67         // FIXME: We should be able to skip relayout of non-relative kids when only bounds size has changed
68         // that's a possible future optimization using LayoutState
69         // http://bugs.webkit.org/show_bug.cgi?id=15391
70         if (selfNeedsLayout())
71             child->setNeedsLayout(true);
72 
73         child->layoutIfNeeded();
74         ASSERT(!child->needsLayout());
75     }
76     repainter.repaintAfterLayout();
77 
78     setNeedsLayout(false);
79 }
80 
selfWillPaint() const81 bool RenderSVGContainer::selfWillPaint() const
82 {
83 #if ENABLE(FILTERS)
84     const SVGRenderStyle* svgStyle = style()->svgStyle();
85     SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter());
86     if (filter)
87         return true;
88 #endif
89     return false;
90 }
91 
paint(PaintInfo & paintInfo,int,int)92 void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int)
93 {
94     if (paintInfo.context->paintingDisabled() || !drawsContents())
95         return;
96 
97      // Spec: groups w/o children still may render filter content.
98     if (!firstChild() && !selfWillPaint())
99         return;
100 
101     PaintInfo childPaintInfo(paintInfo);
102 
103     childPaintInfo.context->save();
104 
105     // Let the RenderSVGViewportContainer subclass clip if necessary
106     applyViewportClip(childPaintInfo);
107 
108     applyTransformToPaintInfo(childPaintInfo, localToParentTransform());
109 
110     SVGResourceFilter* filter = 0;
111     FloatRect boundingBox = repaintRectInLocalCoordinates();
112     if (childPaintInfo.phase == PaintPhaseForeground)
113         prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
114 
115     childPaintInfo.paintingRoot = paintingRootForChildren(childPaintInfo);
116     for (RenderObject* child = firstChild(); child; child = child->nextSibling())
117         child->paint(childPaintInfo, 0, 0);
118 
119     if (paintInfo.phase == PaintPhaseForeground)
120         finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context);
121 
122     childPaintInfo.context->restore();
123 
124     // FIXME: This really should be drawn from local coordinates, but currently we hack it
125     // to avoid our clip killing our outline rect.  Thus we translate our
126     // outline rect into parent coords before drawing.
127     // FIXME: This means our focus ring won't share our rotation like it should.
128     // We should instead disable our clip during PaintPhaseOutline
129     IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates()));
130     if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE)
131         paintOutline(paintInfo.context, paintRectInParent.x(), paintRectInParent.y(), paintRectInParent.width(), paintRectInParent.height(), style());
132 }
133 
134 // addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call
addFocusRingRects(GraphicsContext * graphicsContext,int,int)135 void RenderSVGContainer::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
136 {
137     IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates()));
138     graphicsContext->addFocusRingRect(paintRectInParent);
139 }
140 
objectBoundingBox() const141 FloatRect RenderSVGContainer::objectBoundingBox() const
142 {
143     return computeContainerBoundingBox(this, false);
144 }
145 
146 // RenderSVGContainer is used for <g> elements which do not themselves have a
147 // width or height, so we union all of our child rects as our repaint rect.
repaintRectInLocalCoordinates() const148 FloatRect RenderSVGContainer::repaintRectInLocalCoordinates() const
149 {
150     FloatRect repaintRect = computeContainerBoundingBox(this, true);
151 
152     // A filter on this container can paint outside of the union of the child repaint rects
153     repaintRect.unite(filterBoundingBoxForRenderer(this));
154 
155     return repaintRect;
156 }
157 
nodeAtFloatPoint(const HitTestRequest & request,HitTestResult & result,const FloatPoint & pointInParent,HitTestAction hitTestAction)158 bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
159 {
160     // Give RenderSVGViewportContainer a chance to apply its viewport clip
161     if (!pointIsInsideViewportClip(pointInParent))
162         return false;
163 
164     FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent);
165 
166     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
167         if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) {
168             updateHitTestResult(result, roundedIntPoint(localPoint));
169             return true;
170         }
171     }
172 
173     // Spec: Only graphical elements can be targeted by the mouse, period.
174     // 16.4: "If there are no graphics elements whose relevant graphics content is under the pointer (i.e., there is no target element), the event is not dispatched."
175     return false;
176 }
177 
178 }
179 
180 #endif // ENABLE(SVG)
181 
182 // vim:ts=4:noet
183