/* | |
Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> | |
2004, 2005, 2007, 2008 Rob Buis <buis@kde.org> | |
2007 Eric Seidel <eric@webkit.org> | |
Copyright (C) 2009 Google, Inc. All rights reserved. | |
2009 Dirk Schulze <krit@webkit.org> | |
This library is free software; you can redistribute it and/or | |
modify it under the terms of the GNU Library General Public | |
License as published by the Free Software Foundation; either | |
version 2 of the License, or (at your option) any later version. | |
This library is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
Library General Public License for more details. | |
You should have received a copy of the GNU Library General Public License | |
aint with this library; see the file COPYING.LIB. If not, write to | |
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
Boston, MA 02110-1301, USA. | |
*/ | |
#include "config.h" | |
#if ENABLE(SVG) | |
#include "RenderSVGContainer.h" | |
#include "GraphicsContext.h" | |
#include "RenderView.h" | |
#include "SVGRenderSupport.h" | |
#include "SVGResourceFilter.h" | |
#include "SVGStyledElement.h" | |
namespace WebCore { | |
RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node) | |
: RenderSVGModelObject(node) | |
, m_drawsContents(true) | |
{ | |
} | |
bool RenderSVGContainer::drawsContents() const | |
{ | |
return m_drawsContents; | |
} | |
void RenderSVGContainer::setDrawsContents(bool drawsContents) | |
{ | |
m_drawsContents = drawsContents; | |
} | |
void RenderSVGContainer::layout() | |
{ | |
ASSERT(needsLayout()); | |
ASSERT(!view()->layoutStateEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree. | |
calcViewport(); // Allow RenderSVGViewportContainer to update its viewport | |
LayoutRepainter repainter(*this, checkForRepaintDuringLayout() || selfWillPaint()); | |
calculateLocalTransform(); // Allow RenderSVGTransformableContainer to update its transform | |
layoutChildren(this, selfNeedsLayout()); | |
repainter.repaintAfterLayout(); | |
setNeedsLayout(false); | |
} | |
bool RenderSVGContainer::selfWillPaint() const | |
{ | |
#if ENABLE(FILTERS) | |
const SVGRenderStyle* svgStyle = style()->svgStyle(); | |
SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter(), this); | |
if (filter) | |
return true; | |
#endif | |
return false; | |
} | |
void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int) | |
{ | |
if (paintInfo.context->paintingDisabled() || !drawsContents()) | |
return; | |
// Spec: groups w/o children still may render filter content. | |
if (!firstChild() && !selfWillPaint()) | |
return; | |
PaintInfo childPaintInfo(paintInfo); | |
childPaintInfo.context->save(); | |
// Let the RenderSVGViewportContainer subclass clip if necessary | |
applyViewportClip(childPaintInfo); | |
applyTransformToPaintInfo(childPaintInfo, localToParentTransform()); | |
SVGResourceFilter* filter = 0; | |
FloatRect boundingBox = repaintRectInLocalCoordinates(); | |
bool continueRendering = true; | |
if (childPaintInfo.phase == PaintPhaseForeground) | |
continueRendering = prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter); | |
if (continueRendering) { | |
childPaintInfo.paintingRoot = paintingRootForChildren(childPaintInfo); | |
for (RenderObject* child = firstChild(); child; child = child->nextSibling()) | |
child->paint(childPaintInfo, 0, 0); | |
} | |
if (paintInfo.phase == PaintPhaseForeground) | |
finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context); | |
childPaintInfo.context->restore(); | |
// FIXME: This really should be drawn from local coordinates, but currently we hack it | |
// to avoid our clip killing our outline rect. Thus we translate our | |
// outline rect into parent coords before drawing. | |
// FIXME: This means our focus ring won't share our rotation like it should. | |
// We should instead disable our clip during PaintPhaseOutline | |
IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates())); | |
if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE) | |
paintOutline(paintInfo.context, paintRectInParent.x(), paintRectInParent.y(), paintRectInParent.width(), paintRectInParent.height(), style()); | |
} | |
// addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call | |
void RenderSVGContainer::addFocusRingRects(Vector<IntRect>& rects, int, int) | |
{ | |
IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates())); | |
if (!paintRectInParent.isEmpty()) | |
rects.append(paintRectInParent); | |
} | |
FloatRect RenderSVGContainer::objectBoundingBox() const | |
{ | |
return computeContainerBoundingBox(this, false); | |
} | |
FloatRect RenderSVGContainer::strokeBoundingBox() const | |
{ | |
return computeContainerBoundingBox(this, true); | |
} | |
// RenderSVGContainer is used for <g> elements which do not themselves have a | |
// width or height, so we union all of our child rects as our repaint rect. | |
FloatRect RenderSVGContainer::repaintRectInLocalCoordinates() const | |
{ | |
FloatRect repaintRect = computeContainerBoundingBox(this, true); | |
FloatRect rect = filterBoundingBoxForRenderer(this); | |
if (!rect.isEmpty()) | |
repaintRect = rect; | |
rect = clipperBoundingBoxForRenderer(this); | |
if (!rect.isEmpty()) | |
repaintRect.intersect(rect); | |
rect = maskerBoundingBoxForRenderer(this); | |
if (!rect.isEmpty()) | |
repaintRect.intersect(rect); | |
style()->svgStyle()->inflateForShadow(repaintRect); | |
return repaintRect; | |
} | |
bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) | |
{ | |
// Give RenderSVGViewportContainer a chance to apply its viewport clip | |
if (!pointIsInsideViewportClip(pointInParent)) | |
return false; | |
FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); | |
for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { | |
if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) { | |
updateHitTestResult(result, roundedIntPoint(localPoint)); | |
return true; | |
} | |
} | |
// Spec: Only graphical elements can be targeted by the mouse, period. | |
// 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." | |
return false; | |
} | |
} | |
#endif // ENABLE(SVG) |