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 "RenderView.h" 31#include "SVGRenderSupport.h" 32#include "SVGResourceFilter.h" 33#include "SVGStyledElement.h" 34 35namespace WebCore { 36 37RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node) 38 : RenderSVGModelObject(node) 39 , m_drawsContents(true) 40{ 41} 42 43bool RenderSVGContainer::drawsContents() const 44{ 45 return m_drawsContents; 46} 47 48void RenderSVGContainer::setDrawsContents(bool drawsContents) 49{ 50 m_drawsContents = drawsContents; 51} 52 53void RenderSVGContainer::layout() 54{ 55 ASSERT(needsLayout()); 56 ASSERT(!view()->layoutStateEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree. 57 58 calcViewport(); // Allow RenderSVGViewportContainer to update its viewport 59 60 LayoutRepainter repainter(*this, checkForRepaintDuringLayout() || selfWillPaint()); 61 calculateLocalTransform(); // Allow RenderSVGTransformableContainer to update its transform 62 63 layoutChildren(this, selfNeedsLayout()); 64 repainter.repaintAfterLayout(); 65 66 setNeedsLayout(false); 67} 68 69bool RenderSVGContainer::selfWillPaint() const 70{ 71#if ENABLE(FILTERS) 72 const SVGRenderStyle* svgStyle = style()->svgStyle(); 73 SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter(), this); 74 if (filter) 75 return true; 76#endif 77 return false; 78} 79 80void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int) 81{ 82 if (paintInfo.context->paintingDisabled() || !drawsContents()) 83 return; 84 85 // Spec: groups w/o children still may render filter content. 86 if (!firstChild() && !selfWillPaint()) 87 return; 88 89 PaintInfo childPaintInfo(paintInfo); 90 91 childPaintInfo.context->save(); 92 93 // Let the RenderSVGViewportContainer subclass clip if necessary 94 applyViewportClip(childPaintInfo); 95 96 applyTransformToPaintInfo(childPaintInfo, localToParentTransform()); 97 98 SVGResourceFilter* filter = 0; 99 FloatRect boundingBox = repaintRectInLocalCoordinates(); 100 101 bool continueRendering = true; 102 if (childPaintInfo.phase == PaintPhaseForeground) 103 continueRendering = prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter); 104 105 if (continueRendering) { 106 childPaintInfo.paintingRoot = paintingRootForChildren(childPaintInfo); 107 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) 108 child->paint(childPaintInfo, 0, 0); 109 } 110 111 if (paintInfo.phase == PaintPhaseForeground) 112 finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context); 113 114 childPaintInfo.context->restore(); 115 116 // FIXME: This really should be drawn from local coordinates, but currently we hack it 117 // to avoid our clip killing our outline rect. Thus we translate our 118 // outline rect into parent coords before drawing. 119 // FIXME: This means our focus ring won't share our rotation like it should. 120 // We should instead disable our clip during PaintPhaseOutline 121 IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates())); 122 if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE) 123 paintOutline(paintInfo.context, paintRectInParent.x(), paintRectInParent.y(), paintRectInParent.width(), paintRectInParent.height(), style()); 124} 125 126// addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call 127void RenderSVGContainer::addFocusRingRects(Vector<IntRect>& rects, int, int) 128{ 129 IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates())); 130 if (!paintRectInParent.isEmpty()) 131 rects.append(paintRectInParent); 132} 133 134FloatRect RenderSVGContainer::objectBoundingBox() const 135{ 136 return computeContainerBoundingBox(this, false); 137} 138 139FloatRect RenderSVGContainer::strokeBoundingBox() const 140{ 141 return computeContainerBoundingBox(this, true); 142} 143 144// RenderSVGContainer is used for <g> elements which do not themselves have a 145// width or height, so we union all of our child rects as our repaint rect. 146FloatRect RenderSVGContainer::repaintRectInLocalCoordinates() const 147{ 148 FloatRect repaintRect = computeContainerBoundingBox(this, true); 149 150 FloatRect rect = filterBoundingBoxForRenderer(this); 151 if (!rect.isEmpty()) 152 repaintRect = rect; 153 154 rect = clipperBoundingBoxForRenderer(this); 155 if (!rect.isEmpty()) 156 repaintRect.intersect(rect); 157 158 rect = maskerBoundingBoxForRenderer(this); 159 if (!rect.isEmpty()) 160 repaintRect.intersect(rect); 161 162 style()->svgStyle()->inflateForShadow(repaintRect); 163 164 return repaintRect; 165} 166 167bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) 168{ 169 // Give RenderSVGViewportContainer a chance to apply its viewport clip 170 if (!pointIsInsideViewportClip(pointInParent)) 171 return false; 172 173 FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); 174 175 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { 176 if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) { 177 updateHitTestResult(result, roundedIntPoint(localPoint)); 178 return true; 179 } 180 } 181 182 // Spec: Only graphical elements can be targeted by the mouse, period. 183 // 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." 184 return false; 185} 186 187} 188 189#endif // ENABLE(SVG) 190