|
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 2009 Dirk Schulze <krit@webkit.org> |
|
7 |
|
8 This library is free software; you can redistribute it and/or |
|
9 modify it under the terms of the GNU Library General Public |
|
10 License as published by the Free Software Foundation; either |
|
11 version 2 of the License, or (at your option) any later version. |
|
12 |
|
13 This library is distributed in the hope that it will be useful, |
|
14 but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
16 Library General Public License for more details. |
|
17 |
|
18 You should have received a copy of the GNU Library General Public License |
|
19 aint with this library; see the file COPYING.LIB. If not, write to |
|
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|
21 Boston, MA 02110-1301, USA. |
|
22 */ |
|
23 |
|
24 #include "config.h" |
|
25 |
|
26 #if ENABLE(SVG) |
|
27 #include "RenderSVGContainer.h" |
|
28 |
|
29 #include "GraphicsContext.h" |
|
30 #include "RenderSVGResourceFilter.h" |
|
31 #include "RenderView.h" |
|
32 #include "SVGRenderSupport.h" |
|
33 #include "SVGStyledElement.h" |
|
34 |
|
35 namespace WebCore { |
|
36 |
|
37 RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node) |
|
38 : RenderSVGModelObject(node) |
|
39 , m_drawsContents(true) |
|
40 { |
|
41 } |
|
42 |
|
43 void RenderSVGContainer::layout() |
|
44 { |
|
45 ASSERT(needsLayout()); |
|
46 |
|
47 // RenderSVGRoot disables layoutState for the SVG rendering tree. |
|
48 ASSERT(!view()->layoutStateEnabled()); |
|
49 |
|
50 // Allow RenderSVGViewportContainer to update its viewport. |
|
51 calcViewport(); |
|
52 |
|
53 LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout()); |
|
54 |
|
55 // Allow RenderSVGTransformableContainer to update its transform. |
|
56 calculateLocalTransform(); |
|
57 |
|
58 SVGRenderSupport::layoutChildren(this, selfNeedsLayout()); |
|
59 |
|
60 // Invalidate all resources of this client, if we changed something. |
|
61 if (m_everHadLayout && selfNeedsLayout()) |
|
62 RenderSVGResource::invalidateAllResourcesOfRenderer(this); |
|
63 |
|
64 repainter.repaintAfterLayout(); |
|
65 setNeedsLayout(false); |
|
66 } |
|
67 |
|
68 bool RenderSVGContainer::selfWillPaint() const |
|
69 { |
|
70 #if ENABLE(FILTERS) |
|
71 const SVGRenderStyle* svgStyle = style()->svgStyle(); |
|
72 RenderSVGResourceFilter* filter = getRenderSVGResourceById<RenderSVGResourceFilter>(document(), svgStyle->filterResource()); |
|
73 if (filter) |
|
74 return true; |
|
75 #endif |
|
76 return false; |
|
77 } |
|
78 |
|
79 void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int) |
|
80 { |
|
81 if (paintInfo.context->paintingDisabled() || !drawsContents()) |
|
82 return; |
|
83 |
|
84 // Spec: groups w/o children still may render filter content. |
|
85 if (!firstChild() && !selfWillPaint()) |
|
86 return; |
|
87 |
|
88 PaintInfo childPaintInfo(paintInfo); |
|
89 childPaintInfo.context->save(); |
|
90 |
|
91 // Let the RenderSVGViewportContainer subclass clip if necessary |
|
92 applyViewportClip(childPaintInfo); |
|
93 |
|
94 childPaintInfo.applyTransform(localToParentTransform()); |
|
95 |
|
96 bool continueRendering = true; |
|
97 if (childPaintInfo.phase == PaintPhaseForeground) |
|
98 continueRendering = SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo); |
|
99 |
|
100 if (continueRendering) { |
|
101 childPaintInfo.updatePaintingRootForChildren(this); |
|
102 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) |
|
103 child->paint(childPaintInfo, 0, 0); |
|
104 } |
|
105 |
|
106 if (paintInfo.phase == PaintPhaseForeground) |
|
107 SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, paintInfo.context); |
|
108 |
|
109 childPaintInfo.context->restore(); |
|
110 |
|
111 // FIXME: This really should be drawn from local coordinates, but currently we hack it |
|
112 // to avoid our clip killing our outline rect. Thus we translate our |
|
113 // outline rect into parent coords before drawing. |
|
114 // FIXME: This means our focus ring won't share our rotation like it should. |
|
115 // We should instead disable our clip during PaintPhaseOutline |
|
116 if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE) { |
|
117 IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates())); |
|
118 paintOutline(paintInfo.context, paintRectInParent.x(), paintRectInParent.y(), paintRectInParent.width(), paintRectInParent.height()); |
|
119 } |
|
120 } |
|
121 |
|
122 // addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call |
|
123 void RenderSVGContainer::addFocusRingRects(Vector<IntRect>& rects, int, int) |
|
124 { |
|
125 IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates())); |
|
126 if (!paintRectInParent.isEmpty()) |
|
127 rects.append(paintRectInParent); |
|
128 } |
|
129 |
|
130 FloatRect RenderSVGContainer::objectBoundingBox() const |
|
131 { |
|
132 return SVGRenderSupport::computeContainerBoundingBox(this, SVGRenderSupport::ObjectBoundingBox); |
|
133 } |
|
134 |
|
135 FloatRect RenderSVGContainer::strokeBoundingBox() const |
|
136 { |
|
137 return SVGRenderSupport::computeContainerBoundingBox(this, SVGRenderSupport::StrokeBoundingBox); |
|
138 } |
|
139 |
|
140 FloatRect RenderSVGContainer::repaintRectInLocalCoordinates() const |
|
141 { |
|
142 FloatRect repaintRect = SVGRenderSupport::computeContainerBoundingBox(this, SVGRenderSupport::RepaintBoundingBox); |
|
143 SVGRenderSupport::intersectRepaintRectWithResources(this, repaintRect); |
|
144 return repaintRect; |
|
145 } |
|
146 |
|
147 bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) |
|
148 { |
|
149 // Give RenderSVGViewportContainer a chance to apply its viewport clip |
|
150 if (!pointIsInsideViewportClip(pointInParent)) |
|
151 return false; |
|
152 |
|
153 FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); |
|
154 |
|
155 if (!SVGRenderSupport::pointInClippingArea(this, localPoint)) |
|
156 return false; |
|
157 |
|
158 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { |
|
159 if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) { |
|
160 updateHitTestResult(result, roundedIntPoint(localPoint)); |
|
161 return true; |
|
162 } |
|
163 } |
|
164 |
|
165 // Spec: Only graphical elements can be targeted by the mouse, period. |
|
166 // 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." |
|
167 return false; |
|
168 } |
|
169 |
|
170 } |
|
171 |
|
172 #endif // ENABLE(SVG) |