summaryrefslogtreecommitdiffstats
path: root/WebCore/rendering/SVGRenderSupport.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/rendering/SVGRenderSupport.cpp')
-rw-r--r--WebCore/rendering/SVGRenderSupport.cpp125
1 files changed, 101 insertions, 24 deletions
diff --git a/WebCore/rendering/SVGRenderSupport.cpp b/WebCore/rendering/SVGRenderSupport.cpp
index fb6866f..079a36e 100644
--- a/WebCore/rendering/SVGRenderSupport.cpp
+++ b/WebCore/rendering/SVGRenderSupport.cpp
@@ -2,7 +2,8 @@
* Copyright (C) 2007, 2008 Rob Buis <buis@kde.org>
* (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
* (C) 2007 Eric Seidel <eric@webkit.org>
- * Copyright (C) 2009 Google, Inc. All rights reserved.
+ * (C) 2009 Google, Inc. All rights reserved.
+ * (C) 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
@@ -26,6 +27,7 @@
#if ENABLE(SVG)
#include "SVGRenderSupport.h"
+#include "AffineTransform.h"
#include "ImageBuffer.h"
#include "RenderObject.h"
#include "RenderSVGContainer.h"
@@ -36,11 +38,14 @@
#include "SVGStyledElement.h"
#include "SVGURIReference.h"
#include "TransformState.h"
-#include "TransformationMatrix.h"
#include <wtf/UnusedParam.h>
namespace WebCore {
+SVGRenderBase::~SVGRenderBase()
+{
+}
+
IntRect SVGRenderBase::clippedOverflowRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer)
{
// Return early for any cases where we don't actually paint
@@ -56,6 +61,8 @@ IntRect SVGRenderBase::clippedOverflowRectForRepaint(RenderObject* object, Rende
void SVGRenderBase::computeRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
{
+ object->style()->svgStyle()->inflateForShadow(repaintRect);
+
// Translate to coords in our parent renderer, and then call computeRectForRepaint on our parent
repaintRect = object->localToParentTransform().mapRect(repaintRect);
object->parent()->computeRectForRepaint(repaintContainer, repaintRect, fixed);
@@ -64,12 +71,12 @@ void SVGRenderBase::computeRectForRepaint(RenderObject* object, RenderBoxModelOb
void SVGRenderBase::mapLocalToContainer(const RenderObject* object, RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState)
{
ASSERT(!fixed); // We should have no fixed content in the SVG rendering tree.
- ASSERT(useTransforms); // mapping a point through SVG w/o respecting trasnforms is useless.
+ ASSERT(useTransforms); // Mapping a point through SVG w/o respecting transforms is useless.
transformState.applyTransform(object->localToParentTransform());
object->parent()->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
}
-void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& boundingBox, SVGResourceFilter*& filter, SVGResourceFilter* rootFilter)
+bool SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& repaintRect, SVGResourceFilter*& filter, SVGResourceFilter* rootFilter)
{
#if !ENABLE(FILTERS)
UNUSED_PARAM(filter);
@@ -90,10 +97,16 @@ void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject
// Setup transparency layers before setting up filters!
float opacity = style->opacity();
if (opacity < 1.0f) {
- paintInfo.context->clip(enclosingIntRect(boundingBox));
+ paintInfo.context->clip(repaintRect);
paintInfo.context->beginTransparencyLayer(opacity);
}
+ if (ShadowData* shadow = svgStyle->shadow()) {
+ paintInfo.context->clip(repaintRect);
+ paintInfo.context->setShadow(IntSize(shadow->x, shadow->y), shadow->blur, shadow->color, style->colorSpace());
+ paintInfo.context->beginTransparencyLayer(1.0f);
+ }
+
#if ENABLE(FILTERS)
AtomicString filterId(svgStyle->filter());
#endif
@@ -104,7 +117,7 @@ void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject
Document* document = object->document();
#if ENABLE(FILTERS)
- SVGResourceFilter* newFilter = getFilterById(document, filterId);
+ SVGResourceFilter* newFilter = getFilterById(document, filterId, object);
if (newFilter == rootFilter) {
// Catch <text filter="url(#foo)">Test<tspan filter="url(#foo)">123</tspan></text>.
// The filter is NOT meant to be applied twice in that case!
@@ -114,28 +127,32 @@ void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject
filter = newFilter;
#endif
- SVGResourceClipper* clipper = getClipperById(document, clipperId);
- SVGResourceMasker* masker = getMaskerById(document, maskerId);
+ SVGResourceClipper* clipper = getClipperById(document, clipperId, object);
+ SVGResourceMasker* masker = getMaskerById(document, maskerId, object);
+
+ if (masker) {
+ masker->addClient(styledElement);
+ if (!masker->applyMask(paintInfo.context, object))
+ return false;
+ } else if (!maskerId.isEmpty())
+ svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement);
+
+ if (clipper) {
+ clipper->addClient(styledElement);
+ clipper->applyClip(paintInfo.context, object->objectBoundingBox());
+ } else if (!clipperId.isEmpty())
+ svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement);
#if ENABLE(FILTERS)
if (filter) {
filter->addClient(styledElement);
- filter->prepareFilter(paintInfo.context, object);
+ if (!filter->prepareFilter(paintInfo.context, object))
+ return false;
} else if (!filterId.isEmpty())
svgElement->document()->accessSVGExtensions()->addPendingResource(filterId, styledElement);
#endif
- if (clipper) {
- clipper->addClient(styledElement);
- clipper->applyClip(paintInfo.context, boundingBox);
- } else if (!clipperId.isEmpty())
- svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement);
-
- if (masker) {
- masker->addClient(styledElement);
- masker->applyMask(paintInfo.context, boundingBox);
- } else if (!maskerId.isEmpty())
- svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement);
+ return true;
}
void SVGRenderBase::finishRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, SVGResourceFilter*& filter, GraphicsContext* savedContext)
@@ -160,6 +177,11 @@ void SVGRenderBase::finishRenderSVGContent(RenderObject* object, RenderObject::P
float opacity = style->opacity();
if (opacity < 1.0f)
paintInfo.context->endTransparencyLayer();
+
+ // This needs to be done separately from opacity, because if both properties are set,
+ // then the transparency layers are nested.
+ if (style->svgStyle()->shadow())
+ paintInfo.context->endTransparencyLayer();
}
void renderSubtreeToImage(ImageBuffer* image, RenderObject* item)
@@ -215,19 +237,74 @@ FloatRect SVGRenderBase::computeContainerBoundingBox(const RenderObject* contain
return boundingBox;
}
-FloatRect SVGRenderBase::filterBoundingBoxForRenderer(const RenderObject* object)
+void SVGRenderBase::layoutChildren(RenderObject* start, bool selfNeedsLayout)
+{
+ for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
+ // Only force our kids to layout if we're being asked to relayout as a result of a parent changing
+ // FIXME: We should be able to skip relayout of non-relative kids when only bounds size has changed
+ // that's a possible future optimization using LayoutState
+ // http://bugs.webkit.org/show_bug.cgi?id=15391
+ bool needsLayout = selfNeedsLayout;
+ if (!needsLayout) {
+ if (SVGElement* element = child->node()->isSVGElement() ? static_cast<SVGElement*>(child->node()) : 0) {
+ if (element->isStyled())
+ needsLayout = static_cast<SVGStyledElement*>(element)->hasRelativeValues();
+ }
+ }
+
+ if (needsLayout)
+ child->setNeedsLayout(true, false);
+
+ child->layoutIfNeeded();
+ ASSERT(!child->needsLayout());
+ }
+}
+
+bool SVGRenderBase::isOverflowHidden(const RenderObject* object)
+{
+ // SVG doesn't support independent x/y overflow
+ ASSERT(object->style()->overflowX() == object->style()->overflowY());
+
+ // OSCROLL is never set for SVG - see CSSStyleSelector::adjustRenderStyle
+ ASSERT(object->style()->overflowX() != OSCROLL);
+
+ // RenderSVGRoot should never query for overflow state - it should always clip itself to the initial viewport size.
+ ASSERT(!object->isRoot());
+
+ return object->style()->overflowX() == OHIDDEN;
+}
+
+FloatRect SVGRenderBase::filterBoundingBoxForRenderer(const RenderObject* object) const
{
#if ENABLE(FILTERS)
- SVGResourceFilter* filter = getFilterById(object->document(), object->style()->svgStyle()->filter());
+ SVGResourceFilter* filter = getFilterById(object->document(), object->style()->svgStyle()->filter(), object);
if (filter)
- return filter->filterBBoxForItemBBox(object->objectBoundingBox());
+ return filter->filterBoundingBox(object->objectBoundingBox());
#else
UNUSED_PARAM(object);
#endif
return FloatRect();
}
-void applyTransformToPaintInfo(RenderObject::PaintInfo& paintInfo, const TransformationMatrix& localToAncestorTransform)
+FloatRect SVGRenderBase::clipperBoundingBoxForRenderer(const RenderObject* object) const
+{
+ SVGResourceClipper* clipper = getClipperById(object->document(), object->style()->svgStyle()->clipPath(), object);
+ if (clipper)
+ return clipper->clipperBoundingBox(object->objectBoundingBox());
+
+ return FloatRect();
+}
+
+FloatRect SVGRenderBase::maskerBoundingBoxForRenderer(const RenderObject* object) const
+{
+ SVGResourceMasker* masker = getMaskerById(object->document(), object->style()->svgStyle()->maskElement(), object);
+ if (masker)
+ return masker->maskerBoundingBox(object->objectBoundingBox());
+
+ return FloatRect();
+}
+
+void applyTransformToPaintInfo(RenderObject::PaintInfo& paintInfo, const AffineTransform& localToAncestorTransform)
{
if (localToAncestorTransform.isIdentity())
return;