diff -r 000000000000 -r 4f2f89ce4247 WebCore/rendering/RenderSVGResource.cpp --- /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 + * 2007 Rob Buis + * 2008 Dirk Schulze + * 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(object->node()); + ASSERT(svgElement); + ASSERT(svgElement->isStyled()); + + object->document()->accessSVGExtensions()->addPendingResource(id, static_cast(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(document, svgStyle->maskerResource())) + masker->invalidateClient(object); + + // Clipper + if (RenderSVGResourceClipper* clipper = getRenderSVGResourceById(document, svgStyle->clipperResource())) + clipper->invalidateClient(object); + + // Filter +#if ENABLE(FILTERS) + if (RenderSVGResourceFilter* filter = getRenderSVGResourceById(document, svgStyle->filterResource())) + filter->invalidateClient(object); +#endif + + // Markers + if (RenderSVGResourceMarker* startMarker = getRenderSVGResourceById(document, svgStyle->markerStartResource())) + startMarker->invalidateClient(object); + if (RenderSVGResourceMarker* midMarker = getRenderSVGResourceById(document, svgStyle->markerMidResource())) + midMarker->invalidateClient(object); + if (RenderSVGResourceMarker* endMarker = getRenderSVGResourceById(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