WebCore/rendering/RenderSVGResource.cpp
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebCore/rendering/RenderSVGResource.cpp	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ *               2007 Rob Buis <buis@kde.org>
+ *               2008 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * 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
+ * along 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 "RenderSVGResource.h"
+
+#include "RenderSVGResourceClipper.h"
+#include "RenderSVGResourceContainer.h"
+#include "RenderSVGResourceFilter.h"
+#include "RenderSVGResourceMarker.h"
+#include "RenderSVGResourceMasker.h"
+#include "RenderSVGResourceSolidColor.h"
+#include "SVGURIReference.h"
+
+namespace WebCore {
+
+static inline void registerPendingResource(const AtomicString& id, const SVGPaint::SVGPaintType& paintType, const RenderObject* object)
+{
+    if (paintType != SVGPaint::SVG_PAINTTYPE_URI)
+        return;
+
+    SVGElement* svgElement = static_cast<SVGElement*>(object->node());
+    ASSERT(svgElement);
+    ASSERT(svgElement->isStyled());
+
+    object->document()->accessSVGExtensions()->addPendingResource(id, static_cast<SVGStyledElement*>(svgElement));
+}
+
+inline void RenderSVGResource::adjustColorForPseudoRules(const RenderStyle* style, bool useFillPaint, Color& color)
+{
+    if (style->insideLink() != InsideVisitedLink)
+        return;
+
+    RenderStyle* visitedStyle = style->getCachedPseudoStyle(VISITED_LINK);
+    SVGPaint* visitedPaint = useFillPaint ? visitedStyle->svgStyle()->fillPaint() : visitedStyle->svgStyle()->strokePaint();
+    if (visitedPaint->paintType() == SVGPaint::SVG_PAINTTYPE_URI)
+        return;
+        
+    Color visitedColor;
+    if (visitedPaint->paintType() == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR)
+        visitedColor = visitedStyle->color();
+    else
+        visitedColor = visitedPaint->color();
+
+    if (visitedColor.isValid())
+        color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha());
+}
+
+// FIXME: This method and strokePaintingResource() should be refactored, to share even more code
+RenderSVGResource* RenderSVGResource::fillPaintingResource(const RenderObject* object, const RenderStyle* style)
+{
+    ASSERT(object);
+    ASSERT(style);
+
+    const SVGRenderStyle* svgStyle = style->svgStyle();
+    if (!svgStyle || !svgStyle->hasFill())
+        return 0;
+
+    SVGPaint* fillPaint = svgStyle->fillPaint();
+    ASSERT(fillPaint);
+
+    RenderSVGResource* fillPaintingResource = 0;
+
+    SVGPaint::SVGPaintType paintType = fillPaint->paintType();
+    if (paintType == SVGPaint::SVG_PAINTTYPE_URI
+        || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) {
+        AtomicString id(SVGURIReference::getTarget(fillPaint->uri()));
+        fillPaintingResource = getRenderSVGResourceContainerById(object->document(), id);
+
+        if (!fillPaintingResource)
+            registerPendingResource(id, paintType, object);
+    }
+
+    if (paintType != SVGPaint::SVG_PAINTTYPE_URI && !fillPaintingResource) {
+        RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource();
+        fillPaintingResource = solidResource;
+
+        Color fillColor;
+        if (fillPaint->paintType() == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR)
+            fillColor = style->visitedDependentColor(CSSPropertyColor);
+        else
+            fillColor = fillPaint->color();
+
+        adjustColorForPseudoRules(style, true /* useFillPaint */, fillColor);
+
+        // FIXME: Ideally invalid colors would never get set on the RenderStyle and this could turn into an ASSERT
+        if (fillColor.isValid())
+            solidResource->setColor(fillColor);
+        else
+            fillPaintingResource = 0;
+    }
+
+    if (!fillPaintingResource) {
+        // default value (black), see bug 11017
+        RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource();
+        solidResource->setColor(Color::black);
+        fillPaintingResource = solidResource;
+    }
+
+    return fillPaintingResource;
+}
+
+RenderSVGResource* RenderSVGResource::strokePaintingResource(const RenderObject* object, const RenderStyle* style)
+{
+    ASSERT(object);
+    ASSERT(style);
+
+    const SVGRenderStyle* svgStyle = style->svgStyle();
+    if (!svgStyle || !svgStyle->hasStroke())
+        return 0;
+
+    SVGPaint* strokePaint = svgStyle->strokePaint();
+    ASSERT(strokePaint);
+
+    RenderSVGResource* strokePaintingResource = 0;
+    FloatRect objectBoundingBox = object->objectBoundingBox();
+
+    SVGPaint::SVGPaintType paintType = strokePaint->paintType();
+    if (!objectBoundingBox.isEmpty()
+        && (paintType == SVGPaint::SVG_PAINTTYPE_URI || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR)) {
+        AtomicString id(SVGURIReference::getTarget(strokePaint->uri()));
+        strokePaintingResource = getRenderSVGResourceContainerById(object->document(), id);
+
+        if (!strokePaintingResource)
+            registerPendingResource(id, paintType, object);
+    }
+
+    if (paintType != SVGPaint::SVG_PAINTTYPE_URI && !strokePaintingResource) {
+        RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource();
+        strokePaintingResource = solidResource;
+
+        Color strokeColor;
+        if (strokePaint->paintType() == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR)
+            strokeColor = style->visitedDependentColor(CSSPropertyColor);
+        else
+            strokeColor = strokePaint->color();
+
+        adjustColorForPseudoRules(style, false /* useFillPaint */, strokeColor);
+
+        // FIXME: Ideally invalid colors would never get set on the RenderStyle and this could turn into an ASSERT
+        if (strokeColor.isValid())
+            solidResource->setColor(strokeColor);
+        else
+            strokePaintingResource = 0;
+    }
+
+    if (!strokePaintingResource) {
+        // default value (black), see bug 11017
+        RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource();
+        solidResource->setColor(Color::black);
+        strokePaintingResource = solidResource;
+    }
+
+    return strokePaintingResource;
+}
+
+RenderSVGResourceSolidColor* RenderSVGResource::sharedSolidPaintingResource()
+{
+    static RenderSVGResourceSolidColor* s_sharedSolidPaintingResource = 0;
+    if (!s_sharedSolidPaintingResource)
+        s_sharedSolidPaintingResource = new RenderSVGResourceSolidColor;
+    return s_sharedSolidPaintingResource;
+}
+
+void RenderSVGResource::markForLayoutAndResourceInvalidation(RenderObject* object, bool needsBoundariesUpdate)
+{
+    ASSERT(object);
+    ASSERT(object->node());
+    ASSERT(object->node()->isSVGElement());
+
+    // Eventually mark the renderer needing a boundaries update
+    if (needsBoundariesUpdate)
+        object->setNeedsBoundariesUpdate();
+
+    markForLayoutAndParentResourceInvalidation(object);
+}
+
+static inline void invalidatePaintingResource(SVGPaint* paint, RenderObject* object)
+{
+    ASSERT(paint);
+
+    SVGPaint::SVGPaintType paintType = paint->paintType();
+    if (paintType != SVGPaint::SVG_PAINTTYPE_URI && paintType != SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR)
+        return;
+
+    AtomicString id(SVGURIReference::getTarget(paint->uri()));
+    if (RenderSVGResourceContainer* paintingResource = getRenderSVGResourceContainerById(object->document(), id))
+        paintingResource->invalidateClient(object);
+}
+
+void RenderSVGResource::invalidateAllResourcesOfRenderer(RenderObject* object)
+{
+    ASSERT(object);
+    ASSERT(object->style());
+
+    Document* document = object->document();
+    ASSERT(document);
+
+    const SVGRenderStyle* svgStyle = object->style()->svgStyle();
+    ASSERT(svgStyle);
+
+    // Masker
+    if (RenderSVGResourceMasker* masker = getRenderSVGResourceById<RenderSVGResourceMasker>(document, svgStyle->maskerResource()))
+        masker->invalidateClient(object);
+
+    // Clipper
+    if (RenderSVGResourceClipper* clipper = getRenderSVGResourceById<RenderSVGResourceClipper>(document, svgStyle->clipperResource()))
+        clipper->invalidateClient(object);
+
+    // Filter
+#if ENABLE(FILTERS)
+    if (RenderSVGResourceFilter* filter = getRenderSVGResourceById<RenderSVGResourceFilter>(document, svgStyle->filterResource()))
+        filter->invalidateClient(object);
+#endif
+
+    // Markers
+    if (RenderSVGResourceMarker* startMarker = getRenderSVGResourceById<RenderSVGResourceMarker>(document, svgStyle->markerStartResource()))
+        startMarker->invalidateClient(object);
+    if (RenderSVGResourceMarker* midMarker = getRenderSVGResourceById<RenderSVGResourceMarker>(document, svgStyle->markerMidResource()))
+        midMarker->invalidateClient(object);
+    if (RenderSVGResourceMarker* endMarker = getRenderSVGResourceById<RenderSVGResourceMarker>(document, svgStyle->markerEndResource()))
+        endMarker->invalidateClient(object);
+
+    // Gradients/Patterns
+    if (svgStyle->hasFill())
+        invalidatePaintingResource(svgStyle->fillPaint(), object);
+    if (svgStyle->hasStroke())
+        invalidatePaintingResource(svgStyle->strokePaint(), object);
+}
+
+void RenderSVGResource::markForLayoutAndParentResourceInvalidation(RenderObject* object, bool needsLayout)
+{
+    ASSERT(object);
+    if (needsLayout)
+        object->setNeedsLayout(true);
+
+    // Invalidate resources in ancestor chain, if needed.
+    RenderObject* current = object->parent();
+    while (current) {
+        if (current->isSVGResourceContainer()) 
+            current->toRenderSVGResourceContainer()->invalidateClients();
+
+        current = current->parent();
+    }
+}
+
+}
+
+#endif