summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/rendering/svg
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-05-13 16:23:25 +0100
committerBen Murdoch <benm@google.com>2011-05-16 11:35:02 +0100
commit65f03d4f644ce73618e5f4f50dd694b26f55ae12 (patch)
treef478babb801e720de7bfaee23443ffe029f58731 /Source/WebCore/rendering/svg
parent47de4a2fb7262c7ebdb9cd133ad2c54c187454d0 (diff)
downloadexternal_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.zip
external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.gz
external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.bz2
Merge WebKit at r75993: Initial merge by git.
Change-Id: I602bbdc3974787a3b0450456a30a7868286921c3
Diffstat (limited to 'Source/WebCore/rendering/svg')
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp75
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGBlock.cpp104
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGBlock.h49
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGContainer.cpp184
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGContainer.h101
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp173
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGForeignObject.h75
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp80
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGGradientStop.h67
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp59
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGHiddenContainer.h55
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGImage.cpp195
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGImage.h99
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGInline.cpp1
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGInline.h5
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGInlineText.cpp1
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGInlineText.h5
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGModelObject.cpp117
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGModelObject.h76
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGPath.cpp46
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGPath.h42
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResource.cpp161
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResource.h89
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp349
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceClipper.h78
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp192
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceContainer.h94
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp328
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceFilter.h93
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp106
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h58
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp281
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceGradient.h77
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp66
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.h54
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp176
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceMarker.h82
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp223
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceMasker.h70
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp292
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourcePattern.h75
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp71
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.h54
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp92
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.h55
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGRoot.cpp361
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGRoot.h121
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp108
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.h54
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGTSpan.cpp3
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGTSpan.h5
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGText.cpp1
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGText.h1
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGTextPath.cpp3
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGTextPath.h3
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp66
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h47
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp93
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGViewportContainer.h66
-rw-r--r--Source/WebCore/rendering/svg/SVGImageBufferTools.cpp128
-rw-r--r--Source/WebCore/rendering/svg/SVGImageBufferTools.h53
-rw-r--r--Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp5
-rw-r--r--Source/WebCore/rendering/svg/SVGInlineFlowBox.h5
-rw-r--r--Source/WebCore/rendering/svg/SVGInlineTextBox.cpp3
-rw-r--r--Source/WebCore/rendering/svg/SVGInlineTextBox.h3
-rw-r--r--Source/WebCore/rendering/svg/SVGMarkerData.h134
-rw-r--r--Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp123
-rw-r--r--Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h74
-rw-r--r--Source/WebCore/rendering/svg/SVGRenderSupport.cpp351
-rw-r--r--Source/WebCore/rendering/svg/SVGRenderSupport.h83
-rw-r--r--Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp748
-rw-r--r--Source/WebCore/rendering/svg/SVGRenderTreeAsText.h95
-rw-r--r--Source/WebCore/rendering/svg/SVGResources.cpp684
-rw-r--r--Source/WebCore/rendering/svg/SVGResources.h179
-rw-r--r--Source/WebCore/rendering/svg/SVGResourcesCache.cpp165
-rw-r--r--Source/WebCore/rendering/svg/SVGResourcesCache.h65
-rw-r--r--Source/WebCore/rendering/svg/SVGResourcesCycleSolver.cpp213
-rw-r--r--Source/WebCore/rendering/svg/SVGResourcesCycleSolver.h51
-rw-r--r--Source/WebCore/rendering/svg/SVGRootInlineBox.cpp1
-rw-r--r--Source/WebCore/rendering/svg/SVGRootInlineBox.h5
-rw-r--r--Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp90
-rw-r--r--Source/WebCore/rendering/svg/SVGShadowTreeElements.h67
-rw-r--r--Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp3
-rw-r--r--Source/WebCore/rendering/svg/SVGTextQuery.cpp34
-rw-r--r--Source/WebCore/rendering/svg/SVGTextQuery.h34
85 files changed, 9035 insertions, 118 deletions
diff --git a/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp b/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp
new file mode 100644
index 0000000..835bce8
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2009, 2010 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build.
+
+#include "RenderSVGBlock.cpp"
+#include "RenderSVGContainer.cpp"
+#include "RenderSVGForeignObject.cpp"
+#include "RenderSVGGradientStop.cpp"
+#include "RenderSVGHiddenContainer.cpp"
+#include "RenderSVGImage.cpp"
+#include "RenderSVGInline.cpp"
+#include "RenderSVGInlineText.cpp"
+#include "RenderSVGModelObject.cpp"
+#include "RenderSVGResource.cpp"
+#include "RenderSVGResourceClipper.cpp"
+#include "RenderSVGResourceContainer.cpp"
+#include "RenderSVGResourceFilter.cpp"
+#include "RenderSVGResourceFilterPrimitive.cpp"
+#include "RenderSVGResourceGradient.cpp"
+#include "RenderSVGResourceLinearGradient.cpp"
+#include "RenderSVGResourceMarker.cpp"
+#include "RenderSVGResourceMasker.cpp"
+#include "RenderSVGResourcePattern.cpp"
+#include "RenderSVGResourceRadialGradient.cpp"
+#include "RenderSVGResourceSolidColor.cpp"
+#include "RenderSVGRoot.cpp"
+#include "RenderSVGShadowTreeRootContainer.cpp"
+#include "RenderSVGTSpan.cpp"
+#include "RenderSVGText.cpp"
+#include "RenderSVGTextPath.cpp"
+#include "RenderSVGTransformableContainer.cpp"
+#include "RenderSVGViewportContainer.cpp"
+#include "SVGImageBufferTools.cpp"
+#include "SVGInlineFlowBox.cpp"
+#include "SVGInlineTextBox.cpp"
+#include "SVGMarkerLayoutInfo.cpp"
+#include "SVGRenderSupport.cpp"
+#include "SVGRenderTreeAsText.cpp"
+#include "SVGResources.cpp"
+#include "SVGResourcesCache.cpp"
+#include "SVGResourcesCycleSolver.cpp"
+#include "SVGRootInlineBox.cpp"
+#include "SVGShadowTreeElements.cpp"
+#include "SVGTextChunk.cpp"
+#include "SVGTextChunkBuilder.cpp"
+#include "SVGTextLayoutAttributes.cpp"
+#include "SVGTextLayoutAttributesBuilder.cpp"
+#include "SVGTextLayoutEngine.cpp"
+#include "SVGTextLayoutEngineBaseline.cpp"
+#include "SVGTextLayoutEngineSpacing.cpp"
+#include "SVGTextMetrics.cpp"
+#include "SVGTextQuery.cpp"
diff --git a/Source/WebCore/rendering/svg/RenderSVGBlock.cpp b/Source/WebCore/rendering/svg/RenderSVGBlock.cpp
new file mode 100644
index 0000000..ed8e24e
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGBlock.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.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 "RenderSVGBlock.h"
+
+#include "RenderSVGResource.h"
+#include "SVGElement.h"
+
+namespace WebCore {
+
+RenderSVGBlock::RenderSVGBlock(SVGElement* node)
+ : RenderBlock(node)
+{
+}
+
+void RenderSVGBlock::setStyle(PassRefPtr<RenderStyle> style)
+{
+ RefPtr<RenderStyle> useStyle = style;
+
+ // SVG text layout code expects us to be a block-level style element.
+ if (useStyle->isDisplayInlineType()) {
+ RefPtr<RenderStyle> newStyle = RenderStyle::create();
+ newStyle->inheritFrom(useStyle.get());
+ newStyle->setDisplay(BLOCK);
+ useStyle = newStyle.release();
+ }
+
+ RenderBlock::setStyle(useStyle.release());
+}
+
+void RenderSVGBlock::updateBoxModelInfoFromStyle()
+{
+ RenderBlock::updateBoxModelInfoFromStyle();
+
+ // RenderSVGlock, used by Render(SVGText|ForeignObject), is not allowed to call setHasOverflowClip(true).
+ // RenderBlock assumes a layer to be present when the overflow clip functionality is requested. Both
+ // Render(SVGText|ForeignObject) return 'false' on 'requiresLayer'. Fine for RenderSVGText.
+ //
+ // If we want to support overflow rules for <foreignObject> we can choose between two solutions:
+ // a) make RenderSVGForeignObject require layers and SVG layer aware
+ // b) reactor overflow logic out of RenderLayer (as suggested by dhyatt), which is a large task
+ //
+ // Until this is resolved, disable overflow support. Opera/FF don't support it as well at the moment (Feb 2010).
+ //
+ // Note: This does NOT affect overflow handling on outer/inner <svg> elements - this is handled
+ // manually by RenderSVGRoot - which owns the documents enclosing root layer and thus works fine.
+ setHasOverflowClip(false);
+}
+
+void RenderSVGBlock::absoluteRects(Vector<IntRect>&, int, int)
+{
+ // This code path should never be taken for SVG, as we're assuming useTransforms=true everywhere, absoluteQuads should be used.
+ ASSERT_NOT_REACHED();
+}
+
+void RenderSVGBlock::destroy()
+{
+ SVGResourcesCache::clientDestroyed(this);
+ RenderBlock::destroy();
+}
+
+void RenderSVGBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
+{
+ if (diff == StyleDifferenceLayout)
+ setNeedsBoundariesUpdate();
+ RenderBlock::styleWillChange(diff, newStyle);
+}
+
+void RenderSVGBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+ RenderBlock::styleDidChange(diff, oldStyle);
+ SVGResourcesCache::clientStyleChanged(this, diff, style());
+}
+
+void RenderSVGBlock::updateFromElement()
+{
+ RenderBlock::updateFromElement();
+ SVGResourcesCache::clientUpdatedFromElement(this, style());
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGBlock.h b/Source/WebCore/rendering/svg/RenderSVGBlock.h
new file mode 100644
index 0000000..350fdde
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGBlock.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * 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.
+ */
+
+#ifndef RenderSVGBlock_h
+#define RenderSVGBlock_h
+
+#if ENABLE(SVG)
+#include "RenderBlock.h"
+#include "SVGRenderSupport.h"
+
+namespace WebCore {
+
+class SVGElement;
+
+class RenderSVGBlock : public RenderBlock {
+public:
+ explicit RenderSVGBlock(SVGElement*);
+
+private:
+ virtual void setStyle(PassRefPtr<RenderStyle>);
+ virtual void updateBoxModelInfoFromStyle();
+
+ virtual void absoluteRects(Vector<IntRect>&, int tx, int ty);
+
+ virtual void destroy();
+ virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
+ virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+ virtual void updateFromElement();
+};
+
+}
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGContainer.cpp
new file mode 100644
index 0000000..1897f53
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGContainer.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005, 2007, 2008 Rob Buis <buis@kde.org>
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Google, Inc. All rights reserved.
+ * Copyright (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
+ * 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 "RenderSVGContainer.h"
+
+#include "GraphicsContext.h"
+#include "RenderSVGResource.h"
+#include "RenderSVGResourceFilter.h"
+#include "RenderView.h"
+#include "SVGRenderSupport.h"
+#include "SVGResources.h"
+#include "SVGStyledElement.h"
+
+namespace WebCore {
+
+RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node)
+ : RenderSVGModelObject(node)
+ , m_needsBoundariesUpdate(true)
+{
+}
+
+RenderSVGContainer::~RenderSVGContainer()
+{
+}
+
+void RenderSVGContainer::layout()
+{
+ ASSERT(needsLayout());
+
+ // RenderSVGRoot disables layoutState for the SVG rendering tree.
+ ASSERT(!view()->layoutStateEnabled());
+
+ // Allow RenderSVGViewportContainer to update its viewport.
+ calcViewport();
+
+ LayoutRepainter repainter(*this, checkForRepaintDuringLayout() || selfWillPaint());
+
+ // Allow RenderSVGTransformableContainer to update its transform.
+ bool updatedTransform = calculateLocalTransform();
+
+ SVGRenderSupport::layoutChildren(this, selfNeedsLayout());
+
+ // Invalidate all resources of this client if our layout changed.
+ if (m_everHadLayout && selfNeedsLayout())
+ SVGResourcesCache::clientLayoutChanged(this);
+
+ // At this point LayoutRepainter already grabbed the old bounds,
+ // recalculate them now so repaintAfterLayout() uses the new bounds.
+ if (m_needsBoundariesUpdate || updatedTransform) {
+ updateCachedBoundaries();
+ m_needsBoundariesUpdate = false;
+
+ // If our bounds changed, notify the parents.
+ RenderSVGModelObject::setNeedsBoundariesUpdate();
+ }
+
+ repainter.repaintAfterLayout();
+ setNeedsLayout(false);
+}
+
+bool RenderSVGContainer::selfWillPaint()
+{
+#if ENABLE(FILTERS)
+ SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this);
+ return resources && resources->filter();
+#else
+ return false;
+#endif
+}
+
+void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int)
+{
+ if (paintInfo.context->paintingDisabled())
+ return;
+
+ // Spec: groups w/o children still may render filter content.
+ if (!firstChild() && !selfWillPaint())
+ return;
+
+ FloatRect repaintRect = repaintRectInLocalCoordinates();
+ if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(repaintRect, localToParentTransform(), paintInfo))
+ return;
+
+ PaintInfo childPaintInfo(paintInfo);
+ childPaintInfo.context->save();
+
+ // Let the RenderSVGViewportContainer subclass clip if necessary
+ applyViewportClip(childPaintInfo);
+
+ childPaintInfo.applyTransform(localToParentTransform());
+
+ bool continueRendering = true;
+ if (childPaintInfo.phase == PaintPhaseForeground)
+ continueRendering = SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo);
+
+ if (continueRendering) {
+ childPaintInfo.updatePaintingRootForChildren(this);
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling())
+ child->paint(childPaintInfo, 0, 0);
+ }
+
+ if (paintInfo.phase == PaintPhaseForeground)
+ SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, 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
+ if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE) {
+ IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRect));
+ paintOutline(paintInfo.context, paintRectInParent.x(), paintRectInParent.y(), paintRectInParent.width(), paintRectInParent.height());
+ }
+}
+
+// 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);
+}
+
+void RenderSVGContainer::updateCachedBoundaries()
+{
+ m_objectBoundingBox = FloatRect();
+ m_strokeBoundingBox = FloatRect();
+ m_repaintBoundingBox = FloatRect();
+
+ SVGRenderSupport::computeContainerBoundingBoxes(this, m_objectBoundingBox, m_strokeBoundingBox, m_repaintBoundingBox);
+ SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox);
+}
+
+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);
+
+ if (!SVGRenderSupport::pointInClippingArea(this, localPoint))
+ return false;
+
+ 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)
diff --git a/Source/WebCore/rendering/svg/RenderSVGContainer.h b/Source/WebCore/rendering/svg/RenderSVGContainer.h
new file mode 100644
index 0000000..d478c49
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGContainer.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005, 2007 Rob Buis <buis@kde.org>
+ * Copyright (C) 2009 Google, Inc. All rights reserved.
+ * Copyright (C) 2009 Apple Inc. 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.
+ */
+
+#ifndef RenderSVGContainer_h
+#define RenderSVGContainer_h
+
+#if ENABLE(SVG)
+
+#include "RenderSVGModelObject.h"
+
+namespace WebCore {
+
+class SVGElement;
+
+class RenderSVGContainer : public RenderSVGModelObject {
+public:
+ explicit RenderSVGContainer(SVGStyledElement*);
+ virtual ~RenderSVGContainer();
+
+ const RenderObjectChildList* children() const { return &m_children; }
+ RenderObjectChildList* children() { return &m_children; }
+
+ virtual void paint(PaintInfo&, int parentX, int parentY);
+ virtual void setNeedsBoundariesUpdate() { m_needsBoundariesUpdate = true; }
+
+protected:
+ virtual RenderObjectChildList* virtualChildren() { return children(); }
+ virtual const RenderObjectChildList* virtualChildren() const { return children(); }
+
+ virtual bool isSVGContainer() const { return true; }
+ virtual const char* renderName() const { return "RenderSVGContainer"; }
+
+ virtual void layout();
+
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
+
+ virtual FloatRect objectBoundingBox() const { return m_objectBoundingBox; }
+ virtual FloatRect strokeBoundingBox() const { return m_strokeBoundingBox; }
+ virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; }
+
+ virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
+
+ // Allow RenderSVGTransformableContainer to hook in at the right time in layout()
+ virtual bool calculateLocalTransform() { return false; }
+
+ // Allow RenderSVGViewportContainer to hook in at the right times in layout(), paint() and nodeAtFloatPoint()
+ virtual void calcViewport() { }
+ virtual void applyViewportClip(PaintInfo&) { }
+ virtual bool pointIsInsideViewportClip(const FloatPoint& /*pointInParent*/) { return true; }
+
+ bool selfWillPaint();
+ void updateCachedBoundaries();
+
+private:
+ RenderObjectChildList m_children;
+ FloatRect m_objectBoundingBox;
+ FloatRect m_strokeBoundingBox;
+ FloatRect m_repaintBoundingBox;
+ bool m_needsBoundariesUpdate : 1;
+};
+
+inline RenderSVGContainer* toRenderSVGContainer(RenderObject* object)
+{
+ // Note: isSVGContainer is also true for RenderSVGViewportContainer, which is not derived from this.
+ ASSERT(!object || (object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer")));
+ return static_cast<RenderSVGContainer*>(object);
+}
+
+inline const RenderSVGContainer* toRenderSVGContainer(const RenderObject* object)
+{
+ // Note: isSVGContainer is also true for RenderSVGViewportContainer, which is not derived from this.
+ ASSERT(!object || (object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer")));
+ return static_cast<const RenderSVGContainer*>(object);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toRenderSVGContainer(const RenderSVGContainer*);
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGContainer_h
diff --git a/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp b/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp
new file mode 100644
index 0000000..200fab2
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2009 Google, Inc.
+ * 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) && ENABLE(SVG_FOREIGN_OBJECT)
+#include "RenderSVGForeignObject.h"
+
+#include "GraphicsContext.h"
+#include "RenderSVGResource.h"
+#include "RenderView.h"
+#include "SVGForeignObjectElement.h"
+#include "SVGRenderSupport.h"
+#include "SVGSVGElement.h"
+#include "TransformState.h"
+
+namespace WebCore {
+
+RenderSVGForeignObject::RenderSVGForeignObject(SVGForeignObjectElement* node)
+ : RenderSVGBlock(node)
+ , m_needsTransformUpdate(true)
+{
+}
+
+RenderSVGForeignObject::~RenderSVGForeignObject()
+{
+}
+
+void RenderSVGForeignObject::paint(PaintInfo& paintInfo, int, int)
+{
+ if (paintInfo.context->paintingDisabled())
+ return;
+
+ PaintInfo childPaintInfo(paintInfo);
+ childPaintInfo.context->save();
+ childPaintInfo.applyTransform(localTransform());
+
+ if (SVGRenderSupport::isOverflowHidden(this))
+ childPaintInfo.context->clip(m_viewport);
+
+ float opacity = style()->opacity();
+ if (opacity < 1.0f)
+ childPaintInfo.context->beginTransparencyLayer(opacity);
+
+ RenderBlock::paint(childPaintInfo, 0, 0);
+
+ if (opacity < 1.0f)
+ childPaintInfo.context->endTransparencyLayer();
+
+ childPaintInfo.context->restore();
+}
+
+IntRect RenderSVGForeignObject::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
+{
+ return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer);
+}
+
+void RenderSVGForeignObject::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
+{
+ SVGRenderSupport::computeRectForRepaint(this, repaintContainer, repaintRect, fixed);
+}
+
+const AffineTransform& RenderSVGForeignObject::localToParentTransform() const
+{
+ m_localToParentTransform = localTransform();
+ m_localToParentTransform.translate(m_viewport.x(), m_viewport.y());
+ return m_localToParentTransform;
+}
+
+void RenderSVGForeignObject::computeLogicalWidth()
+{
+ // FIXME: Investigate in size rounding issues
+ setWidth(static_cast<int>(roundf(m_viewport.width())));
+}
+
+void RenderSVGForeignObject::computeLogicalHeight()
+{
+ // FIXME: Investigate in size rounding issues
+ setHeight(static_cast<int>(roundf(m_viewport.height())));
+}
+
+void RenderSVGForeignObject::layout()
+{
+ ASSERT(needsLayout());
+ ASSERT(!view()->layoutStateEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree.
+
+ LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
+ SVGForeignObjectElement* foreign = static_cast<SVGForeignObjectElement*>(node());
+
+ bool updateCachedBoundariesInParents = false;
+ if (m_needsTransformUpdate) {
+ m_localTransform = foreign->animatedLocalTransform();
+ m_needsTransformUpdate = false;
+ updateCachedBoundariesInParents = true;
+ }
+
+ FloatRect oldViewport = m_viewport;
+
+ // Cache viewport boundaries
+ FloatPoint viewportLocation(foreign->x().value(foreign), foreign->y().value(foreign));
+ m_viewport = FloatRect(viewportLocation, FloatSize(foreign->width().value(foreign), foreign->height().value(foreign)));
+ if (!updateCachedBoundariesInParents)
+ updateCachedBoundariesInParents = oldViewport != m_viewport;
+
+ // Set box origin to the foreignObject x/y translation, so positioned objects in XHTML content get correct
+ // positions. A regular RenderBoxModelObject would pull this information from RenderStyle - in SVG those
+ // properties are ignored for non <svg> elements, so we mimic what happens when specifying them through CSS.
+
+ // FIXME: Investigate in location rounding issues - only affects RenderSVGForeignObject & RenderSVGText
+ setLocation(roundedIntPoint(viewportLocation));
+
+ bool layoutChanged = m_everHadLayout && selfNeedsLayout();
+ RenderBlock::layout();
+ ASSERT(!needsLayout());
+
+ // If our bounds changed, notify the parents.
+ if (updateCachedBoundariesInParents)
+ RenderSVGBlock::setNeedsBoundariesUpdate();
+
+ // Invalidate all resources of this client if our layout changed.
+ if (layoutChanged)
+ SVGResourcesCache::clientLayoutChanged(this);
+
+ repainter.repaintAfterLayout();
+}
+
+bool RenderSVGForeignObject::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
+{
+ FloatPoint localPoint = localTransform().inverse().mapPoint(pointInParent);
+
+ // Early exit if local point is not contained in clipped viewport area
+ if (SVGRenderSupport::isOverflowHidden(this) && !m_viewport.contains(localPoint))
+ return false;
+
+ IntPoint roundedLocalPoint = roundedIntPoint(localPoint);
+ return RenderBlock::nodeAtPoint(request, result, roundedLocalPoint.x(), roundedLocalPoint.y(), 0, 0, hitTestAction);
+}
+
+bool RenderSVGForeignObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction)
+{
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+void RenderSVGForeignObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const
+{
+ // When crawling up the hierachy starting from foreignObject child content, useTransforms may not be set to true.
+ if (!useTransforms)
+ useTransforms = true;
+ SVGRenderSupport::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState);
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGForeignObject.h b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h
new file mode 100644
index 0000000..a1cf91a
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * 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.
+ */
+
+#ifndef RenderSVGForeignObject_h
+#define RenderSVGForeignObject_h
+
+#if ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT)
+#include "AffineTransform.h"
+#include "FloatPoint.h"
+#include "RenderSVGBlock.h"
+
+namespace WebCore {
+
+class SVGForeignObjectElement;
+
+class RenderSVGForeignObject : public RenderSVGBlock {
+public:
+ explicit RenderSVGForeignObject(SVGForeignObjectElement*);
+ virtual ~RenderSVGForeignObject();
+
+ virtual const char* renderName() const { return "RenderSVGForeignObject"; }
+
+ virtual void paint(PaintInfo&, int parentX, int parentY);
+
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
+ virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false);
+
+ virtual bool requiresLayer() const { return false; }
+ virtual void layout();
+
+ virtual FloatRect objectBoundingBox() const { return m_viewport; }
+ virtual FloatRect strokeBoundingBox() const { return m_viewport; }
+ virtual FloatRect repaintRectInLocalCoordinates() const { return m_viewport; }
+
+ virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+ virtual bool isSVGForeignObject() const { return true; }
+
+ virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState&) const;
+ virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; }
+
+private:
+ virtual void computeLogicalWidth();
+ virtual void computeLogicalHeight();
+
+ virtual const AffineTransform& localToParentTransform() const;
+ virtual AffineTransform localTransform() const { return m_localTransform; }
+
+ bool m_needsTransformUpdate : 1;
+ FloatRect m_viewport;
+ AffineTransform m_localTransform;
+ mutable AffineTransform m_localToParentTransform;
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp b/Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp
new file mode 100644
index 0000000..46c3e2b
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 Eric Seidel <eric@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
+ * 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 "RenderSVGGradientStop.h"
+
+#include "RenderSVGResourceContainer.h"
+#include "SVGGradientElement.h"
+#include "SVGNames.h"
+#include "SVGResourcesCache.h"
+#include "SVGStopElement.h"
+
+namespace WebCore {
+
+using namespace SVGNames;
+
+RenderSVGGradientStop::RenderSVGGradientStop(SVGStopElement* element)
+ : RenderObject(element)
+{
+}
+
+RenderSVGGradientStop::~RenderSVGGradientStop()
+{
+}
+
+void RenderSVGGradientStop::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+ RenderObject::styleDidChange(diff, oldStyle);
+ if (diff == StyleDifferenceEqual)
+ return;
+
+ // <stop> elements should only be allowed to make renderers under gradient elements
+ // but I can imagine a few cases we might not be catching, so let's not crash if our parent isn't a gradient.
+ SVGGradientElement* gradient = gradientElement();
+ if (!gradient)
+ return;
+
+ RenderObject* renderer = gradient->renderer();
+ if (!renderer)
+ return;
+
+ ASSERT(renderer->isSVGResourceContainer());
+ RenderSVGResourceContainer* container = renderer->toRenderSVGResourceContainer();
+ container->removeAllClientsFromCache();
+}
+
+void RenderSVGGradientStop::layout()
+{
+ setNeedsLayout(false);
+}
+
+SVGGradientElement* RenderSVGGradientStop::gradientElement() const
+{
+ ContainerNode* parentNode = node()->parentNode();
+ if (parentNode->hasTagName(linearGradientTag) || parentNode->hasTagName(radialGradientTag))
+ return static_cast<SVGGradientElement*>(parentNode);
+ return 0;
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/RenderSVGGradientStop.h b/Source/WebCore/rendering/svg/RenderSVGGradientStop.h
new file mode 100644
index 0000000..ae90f37
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGGradientStop.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * 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.
+ */
+
+#ifndef RenderSVGGradientStop_h
+#define RenderSVGGradientStop_h
+
+#if ENABLE(SVG)
+#include "RenderObject.h"
+
+namespace WebCore {
+
+class SVGGradientElement;
+class SVGStopElement;
+
+// This class exists mostly so we can hear about gradient stop style changes
+class RenderSVGGradientStop : public RenderObject {
+public:
+ RenderSVGGradientStop(SVGStopElement*);
+ virtual ~RenderSVGGradientStop();
+
+ virtual bool isSVGGradientStop() const { return true; }
+ virtual const char* renderName() const { return "RenderSVGGradientStop"; }
+
+ virtual void layout();
+
+ // This overrides are needed to prevent ASSERTs on <svg><stop /></svg>
+ // RenderObject's default implementations ASSERT_NOT_REACHED()
+ // https://bugs.webkit.org/show_bug.cgi?id=20400
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject*) { return IntRect(); }
+ virtual FloatRect objectBoundingBox() const { return FloatRect(); }
+ virtual FloatRect strokeBoundingBox() const { return FloatRect(); }
+ virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); }
+
+protected:
+ virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+
+private:
+ SVGGradientElement* gradientElement() const;
+};
+
+inline const RenderSVGGradientStop* toRenderSVGGradientStop(const RenderObject* object)
+{
+ ASSERT(!object || object->isSVGGradientStop());
+ return static_cast<const RenderSVGGradientStop*>(object);
+}
+
+}
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGGradientStop_h
diff --git a/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp
new file mode 100644
index 0000000..9ddabef
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 Eric Seidel <eric@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
+ * 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 "RenderSVGHiddenContainer.h"
+
+#include "RenderSVGPath.h"
+#include "SVGStyledElement.h"
+
+namespace WebCore {
+
+RenderSVGHiddenContainer::RenderSVGHiddenContainer(SVGStyledElement* element)
+ : RenderSVGContainer(element)
+{
+}
+
+void RenderSVGHiddenContainer::layout()
+{
+ ASSERT(needsLayout());
+ SVGRenderSupport::layoutChildren(this, selfNeedsLayout());
+ setNeedsLayout(false);
+}
+
+void RenderSVGHiddenContainer::paint(PaintInfo&, int, int)
+{
+ // This subtree does not paint.
+}
+
+void RenderSVGHiddenContainer::absoluteQuads(Vector<FloatQuad>&)
+{
+ // This subtree does not take up space or paint
+}
+
+bool RenderSVGHiddenContainer::nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint&, HitTestAction)
+{
+ return false;
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.h b/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.h
new file mode 100644
index 0000000..d35de2d
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 Eric Seidel <eric@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
+ * 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.
+ */
+
+#ifndef RenderSVGHiddenContainer_h
+#define RenderSVGHiddenContainer_h
+
+#if ENABLE(SVG)
+#include "RenderSVGContainer.h"
+
+namespace WebCore {
+
+class SVGStyledElement;
+
+// This class is for containers which are never drawn, but do need to support style
+// <defs>, <linearGradient>, <radialGradient> are all good examples
+class RenderSVGHiddenContainer : public RenderSVGContainer {
+public:
+ explicit RenderSVGHiddenContainer(SVGStyledElement*);
+
+ virtual const char* renderName() const { return "RenderSVGHiddenContainer"; }
+
+protected:
+ virtual void layout();
+
+private:
+ virtual bool isSVGHiddenContainer() const { return true; }
+ virtual bool requiresLayer() const { return false; }
+
+ virtual void paint(PaintInfo&, int parentX, int parentY);
+
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject*) { return IntRect(); }
+ virtual void absoluteQuads(Vector<FloatQuad>&);
+
+ virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
+};
+}
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGHiddenContainer_h
diff --git a/Source/WebCore/rendering/svg/RenderSVGImage.cpp b/Source/WebCore/rendering/svg/RenderSVGImage.cpp
new file mode 100644
index 0000000..0f5a55e
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGImage.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2007, 2008, 2009 Rob Buis <buis@kde.org>
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
+ *
+ * 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 "RenderSVGImage.h"
+
+#include "Attr.h"
+#include "FloatConversion.h"
+#include "FloatQuad.h"
+#include "GraphicsContext.h"
+#include "PointerEventsHitRules.h"
+#include "RenderImageResource.h"
+#include "RenderLayer.h"
+#include "RenderSVGResourceContainer.h"
+#include "RenderSVGResourceFilter.h"
+#include "SVGImageElement.h"
+#include "SVGLength.h"
+#include "SVGPreserveAspectRatio.h"
+#include "SVGRenderSupport.h"
+#include "SVGResources.h"
+
+namespace WebCore {
+
+RenderSVGImage::RenderSVGImage(SVGImageElement* impl)
+ : RenderSVGModelObject(impl)
+ , m_updateCachedRepaintRect(true)
+ , m_needsTransformUpdate(true)
+ , m_imageResource(RenderImageResource::create())
+{
+ m_imageResource->initialize(this);
+}
+
+RenderSVGImage::~RenderSVGImage()
+{
+ m_imageResource->shutdown();
+}
+
+void RenderSVGImage::layout()
+{
+ ASSERT(needsLayout());
+
+ LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout());
+ SVGImageElement* image = static_cast<SVGImageElement*>(node());
+
+ bool transformOrBoundariesUpdate = m_needsTransformUpdate || m_updateCachedRepaintRect;
+ if (m_needsTransformUpdate) {
+ m_localTransform = image->animatedLocalTransform();
+ m_needsTransformUpdate = false;
+ }
+
+ if (m_updateCachedRepaintRect) {
+ m_repaintBoundingBox = m_objectBoundingBox;
+ SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox);
+ m_updateCachedRepaintRect = false;
+ }
+
+ // Invalidate all resources of this client if our layout changed.
+ if (m_everHadLayout && selfNeedsLayout())
+ SVGResourcesCache::clientLayoutChanged(this);
+
+ // If our bounds changed, notify the parents.
+ if (transformOrBoundariesUpdate)
+ RenderSVGModelObject::setNeedsBoundariesUpdate();
+
+ repainter.repaintAfterLayout();
+ setNeedsLayout(false);
+}
+
+void RenderSVGImage::updateFromElement()
+{
+ SVGImageElement* image = static_cast<SVGImageElement*>(node());
+
+ FloatRect oldBoundaries = m_objectBoundingBox;
+ m_objectBoundingBox = FloatRect(image->x().value(image), image->y().value(image), image->width().value(image), image->height().value(image));
+ if (m_objectBoundingBox != oldBoundaries) {
+ m_updateCachedRepaintRect = true;
+ setNeedsLayout(true);
+ }
+ RenderSVGModelObject::updateFromElement();
+}
+
+void RenderSVGImage::paint(PaintInfo& paintInfo, int, int)
+{
+ if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || !m_imageResource->hasImage())
+ return;
+
+ FloatRect boundingBox = repaintRectInLocalCoordinates();
+ if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(boundingBox, m_localTransform, paintInfo))
+ return;
+
+ PaintInfo childPaintInfo(paintInfo);
+ bool drawsOutline = style()->outlineWidth() && (childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline);
+ if (drawsOutline || childPaintInfo.phase == PaintPhaseForeground) {
+ childPaintInfo.context->save();
+ childPaintInfo.applyTransform(m_localTransform);
+
+ if (childPaintInfo.phase == PaintPhaseForeground) {
+ PaintInfo savedInfo(childPaintInfo);
+
+ if (SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo)) {
+ Image* image = m_imageResource->image();
+ FloatRect destRect = m_objectBoundingBox;
+ FloatRect srcRect(0, 0, image->width(), image->height());
+
+ SVGImageElement* imageElement = static_cast<SVGImageElement*>(node());
+ if (imageElement->preserveAspectRatio().align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE)
+ imageElement->preserveAspectRatio().transformRect(destRect, srcRect);
+
+ childPaintInfo.context->drawImage(image, ColorSpaceDeviceRGB, destRect, srcRect);
+ }
+
+ SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, savedInfo.context);
+ }
+
+ if (drawsOutline)
+ paintOutline(childPaintInfo.context, static_cast<int>(boundingBox.x()), static_cast<int>(boundingBox.y()),
+ static_cast<int>(boundingBox.width()), static_cast<int>(boundingBox.height()));
+
+ childPaintInfo.context->restore();
+ }
+}
+
+bool RenderSVGImage::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
+{
+ // We only draw in the forground phase, so we only hit-test then.
+ if (hitTestAction != HitTestForeground)
+ return false;
+
+ PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_IMAGE_HITTESTING, request, style()->pointerEvents());
+ bool isVisible = (style()->visibility() == VISIBLE);
+ if (isVisible || !hitRules.requireVisible) {
+ FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent);
+
+ if (!SVGRenderSupport::pointInClippingArea(this, localPoint))
+ return false;
+
+ if (hitRules.canHitFill) {
+ if (m_objectBoundingBox.contains(localPoint)) {
+ updateHitTestResult(result, roundedIntPoint(localPoint));
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void RenderSVGImage::imageChanged(WrappedImagePtr, const IntRect*)
+{
+ // The image resource defaults to nullImage until the resource arrives.
+ // This empty image may be cached by SVG resources which must be invalidated.
+ if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this))
+ resources->removeClientFromCache(this);
+
+ // Eventually notify parent resources, that we've changed.
+ RenderSVGResource::markForLayoutAndParentResourceInvalidation(this, false);
+
+ repaint();
+}
+
+void RenderSVGImage::addFocusRingRects(Vector<IntRect>& rects, int, int)
+{
+ // this is called from paint() after the localTransform has already been applied
+ IntRect contentRect = enclosingIntRect(repaintRectInLocalCoordinates());
+ if (!contentRect.isEmpty())
+ rects.append(contentRect);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/RenderSVGImage.h b/Source/WebCore/rendering/svg/RenderSVGImage.h
new file mode 100644
index 0000000..2c91b52
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGImage.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org>
+ * Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Rob Buis <buis@kde.org>
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
+ *
+ * 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.
+ */
+
+#ifndef RenderSVGImage_h
+#define RenderSVGImage_h
+
+#if ENABLE(SVG)
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "RenderSVGModelObject.h"
+#include "SVGPreserveAspectRatio.h"
+#include "SVGRenderSupport.h"
+
+namespace WebCore {
+
+class RenderImageResource;
+class SVGImageElement;
+
+class RenderSVGImage : public RenderSVGModelObject {
+public:
+ RenderSVGImage(SVGImageElement*);
+ virtual ~RenderSVGImage();
+
+ virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; }
+ virtual void updateFromElement();
+
+ RenderImageResource* imageResource() { return m_imageResource.get(); }
+ const RenderImageResource* imageResource() const { return m_imageResource.get(); }
+
+private:
+ virtual const char* renderName() const { return "RenderSVGImage"; }
+ virtual bool isSVGImage() const { return true; }
+
+ virtual const AffineTransform& localToParentTransform() const { return m_localTransform; }
+
+ virtual FloatRect objectBoundingBox() const { return m_objectBoundingBox; }
+ virtual FloatRect strokeBoundingBox() const { return m_objectBoundingBox; }
+ virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; }
+
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
+
+ virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
+
+ virtual void layout();
+ virtual void paint(PaintInfo&, int parentX, int parentY);
+
+ virtual bool requiresLayer() const { return false; }
+
+ virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
+
+ virtual AffineTransform localTransform() const { return m_localTransform; }
+
+ bool m_updateCachedRepaintRect : 1;
+ bool m_needsTransformUpdate : 1;
+ AffineTransform m_localTransform;
+ FloatRect m_objectBoundingBox;
+ FloatRect m_repaintBoundingBox;
+ OwnPtr<RenderImageResource> m_imageResource;
+};
+
+inline RenderSVGImage* toRenderSVGImage(RenderObject* object)
+{
+ ASSERT(!object || object->isSVGImage());
+ return static_cast<RenderSVGImage*>(object);
+}
+
+inline const RenderSVGImage* toRenderSVGImage(const RenderObject* object)
+{
+ ASSERT(!object || object->isSVGImage());
+ return static_cast<const RenderSVGImage*>(object);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toRenderSVGImage(const RenderSVGImage*);
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGImage_h
diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.cpp b/Source/WebCore/rendering/svg/RenderSVGInline.cpp
index 4d0c533..543d14b 100644
--- a/Source/WebCore/rendering/svg/RenderSVGInline.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGInline.cpp
@@ -17,7 +17,6 @@
* 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"
diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.h b/Source/WebCore/rendering/svg/RenderSVGInline.h
index d7b7e66..33d7d13 100644
--- a/Source/WebCore/rendering/svg/RenderSVGInline.h
+++ b/Source/WebCore/rendering/svg/RenderSVGInline.h
@@ -1,8 +1,6 @@
/*
- * This file is part of the WebKit project.
- *
* Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
- * (C) 2006 Apple Computer Inc.
+ * Copyright (C) 2006 Apple Computer Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -18,7 +16,6 @@
* 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.
- *
*/
#ifndef RenderSVGInline_h
diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp
index b791f3e..91ffb5c 100644
--- a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp
@@ -19,7 +19,6 @@
* 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"
diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.h b/Source/WebCore/rendering/svg/RenderSVGInlineText.h
index 926ec43..f5247f6 100644
--- a/Source/WebCore/rendering/svg/RenderSVGInlineText.h
+++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.h
@@ -1,9 +1,7 @@
/*
- * This file is part of the WebKit project.
- *
* Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
* Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
- * (C) 2008 Rob Buis <buis@kde.org>
+ * Copyright (C) 2008 Rob Buis <buis@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -19,7 +17,6 @@
* 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.
- *
*/
#ifndef RenderSVGInlineText_h
diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp
new file mode 100644
index 0000000..28760a0
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGModelObject.h"
+
+#include "RenderSVGResource.h"
+#include "SVGStyledElement.h"
+
+namespace WebCore {
+
+RenderSVGModelObject::RenderSVGModelObject(SVGStyledElement* node)
+ : RenderObject(node)
+{
+}
+
+IntRect RenderSVGModelObject::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
+{
+ return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer);
+}
+
+void RenderSVGModelObject::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
+{
+ SVGRenderSupport::computeRectForRepaint(this, repaintContainer, repaintRect, fixed);
+}
+
+void RenderSVGModelObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const
+{
+ SVGRenderSupport::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState);
+}
+
+// Copied from RenderBox, this method likely requires further refactoring to work easily for both SVG and CSS Box Model content.
+// FIXME: This may also need to move into SVGRenderSupport as the RenderBox version depends
+// on borderBoundingBox() which SVG RenderBox subclases (like SVGRenderBlock) do not implement.
+IntRect RenderSVGModelObject::outlineBoundsForRepaint(RenderBoxModelObject* repaintContainer, IntPoint*) const
+{
+ IntRect box = enclosingIntRect(repaintRectInLocalCoordinates());
+ adjustRectForOutlineAndShadow(box);
+
+ FloatQuad containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer);
+ return containerRelativeQuad.enclosingBoundingBox();
+}
+
+void RenderSVGModelObject::absoluteRects(Vector<IntRect>&, int, int)
+{
+ // This code path should never be taken for SVG, as we're assuming useTransforms=true everywhere, absoluteQuads should be used.
+ ASSERT_NOT_REACHED();
+}
+
+void RenderSVGModelObject::absoluteQuads(Vector<FloatQuad>& quads)
+{
+ quads.append(localToAbsoluteQuad(strokeBoundingBox()));
+}
+
+void RenderSVGModelObject::destroy()
+{
+ SVGResourcesCache::clientDestroyed(this);
+ RenderObject::destroy();
+}
+
+void RenderSVGModelObject::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
+{
+ if (diff == StyleDifferenceLayout)
+ setNeedsBoundariesUpdate();
+ RenderObject::styleWillChange(diff, newStyle);
+}
+
+void RenderSVGModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+ RenderObject::styleDidChange(diff, oldStyle);
+ SVGResourcesCache::clientStyleChanged(this, diff, style());
+}
+
+void RenderSVGModelObject::updateFromElement()
+{
+ RenderObject::updateFromElement();
+ SVGResourcesCache::clientUpdatedFromElement(this, style());
+}
+
+bool RenderSVGModelObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction)
+{
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.h b/Source/WebCore/rendering/svg/RenderSVGModelObject.h
new file mode 100644
index 0000000..a04db96
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RenderSVGModelObject_h
+#define RenderSVGModelObject_h
+
+#if ENABLE(SVG)
+
+#include "RenderObject.h"
+#include "SVGRenderSupport.h"
+
+namespace WebCore {
+
+// Most renderers in the SVG rendering tree will inherit from this class
+// but not all. (e.g. RenderSVGForeignObject, RenderSVGBlock) thus methods
+// required by SVG renders need to be declared on RenderObject, but shared
+// logic can go in this class or in SVGRenderSupport.
+
+class SVGStyledElement;
+
+class RenderSVGModelObject : public RenderObject {
+public:
+ explicit RenderSVGModelObject(SVGStyledElement*);
+
+ virtual bool requiresLayer() const { return false; }
+
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
+ virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false);
+ virtual IntRect outlineBoundsForRepaint(RenderBoxModelObject* repaintContainer, IntPoint*) const;
+
+ virtual void absoluteRects(Vector<IntRect>&, int tx, int ty);
+ virtual void absoluteQuads(Vector<FloatQuad>&);
+
+ virtual void destroy();
+
+ virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const;
+ virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
+ virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+ virtual void updateFromElement();
+
+private:
+ // This method should never be called, SVG uses a different nodeAtPoint method
+ bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int xInContainer, int yInContainer, int dxParentToContainer, int dyParentToContainer, HitTestAction);
+};
+
+}
+
+#endif // ENABLE(SVG)
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGPath.cpp b/Source/WebCore/rendering/svg/RenderSVGPath.cpp
index 0c8ac0c..1d9eca1 100644
--- a/Source/WebCore/rendering/svg/RenderSVGPath.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGPath.cpp
@@ -1,27 +1,27 @@
/*
- Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
- 2004, 2005, 2008 Rob Buis <buis@kde.org>
- 2005, 2007 Eric Seidel <eric@webkit.org>
- 2009 Google, Inc.
- 2009 Dirk Schulze <krit@webkit.org>
- Copyright (C) Research In Motion Limited 2010. All rights reserved.
- 2009 Jeff Schiller <codedread@gmail.com>
-
- 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.
-*/
+ * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005, 2008 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005, 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ * Copyright (C) 2009 Jeff Schiller <codedread@gmail.com>
+ *
+ * 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"
diff --git a/Source/WebCore/rendering/svg/RenderSVGPath.h b/Source/WebCore/rendering/svg/RenderSVGPath.h
index 41b0e51..c5c8377 100644
--- a/Source/WebCore/rendering/svg/RenderSVGPath.h
+++ b/Source/WebCore/rendering/svg/RenderSVGPath.h
@@ -1,25 +1,25 @@
/*
- Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
- 2004, 2005 Rob Buis <buis@kde.org>
- 2005 Eric Seidel <eric@webkit.org>
- 2006 Apple Computer, Inc
- 2009 Google, Inc.
-
- 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.
-*/
+ * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2006 Apple Computer, Inc
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * 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.
+ */
#ifndef RenderSVGPath_h
#define RenderSVGPath_h
diff --git a/Source/WebCore/rendering/svg/RenderSVGResource.cpp b/Source/WebCore/rendering/svg/RenderSVGResource.cpp
new file mode 100644
index 0000000..c0b16c5
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResource.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2007 Rob Buis <buis@kde.org>
+ * Copyright (C) 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 "RenderSVGResourceContainer.h"
+#include "RenderSVGResourceSolidColor.h"
+#include "SVGResources.h"
+#include "SVGURIReference.h"
+
+namespace WebCore {
+
+static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode mode, RenderObject* object, const RenderStyle* style, Color& fallbackColor)
+{
+ ASSERT(object);
+ ASSERT(style);
+
+ // If we have no style at all, ignore it.
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+ if (!svgStyle)
+ return 0;
+
+ // If we have no fill/stroke, return 0.
+ if (mode == ApplyToFillMode) {
+ if (!svgStyle->hasFill())
+ return 0;
+ } else {
+ if (!svgStyle->hasStroke())
+ return 0;
+ }
+
+ SVGPaint* paint = mode == ApplyToFillMode ? svgStyle->fillPaint() : svgStyle->strokePaint();
+ ASSERT(paint);
+
+ SVGPaint::SVGPaintType paintType = paint->paintType();
+ if (paintType == SVGPaint::SVG_PAINTTYPE_NONE)
+ return 0;
+
+ Color color;
+ if (paintType == SVGPaint::SVG_PAINTTYPE_RGBCOLOR
+ || paintType == SVGPaint::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR
+ || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR
+ || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR)
+ color = paint->color();
+ else if (paintType == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR || paintType == SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR)
+ color = style->visitedDependentColor(CSSPropertyColor);
+
+ if (style->insideLink() == InsideVisitedLink) {
+ RenderStyle* visitedStyle = style->getCachedPseudoStyle(VISITED_LINK);
+ ASSERT(visitedStyle);
+
+ if (SVGPaint* visitedPaint = mode == ApplyToFillMode ? visitedStyle->svgStyle()->fillPaint() : visitedStyle->svgStyle()->strokePaint()) {
+ // For SVG_PAINTTYPE_CURRENTCOLOR, 'color' already contains the 'visitedColor'.
+ if (visitedPaint->paintType() < SVGPaint::SVG_PAINTTYPE_URI_NONE && visitedPaint->paintType() != SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) {
+ const Color& visitedColor = visitedPaint->color();
+ if (visitedColor.isValid())
+ color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha());
+ }
+ }
+ }
+
+ // If the primary resource is just a color, return immediately.
+ RenderSVGResourceSolidColor* colorResource = RenderSVGResource::sharedSolidPaintingResource();
+ if (paintType < SVGPaint::SVG_PAINTTYPE_URI_NONE) {
+ // If an invalid fill color is specified, fallback to fill/stroke="none".
+ if (!color.isValid())
+ return 0;
+
+ colorResource->setColor(color);
+ return colorResource;
+ }
+
+ // If no resources are associated with the given renderer, return the color resource.
+ SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
+ if (!resources) {
+ // If a paint server is specified, and no or an invalid fallback color is given, default to fill/stroke="black".
+ if (!color.isValid())
+ color = Color::black;
+
+ colorResource->setColor(color);
+ return colorResource;
+ }
+
+ // If the requested resource is not available, return the color resource.
+ RenderSVGResource* uriResource = mode == ApplyToFillMode ? resources->fill() : resources->stroke();
+ if (!uriResource) {
+ // If a paint server is specified, and no or an invalid fallback color is given, default to fill/stroke="black".
+ if (!color.isValid())
+ color = Color::black;
+
+ colorResource->setColor(color);
+ return colorResource;
+ }
+
+ // The paint server resource exists, though it may be invalid (pattern with width/height=0). Pass the fallback color to our caller
+ // so it can use the solid color painting resource, if applyResource() on the URI resource failed.
+ fallbackColor = color;
+ return uriResource;
+}
+
+RenderSVGResource* RenderSVGResource::fillPaintingResource(RenderObject* object, const RenderStyle* style, Color& fallbackColor)
+{
+ return requestPaintingResource(ApplyToFillMode, object, style, fallbackColor);
+}
+
+RenderSVGResource* RenderSVGResource::strokePaintingResource(RenderObject* object, const RenderStyle* style, Color& fallbackColor)
+{
+ return requestPaintingResource(ApplyToStrokeMode, object, style, fallbackColor);
+}
+
+RenderSVGResourceSolidColor* RenderSVGResource::sharedSolidPaintingResource()
+{
+ static RenderSVGResourceSolidColor* s_sharedSolidPaintingResource = 0;
+ if (!s_sharedSolidPaintingResource)
+ s_sharedSolidPaintingResource = new RenderSVGResourceSolidColor;
+ return s_sharedSolidPaintingResource;
+}
+
+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()->removeAllClientsFromCache();
+ break;
+ }
+
+ current = current->parent();
+ }
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResource.h b/Source/WebCore/rendering/svg/RenderSVGResource.h
new file mode 100644
index 0000000..a67ba73
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResource.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-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.
+ */
+
+#ifndef RenderSVGResource_h
+#define RenderSVGResource_h
+
+#if ENABLE(SVG)
+#include "RenderStyleConstants.h"
+#include "SVGDocumentExtensions.h"
+
+namespace WebCore {
+
+enum RenderSVGResourceType {
+ MaskerResourceType,
+ MarkerResourceType,
+ PatternResourceType,
+ LinearGradientResourceType,
+ RadialGradientResourceType,
+ SolidColorResourceType,
+ FilterResourceType,
+ ClipperResourceType
+};
+
+enum RenderSVGResourceMode {
+ ApplyToDefaultMode = 1 << 0, // used for all resources except gradient/pattern
+ ApplyToFillMode = 1 << 1,
+ ApplyToStrokeMode = 1 << 2,
+ ApplyToTextMode = 1 << 3 // used in combination with ApplyTo{Fill|Stroke}Mode
+};
+
+class Color;
+class FloatRect;
+class GraphicsContext;
+class Path;
+class RenderObject;
+class RenderStyle;
+class RenderSVGResourceSolidColor;
+
+class RenderSVGResource {
+public:
+ RenderSVGResource() { }
+ virtual ~RenderSVGResource() { }
+
+ virtual void removeAllClientsFromCache(bool markForInvalidation = true) = 0;
+ virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true) = 0;
+
+ virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) = 0;
+ virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short, const Path*) { }
+ virtual FloatRect resourceBoundingBox(RenderObject*) = 0;
+
+ virtual RenderSVGResourceType resourceType() const = 0;
+
+ template<class Renderer>
+ Renderer* cast()
+ {
+ if (Renderer::s_resourceType == resourceType())
+ return static_cast<Renderer*>(this);
+
+ return 0;
+ }
+
+ // Helper utilities used in the render tree to access resources used for painting shapes/text (gradients & patterns & solid colors only)
+ static RenderSVGResource* fillPaintingResource(RenderObject*, const RenderStyle*, Color& fallbackColor);
+ static RenderSVGResource* strokePaintingResource(RenderObject*, const RenderStyle*, Color& fallbackColor);
+ static RenderSVGResourceSolidColor* sharedSolidPaintingResource();
+
+ static void markForLayoutAndParentResourceInvalidation(RenderObject*, bool needsLayout = true);
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp
new file mode 100644
index 0000000..c57f8b0
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Rob Buis <buis@kde.org>
+ * Copyright (C) Research In Motion Limited 2009-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 "RenderSVGResourceClipper.h"
+
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "ImageBuffer.h"
+#include "IntRect.h"
+#include "RenderObject.h"
+#include "RenderSVGResource.h"
+#include "RenderStyle.h"
+#include "SVGClipPathElement.h"
+#include "SVGElement.h"
+#include "SVGImageBufferTools.h"
+#include "SVGNames.h"
+#include "SVGRenderSupport.h"
+#include "SVGResources.h"
+#include "SVGStyledElement.h"
+#include "SVGStyledTransformableElement.h"
+#include "SVGUnitTypes.h"
+#include "SVGUseElement.h"
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+RenderSVGResourceType RenderSVGResourceClipper::s_resourceType = ClipperResourceType;
+
+RenderSVGResourceClipper::RenderSVGResourceClipper(SVGClipPathElement* node)
+ : RenderSVGResourceContainer(node)
+ , m_invalidationBlocked(false)
+{
+}
+
+RenderSVGResourceClipper::~RenderSVGResourceClipper()
+{
+ if (m_clipper.isEmpty())
+ return;
+
+ deleteAllValues(m_clipper);
+ m_clipper.clear();
+}
+
+void RenderSVGResourceClipper::removeAllClientsFromCache(bool markForInvalidation)
+{
+ if (m_invalidationBlocked)
+ return;
+
+ m_clipBoundaries = FloatRect();
+ if (!m_clipper.isEmpty()) {
+ deleteAllValues(m_clipper);
+ m_clipper.clear();
+ }
+
+ markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
+}
+
+void RenderSVGResourceClipper::removeClientFromCache(RenderObject* client, bool markForInvalidation)
+{
+ ASSERT(client);
+ if (m_invalidationBlocked)
+ return;
+
+ if (m_clipper.contains(client))
+ delete m_clipper.take(client);
+
+ markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
+}
+
+bool RenderSVGResourceClipper::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode)
+{
+ ASSERT(object);
+ ASSERT(context);
+#ifndef NDEBUG
+ ASSERT(resourceMode == ApplyToDefaultMode);
+#else
+ UNUSED_PARAM(resourceMode);
+#endif
+
+ return applyClippingToContext(object, object->objectBoundingBox(), object->repaintRectInLocalCoordinates(), context);
+}
+
+bool RenderSVGResourceClipper::pathOnlyClipping(GraphicsContext* context, const FloatRect& objectBoundingBox)
+{
+ // If the current clip-path gets clipped itself, we have to fallback to masking.
+ if (!style()->svgStyle()->clipperResource().isEmpty())
+ return false;
+ WindRule clipRule = RULE_NONZERO;
+ Path clipPath = Path();
+
+ // If clip-path only contains one visible shape or path, we can use path-based clipping. Invisible
+ // shapes don't affect the clipping and can be ignored. If clip-path contains more than one
+ // visible shape, the additive clipping may not work, caused by the clipRule. EvenOdd
+ // as well as NonZero can cause self-clipping of the elements.
+ // See also http://www.w3.org/TR/SVG/painting.html#FillRuleProperty
+ for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
+ RenderObject* renderer = childNode->renderer();
+ if (!renderer)
+ continue;
+ // Only shapes or paths are supported for direct clipping. We need to fallback to masking for texts.
+ if (renderer->isSVGText())
+ return false;
+ if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyledTransformable())
+ continue;
+ SVGStyledTransformableElement* styled = static_cast<SVGStyledTransformableElement*>(childNode);
+ RenderStyle* style = renderer->style();
+ if (!style || style->display() == NONE || style->visibility() != VISIBLE)
+ continue;
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+ // Current shape in clip-path gets clipped too. Fallback to masking.
+ if (!svgStyle->clipperResource().isEmpty())
+ return false;
+ // Fallback to masking, if there is more than one clipping path.
+ if (clipPath.isEmpty()) {
+ styled->toClipPath(clipPath);
+ clipRule = svgStyle->clipRule();
+ } else
+ return false;
+ }
+ // Only one visible shape/path was found. Directly continue clipping and transform the content to userspace if necessary.
+ if (static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+ AffineTransform transform;
+ transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
+ transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
+ clipPath.transform(transform);
+ }
+ // The SVG specification wants us to clip everything, if clip-path doesn't have a child.
+ if (clipPath.isEmpty())
+ clipPath.addRect(FloatRect());
+ context->clipPath(clipPath, clipRule);
+ return true;
+}
+
+bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* object, const FloatRect& objectBoundingBox,
+ const FloatRect& repaintRect, GraphicsContext* context)
+{
+ if (!m_clipper.contains(object))
+ m_clipper.set(object, new ClipperData);
+
+ bool shouldCreateClipData = false;
+ ClipperData* clipperData = m_clipper.get(object);
+ if (!clipperData->clipMaskImage) {
+ if (pathOnlyClipping(context, objectBoundingBox))
+ return true;
+ shouldCreateClipData = true;
+ }
+
+ AffineTransform absoluteTransform;
+ SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform);
+
+ FloatRect absoluteTargetRect = absoluteTransform.mapRect(repaintRect);
+ FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(object, absoluteTargetRect);
+
+ if (shouldCreateClipData && !clampedAbsoluteTargetRect.isEmpty()) {
+ if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, clipperData->clipMaskImage, ColorSpaceDeviceRGB))
+ return false;
+
+ GraphicsContext* maskContext = clipperData->clipMaskImage->context();
+ ASSERT(maskContext);
+
+ // The save/restore pair is needed for clipToImageBuffer - it doesn't work without it on non-Cg platforms.
+ maskContext->save();
+ maskContext->translate(-clampedAbsoluteTargetRect.x(), -clampedAbsoluteTargetRect.y());
+ maskContext->concatCTM(absoluteTransform);
+
+ // clipPath can also be clipped by another clipPath.
+ if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this)) {
+ if (RenderSVGResourceClipper* clipper = resources->clipper()) {
+ if (!clipper->applyClippingToContext(this, objectBoundingBox, repaintRect, maskContext)) {
+ maskContext->restore();
+ return false;
+ }
+ }
+ }
+
+ drawContentIntoMaskImage(clipperData, objectBoundingBox);
+ maskContext->restore();
+ }
+
+ if (!clipperData->clipMaskImage)
+ return false;
+
+ SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, clampedAbsoluteTargetRect, clipperData->clipMaskImage);
+ return true;
+}
+
+bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData, const FloatRect& objectBoundingBox)
+{
+ ASSERT(clipperData);
+ ASSERT(clipperData->clipMaskImage);
+
+ GraphicsContext* maskContext = clipperData->clipMaskImage->context();
+ ASSERT(maskContext);
+
+ AffineTransform maskContentTransformation;
+ SVGClipPathElement* clipPath = static_cast<SVGClipPathElement*>(node());
+ if (clipPath->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+ maskContentTransformation.translate(objectBoundingBox.x(), objectBoundingBox.y());
+ maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
+ maskContext->concatCTM(maskContentTransformation);
+ }
+
+ // Draw all clipPath children into a global mask.
+ for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
+ RenderObject* renderer = childNode->renderer();
+ if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer)
+ continue;
+ RenderStyle* style = renderer->style();
+ if (!style || style->display() == NONE || style->visibility() != VISIBLE)
+ continue;
+
+ WindRule newClipRule = style->svgStyle()->clipRule();
+ bool isUseElement = renderer->isSVGShadowTreeRootContainer();
+ if (isUseElement) {
+ SVGUseElement* useElement = static_cast<SVGUseElement*>(childNode);
+ renderer = useElement->rendererClipChild();
+ if (!renderer)
+ continue;
+ if (!useElement->hasAttribute(SVGNames::clip_ruleAttr))
+ newClipRule = renderer->style()->svgStyle()->clipRule();
+ }
+
+ // Only shapes, paths and texts are allowed for clipping.
+ if (!renderer->isSVGPath() && !renderer->isSVGText())
+ continue;
+
+ // Save the old RenderStyle of the current object for restoring after drawing
+ // it to the MaskImage. The new intermediate RenderStyle needs to inherit from
+ // the old one.
+ RefPtr<RenderStyle> oldRenderStyle = renderer->style();
+ RefPtr<RenderStyle> newRenderStyle = RenderStyle::clone(oldRenderStyle.get());
+ SVGRenderStyle* svgStyle = newRenderStyle.get()->accessSVGStyle();
+ svgStyle->setFillPaint(SVGPaint::defaultFill());
+ svgStyle->setStrokePaint(SVGPaint::defaultStroke());
+ svgStyle->setFillRule(newClipRule);
+ newRenderStyle.get()->setOpacity(1.0f);
+ svgStyle->setFillOpacity(1.0f);
+ svgStyle->setStrokeOpacity(1.0f);
+ svgStyle->setFilterResource(String());
+ svgStyle->setMaskerResource(String());
+
+ // The setStyle() call results in a styleDidChange() call, which in turn invalidations the resources.
+ // As we're mutating the resource on purpose, block updates until we've resetted the style again.
+ m_invalidationBlocked = true;
+ renderer->setStyle(newRenderStyle.release());
+
+ // In the case of a <use> element, we obtained its renderere above, to retrieve its clipRule.
+ // We have to pass the <use> renderer itself to renderSubtreeToImageBuffer() to apply it's x/y/transform/etc. values when rendering.
+ // So if isUseElement is true, refetch the childNode->renderer(), as renderer got overriden above.
+ SVGImageBufferTools::renderSubtreeToImageBuffer(clipperData->clipMaskImage.get(), isUseElement ? childNode->renderer() : renderer, maskContentTransformation);
+
+ renderer->setStyle(oldRenderStyle.release());
+ m_invalidationBlocked = false;
+ }
+
+ return true;
+}
+
+void RenderSVGResourceClipper::calculateClipContentRepaintRect()
+{
+ // This is a rough heuristic to appraise the clip size and doesn't consider clip on clip.
+ for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
+ RenderObject* renderer = childNode->renderer();
+ if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer)
+ continue;
+ if (!renderer->isSVGPath() && !renderer->isSVGText() && !renderer->isSVGShadowTreeRootContainer())
+ continue;
+ RenderStyle* style = renderer->style();
+ if (!style || style->display() == NONE || style->visibility() != VISIBLE)
+ continue;
+ m_clipBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates()));
+ }
+}
+
+bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundingBox, const FloatPoint& nodeAtPoint)
+{
+ FloatPoint point = nodeAtPoint;
+ if (!SVGRenderSupport::pointInClippingArea(this, point))
+ return false;
+
+ if (static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+ AffineTransform transform;
+ transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
+ transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
+ point = transform.inverse().mapPoint(point);
+ }
+
+ for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
+ RenderObject* renderer = childNode->renderer();
+ if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer)
+ continue;
+ if (!renderer->isSVGPath() && !renderer->isSVGText() && !renderer->isSVGShadowTreeRootContainer())
+ continue;
+ IntPoint hitPoint;
+ HitTestResult result(hitPoint);
+ if (renderer->nodeAtFloatPoint(HitTestRequest(HitTestRequest::SVGClipContent), result, point, HitTestForeground))
+ return true;
+ }
+
+ return false;
+}
+
+FloatRect RenderSVGResourceClipper::resourceBoundingBox(RenderObject* object)
+{
+ // Resource was not layouted yet. Give back the boundingBox of the object.
+ if (selfNeedsLayout())
+ return object->objectBoundingBox();
+
+ if (m_clipBoundaries.isEmpty())
+ calculateClipContentRepaintRect();
+
+ if (static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+ FloatRect objectBoundingBox = object->objectBoundingBox();
+ AffineTransform transform;
+ transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
+ transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
+ return transform.mapRect(m_clipBoundaries);
+ }
+
+ return m_clipBoundaries;
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceClipper.h b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.h
new file mode 100644
index 0000000..7f862a7
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-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.
+ */
+
+#ifndef RenderSVGResourceClipper_h
+#define RenderSVGResourceClipper_h
+
+#if ENABLE(SVG)
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "IntSize.h"
+#include "Path.h"
+#include "RenderSVGResourceContainer.h"
+#include "SVGClipPathElement.h"
+#include "SVGUnitTypes.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+struct ClipperData : FastAllocBase {
+ OwnPtr<ImageBuffer> clipMaskImage;
+};
+
+class RenderSVGResourceClipper : public RenderSVGResourceContainer {
+public:
+ RenderSVGResourceClipper(SVGClipPathElement*);
+ virtual ~RenderSVGResourceClipper();
+
+ virtual const char* renderName() const { return "RenderSVGResourceClipper"; }
+
+ virtual void removeAllClientsFromCache(bool markForInvalidation = true);
+ virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true);
+
+ virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode);
+ virtual FloatRect resourceBoundingBox(RenderObject*);
+
+ virtual RenderSVGResourceType resourceType() const { return ClipperResourceType; }
+
+ bool hitTestClipContent(const FloatRect&, const FloatPoint&);
+
+ SVGUnitTypes::SVGUnitType clipPathUnits() const { return toUnitType(static_cast<SVGClipPathElement*>(node())->clipPathUnits()); }
+
+ static RenderSVGResourceType s_resourceType;
+private:
+ // clipPath can be clipped too, but don't have a boundingBox or repaintRect. So we can't call
+ // applyResource directly and use the rects from the object, since they are empty for RenderSVGResources
+ bool applyClippingToContext(RenderObject*, const FloatRect&, const FloatRect&, GraphicsContext*);
+ bool pathOnlyClipping(GraphicsContext*, const FloatRect&);
+ bool drawContentIntoMaskImage(ClipperData*, const FloatRect& objectBoundingBox);
+ void calculateClipContentRepaintRect();
+
+ bool m_invalidationBlocked;
+ FloatRect m_clipBoundaries;
+ HashMap<RenderObject*, ClipperData*> m_clipper;
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp
new file mode 100644
index 0000000..2a8a47f
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp
@@ -0,0 +1,192 @@
+/*
+ * 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 "RenderSVGResourceContainer.h"
+
+#include "RenderSVGShadowTreeRootContainer.h"
+#include "SVGStyledTransformableElement.h"
+
+namespace WebCore {
+
+static inline SVGDocumentExtensions* svgExtensionsFromNode(Node* node)
+{
+ ASSERT(node);
+ ASSERT(node->document());
+ return node->document()->accessSVGExtensions();
+}
+
+RenderSVGResourceContainer::RenderSVGResourceContainer(SVGStyledElement* node)
+ : RenderSVGHiddenContainer(node)
+ , m_id(node->hasID() ? node->getIdAttribute() : nullAtom)
+ , m_registered(false)
+{
+}
+
+RenderSVGResourceContainer::~RenderSVGResourceContainer()
+{
+ if (m_registered)
+ svgExtensionsFromNode(node())->removeResource(m_id);
+}
+
+void RenderSVGResourceContainer::layout()
+{
+ // Invalidate all resources if our layout changed.
+ if (m_everHadLayout && selfNeedsLayout())
+ removeAllClientsFromCache();
+
+ RenderSVGHiddenContainer::layout();
+}
+
+void RenderSVGResourceContainer::destroy()
+{
+ SVGResourcesCache::resourceDestroyed(this);
+ RenderSVGHiddenContainer::destroy();
+}
+
+void RenderSVGResourceContainer::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+ RenderSVGHiddenContainer::styleDidChange(diff, oldStyle);
+
+ if (!m_registered) {
+ m_registered = true;
+ registerResource();
+ }
+}
+
+void RenderSVGResourceContainer::idChanged()
+{
+ // Invalidate all our current clients.
+ removeAllClientsFromCache();
+
+ // Remove old id, that is guaranteed to be present in cache.
+ SVGDocumentExtensions* extensions = svgExtensionsFromNode(node());
+ extensions->removeResource(m_id);
+ m_id = static_cast<Element*>(node())->getIdAttribute();
+
+ registerResource();
+}
+
+void RenderSVGResourceContainer::markAllClientsForInvalidation(InvalidationMode mode)
+{
+ if (m_clients.isEmpty())
+ return;
+
+ bool needsLayout = mode == LayoutAndBoundariesInvalidation;
+ bool markForInvalidation = mode != ParentOnlyInvalidation;
+
+ HashSet<RenderObject*>::iterator end = m_clients.end();
+ for (HashSet<RenderObject*>::iterator it = m_clients.begin(); it != end; ++it) {
+ RenderObject* client = *it;
+ if (client->isSVGResourceContainer()) {
+ client->toRenderSVGResourceContainer()->removeAllClientsFromCache(markForInvalidation);
+ continue;
+ }
+
+ if (markForInvalidation)
+ markClientForInvalidation(client, mode);
+
+ if (needsLayout)
+ client->setNeedsLayout(true);
+
+ // Invalidate resources in ancestor chain, if needed.
+ RenderObject* current = client->parent();
+ while (current) {
+ if (current->isSVGResourceContainer()) {
+ current->toRenderSVGResourceContainer()->removeAllClientsFromCache(markForInvalidation);
+ break;
+ }
+
+ current = current->parent();
+ }
+ }
+}
+
+void RenderSVGResourceContainer::markClientForInvalidation(RenderObject* client, InvalidationMode mode)
+{
+ ASSERT(client);
+ ASSERT(!m_clients.isEmpty());
+
+ switch (mode) {
+ case LayoutAndBoundariesInvalidation:
+ case BoundariesInvalidation:
+ client->setNeedsBoundariesUpdate();
+ break;
+ case RepaintInvalidation:
+ if (client->view())
+ client->repaint();
+ break;
+ case ParentOnlyInvalidation:
+ break;
+ }
+}
+
+void RenderSVGResourceContainer::addClient(RenderObject* client)
+{
+ ASSERT(client);
+ m_clients.add(client);
+}
+
+void RenderSVGResourceContainer::removeClient(RenderObject* client)
+{
+ ASSERT(client);
+ m_clients.remove(client);
+}
+
+void RenderSVGResourceContainer::registerResource()
+{
+ SVGDocumentExtensions* extensions = svgExtensionsFromNode(node());
+ if (!extensions->isPendingResource(m_id)) {
+ extensions->addResource(m_id, this);
+ return;
+ }
+
+ OwnPtr<SVGDocumentExtensions::SVGPendingElements> clients(extensions->removePendingResource(m_id));
+
+ // Cache us with the new id.
+ extensions->addResource(m_id, this);
+
+ // Update cached resources of pending clients.
+ const SVGDocumentExtensions::SVGPendingElements::const_iterator end = clients->end();
+ for (SVGDocumentExtensions::SVGPendingElements::const_iterator it = clients->begin(); it != end; ++it) {
+ RenderObject* renderer = (*it)->renderer();
+ if (!renderer)
+ continue;
+ SVGResourcesCache::clientUpdatedFromElement(renderer, renderer->style());
+ renderer->setNeedsLayout(true);
+ }
+}
+
+// FIXME: This does not belong here.
+AffineTransform RenderSVGResourceContainer::transformOnNonScalingStroke(RenderObject* object, const AffineTransform& resourceTransform)
+{
+ if (!object->isSVGPath())
+ return resourceTransform;
+
+ SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(object->node());
+ AffineTransform transform = resourceTransform;
+ transform.multiply(element->getScreenCTM(SVGLocatable::DisallowStyleUpdate));
+ return transform;
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.h b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.h
new file mode 100644
index 0000000..d98a83a
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#ifndef RenderSVGResourceContainer_h
+#define RenderSVGResourceContainer_h
+
+#if ENABLE(SVG)
+#include "RenderSVGHiddenContainer.h"
+#include "RenderSVGResource.h"
+
+namespace WebCore {
+
+class RenderSVGResourceContainer : public RenderSVGHiddenContainer,
+ public RenderSVGResource {
+public:
+ RenderSVGResourceContainer(SVGStyledElement*);
+ virtual ~RenderSVGResourceContainer();
+
+ virtual void layout();
+ virtual void destroy();
+ virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+
+ virtual bool isSVGResourceContainer() const { return true; }
+ virtual RenderSVGResourceContainer* toRenderSVGResourceContainer() { return this; }
+
+ static AffineTransform transformOnNonScalingStroke(RenderObject*, const AffineTransform& resourceTransform);
+
+ void idChanged();
+
+protected:
+ enum InvalidationMode {
+ LayoutAndBoundariesInvalidation,
+ BoundariesInvalidation,
+ RepaintInvalidation,
+ ParentOnlyInvalidation
+ };
+
+ // Used from the invalidateClient/invalidateClients methods from classes, inheriting from us.
+ void markAllClientsForInvalidation(InvalidationMode);
+ void markClientForInvalidation(RenderObject*, InvalidationMode);
+
+private:
+ friend class SVGResourcesCache;
+ void addClient(RenderObject*);
+ void removeClient(RenderObject*);
+
+private:
+ void registerResource();
+
+ AtomicString m_id;
+ bool m_registered;
+ HashSet<RenderObject*> m_clients;
+};
+
+inline RenderSVGResourceContainer* getRenderSVGResourceContainerById(Document* document, const AtomicString& id)
+{
+ if (id.isEmpty())
+ return 0;
+
+ if (RenderSVGResourceContainer* renderResource = document->accessSVGExtensions()->resourceById(id))
+ return renderResource;
+
+ return 0;
+}
+
+template<typename Renderer>
+Renderer* getRenderSVGResourceById(Document* document, const AtomicString& id)
+{
+ if (RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id))
+ return container->cast<Renderer>();
+
+ return 0;
+}
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp
new file mode 100644
index 0000000..4ba4e0a
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 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) && ENABLE(FILTERS)
+#include "RenderSVGResourceFilter.h"
+
+#include "AffineTransform.h"
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "Image.h"
+#include "ImageBuffer.h"
+#include "ImageData.h"
+#include "IntRect.h"
+#include "RenderSVGResource.h"
+#include "RenderSVGResourceFilterPrimitive.h"
+#include "SVGElement.h"
+#include "SVGFilter.h"
+#include "SVGFilterElement.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+#include "SVGImageBufferTools.h"
+#include "SVGNames.h"
+#include "SVGStyledElement.h"
+#include "SVGUnitTypes.h"
+
+#include <wtf/UnusedParam.h>
+#include <wtf/Vector.h>
+
+static const float kMaxFilterSize = 5000.0f;
+
+using namespace std;
+
+namespace WebCore {
+
+RenderSVGResourceType RenderSVGResourceFilter::s_resourceType = FilterResourceType;
+
+RenderSVGResourceFilter::RenderSVGResourceFilter(SVGFilterElement* node)
+ : RenderSVGResourceContainer(node)
+{
+}
+
+RenderSVGResourceFilter::~RenderSVGResourceFilter()
+{
+ if (m_filter.isEmpty())
+ return;
+
+ deleteAllValues(m_filter);
+ m_filter.clear();
+}
+
+void RenderSVGResourceFilter::removeAllClientsFromCache(bool markForInvalidation)
+{
+ if (!m_filter.isEmpty()) {
+ deleteAllValues(m_filter);
+ m_filter.clear();
+ }
+
+ markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
+}
+
+void RenderSVGResourceFilter::removeClientFromCache(RenderObject* client, bool markForInvalidation)
+{
+ ASSERT(client);
+
+ if (m_filter.contains(client))
+ delete m_filter.take(client);
+
+ markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
+}
+
+PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(Filter* filter)
+{
+ SVGFilterElement* filterElement = static_cast<SVGFilterElement*>(node());
+ bool primitiveBoundingBoxMode = filterElement->primitiveUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX;
+
+ // Add effects to the builder
+ RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(filter);
+ for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) {
+ if (!node->isSVGElement())
+ continue;
+
+ SVGElement* element = static_cast<SVGElement*>(node);
+ if (!element->isFilterEffect())
+ continue;
+
+ SVGFilterPrimitiveStandardAttributes* effectElement = static_cast<SVGFilterPrimitiveStandardAttributes*>(element);
+ RefPtr<FilterEffect> effect = effectElement->build(builder.get(), filter);
+ if (!effect) {
+ builder->clearEffects();
+ return 0;
+ }
+ builder->appendEffectToEffectReferences(effect);
+ effectElement->setStandardAttributes(primitiveBoundingBoxMode, effect.get());
+ builder->add(effectElement->result(), effect);
+ }
+ return builder.release();
+}
+
+bool RenderSVGResourceFilter::fitsInMaximumImageSize(const FloatSize& size, FloatSize& scale)
+{
+ bool matchesFilterSize = true;
+ if (size.width() > kMaxFilterSize) {
+ scale.setWidth(scale.width() * kMaxFilterSize / size.width());
+ matchesFilterSize = false;
+ }
+ if (size.height() > kMaxFilterSize) {
+ scale.setHeight(scale.height() * kMaxFilterSize / size.height());
+ matchesFilterSize = false;
+ }
+
+ return matchesFilterSize;
+}
+
+bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode)
+{
+ ASSERT(object);
+ ASSERT(context);
+#ifndef NDEBUG
+ ASSERT(resourceMode == ApplyToDefaultMode);
+#else
+ UNUSED_PARAM(resourceMode);
+#endif
+
+ // Returning false here, to avoid drawings onto the context. We just want to
+ // draw the stored filter output, not the unfiltered object as well.
+ if (m_filter.contains(object)) {
+ FilterData* filterData = m_filter.get(object);
+ if (filterData->builded)
+ return false;
+
+ delete m_filter.take(object); // Oops, have to rebuild, go through normal code path
+ }
+
+ OwnPtr<FilterData> filterData(new FilterData);
+ FloatRect targetBoundingBox = object->objectBoundingBox();
+
+ SVGFilterElement* filterElement = static_cast<SVGFilterElement*>(node());
+ filterData->boundaries = filterElement->filterBoundingBox(targetBoundingBox);
+ if (filterData->boundaries.isEmpty())
+ return false;
+
+ // Determine absolute transformation matrix for filter.
+ AffineTransform absoluteTransform;
+ SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform);
+ if (!absoluteTransform.isInvertible())
+ return false;
+
+ // Eliminate shear of the absolute transformation matrix, to be able to produce unsheared tile images for feTile.
+ filterData->shearFreeAbsoluteTransform = AffineTransform(absoluteTransform.xScale(), 0, 0, absoluteTransform.yScale(), absoluteTransform.e(), absoluteTransform.f());
+
+ // Determine absolute boundaries of the filter and the drawing region.
+ FloatRect absoluteFilterBoundaries = filterData->shearFreeAbsoluteTransform.mapRect(filterData->boundaries);
+ FloatRect drawingRegion = object->strokeBoundingBox();
+ drawingRegion.intersect(filterData->boundaries);
+ FloatRect absoluteDrawingRegion = filterData->shearFreeAbsoluteTransform.mapRect(drawingRegion);
+
+ // Create the SVGFilter object.
+ bool primitiveBoundingBoxMode = filterElement->primitiveUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX;
+ filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransform, absoluteDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode);
+
+ // Create all relevant filter primitives.
+ filterData->builder = buildPrimitives(filterData->filter.get());
+ if (!filterData->builder)
+ return false;
+
+ // Calculate the scale factor for the use of filterRes.
+ // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion
+ FloatSize scale(1, 1);
+ if (filterElement->hasAttribute(SVGNames::filterResAttr)) {
+ scale.setWidth(filterElement->filterResX() / absoluteFilterBoundaries.width());
+ scale.setHeight(filterElement->filterResY() / absoluteFilterBoundaries.height());
+ }
+
+ if (scale.isEmpty())
+ return false;
+
+ // Determine scale factor for filter. The size of intermediate ImageBuffers shouldn't be bigger than kMaxFilterSize.
+ FloatRect tempSourceRect = absoluteDrawingRegion;
+ tempSourceRect.scale(scale.width(), scale.height());
+ fitsInMaximumImageSize(tempSourceRect.size(), scale);
+
+ // Set the scale level in SVGFilter.
+ filterData->filter->setFilterResolution(scale);
+
+ FilterEffect* lastEffect = filterData->builder->lastEffect();
+ if (!lastEffect)
+ return false;
+
+ RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect, filterData->filter.get());
+ FloatRect subRegion = lastEffect->maxEffectRect();
+ // At least one FilterEffect has a too big image size,
+ // recalculate the effect sizes with new scale factors.
+ if (!fitsInMaximumImageSize(subRegion.size(), scale)) {
+ filterData->filter->setFilterResolution(scale);
+ RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect, filterData->filter.get());
+ }
+
+ // If the drawingRegion is empty, we have something like <g filter=".."/>.
+ // Even if the target objectBoundingBox() is empty, we still have to draw the last effect result image in postApplyResource.
+ if (drawingRegion.isEmpty()) {
+ ASSERT(!m_filter.contains(object));
+ filterData->savedContext = context;
+ m_filter.set(object, filterData.leakPtr());
+ return false;
+ }
+
+ absoluteDrawingRegion.scale(scale.width(), scale.height());
+
+ OwnPtr<ImageBuffer> sourceGraphic;
+ if (!SVGImageBufferTools::createImageBuffer(absoluteDrawingRegion, absoluteDrawingRegion, sourceGraphic, ColorSpaceLinearRGB)) {
+ ASSERT(!m_filter.contains(object));
+ filterData->savedContext = context;
+ m_filter.set(object, filterData.leakPtr());
+ return false;
+ }
+
+ GraphicsContext* sourceGraphicContext = sourceGraphic->context();
+ ASSERT(sourceGraphicContext);
+
+ sourceGraphicContext->translate(-absoluteDrawingRegion.x(), -absoluteDrawingRegion.y());
+ if (scale.width() != 1 || scale.height() != 1)
+ sourceGraphicContext->scale(scale);
+
+ sourceGraphicContext->concatCTM(filterData->shearFreeAbsoluteTransform);
+ sourceGraphicContext->clearRect(FloatRect(FloatPoint(), absoluteDrawingRegion.size()));
+ filterData->sourceGraphicBuffer = sourceGraphic.release();
+ filterData->savedContext = context;
+
+ context = sourceGraphicContext;
+
+ ASSERT(!m_filter.contains(object));
+ m_filter.set(object, filterData.leakPtr());
+
+ return true;
+}
+
+void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsContext*& context, unsigned short resourceMode, const Path*)
+{
+ ASSERT(object);
+ ASSERT(context);
+#ifndef NDEBUG
+ ASSERT(resourceMode == ApplyToDefaultMode);
+#else
+ UNUSED_PARAM(resourceMode);
+#endif
+
+ if (!m_filter.contains(object))
+ return;
+
+ FilterData* filterData = m_filter.get(object);
+ if (!filterData->builded) {
+ if (!filterData->savedContext) {
+ removeClientFromCache(object);
+ return;
+ }
+
+ context = filterData->savedContext;
+ filterData->savedContext = 0;
+#if !PLATFORM(CG)
+ if (filterData->sourceGraphicBuffer)
+ filterData->sourceGraphicBuffer->transformColorSpace(ColorSpaceDeviceRGB, ColorSpaceLinearRGB);
+#endif
+ }
+
+ FilterEffect* lastEffect = filterData->builder->lastEffect();
+
+ if (lastEffect && !filterData->boundaries.isEmpty() && !lastEffect->filterPrimitiveSubregion().isEmpty()) {
+ // This is the real filtering of the object. It just needs to be called on the
+ // initial filtering process. We just take the stored filter result on a
+ // second drawing.
+ if (!filterData->builded) {
+ filterData->filter->setSourceImage(filterData->sourceGraphicBuffer.release());
+ lastEffect->apply();
+#if !PLATFORM(CG)
+ ImageBuffer* resultImage = lastEffect->asImageBuffer();
+ if (resultImage)
+ resultImage->transformColorSpace(ColorSpaceLinearRGB, ColorSpaceDeviceRGB);
+#endif
+ filterData->builded = true;
+ }
+
+ ImageBuffer* resultImage = lastEffect->asImageBuffer();
+ if (resultImage) {
+ context->concatCTM(filterData->shearFreeAbsoluteTransform.inverse());
+
+ context->scale(FloatSize(1 / filterData->filter->filterResolution().width(), 1 / filterData->filter->filterResolution().height()));
+ context->clip(lastEffect->maxEffectRect());
+ context->drawImageBuffer(resultImage, object->style()->colorSpace(), lastEffect->absolutePaintRect());
+ context->scale(filterData->filter->filterResolution());
+
+ context->concatCTM(filterData->shearFreeAbsoluteTransform);
+ }
+ }
+ filterData->sourceGraphicBuffer.clear();
+}
+
+FloatRect RenderSVGResourceFilter::resourceBoundingBox(RenderObject* object)
+{
+ if (SVGFilterElement* element = static_cast<SVGFilterElement*>(node()))
+ return element->filterBoundingBox(object->objectBoundingBox());
+
+ return FloatRect();
+}
+
+}
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h
new file mode 100644
index 0000000..f9a15ce
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 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.
+ */
+
+#ifndef RenderSVGResourceFilter_h
+#define RenderSVGResourceFilter_h
+
+#if ENABLE(SVG) && ENABLE(FILTERS)
+#include "FloatRect.h"
+#include "ImageBuffer.h"
+#include "RenderSVGResourceContainer.h"
+#include "SVGFilter.h"
+#include "SVGFilterBuilder.h"
+#include "SVGFilterElement.h"
+#include "SVGUnitTypes.h"
+
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+struct FilterData {
+ FilterData()
+ : savedContext(0)
+ , builded(false)
+ {
+ }
+
+ RefPtr<SVGFilter> filter;
+ RefPtr<SVGFilterBuilder> builder;
+ OwnPtr<ImageBuffer> sourceGraphicBuffer;
+ GraphicsContext* savedContext;
+ AffineTransform shearFreeAbsoluteTransform;
+ FloatRect boundaries;
+ FloatSize scale;
+ bool builded;
+};
+
+class GraphicsContext;
+
+class RenderSVGResourceFilter : public RenderSVGResourceContainer {
+public:
+ RenderSVGResourceFilter(SVGFilterElement*);
+ virtual ~RenderSVGResourceFilter();
+
+ virtual const char* renderName() const { return "RenderSVGResourceFilter"; }
+
+ virtual void removeAllClientsFromCache(bool markForInvalidation = true);
+ virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true);
+
+ virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode);
+ virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*);
+
+ virtual FloatRect resourceBoundingBox(RenderObject*);
+
+ PassRefPtr<SVGFilterBuilder> buildPrimitives(Filter*);
+
+ SVGUnitTypes::SVGUnitType filterUnits() const { return toUnitType(static_cast<SVGFilterElement*>(node())->filterUnits()); }
+ SVGUnitTypes::SVGUnitType primitiveUnits() const { return toUnitType(static_cast<SVGFilterElement*>(node())->primitiveUnits()); }
+
+ virtual RenderSVGResourceType resourceType() const { return s_resourceType; }
+ static RenderSVGResourceType s_resourceType;
+
+private:
+ bool fitsInMaximumImageSize(const FloatSize&, FloatSize&);
+
+ HashMap<RenderObject*, FilterData*> m_filter;
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp
new file mode 100644
index 0000000..fc7362e
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 University of Szeged
+ * Copyright (C) 2010 Zoltan Herczeg
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG) && ENABLE(FILTERS)
+#include "RenderSVGResourceFilterPrimitive.h"
+
+#include "SVGFEImage.h"
+
+namespace WebCore {
+
+FloatRect RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(FilterEffect* effect, SVGFilter* filter)
+{
+ FloatRect uniteRect;
+ FloatRect subregionBoundingBox = effect->effectBoundaries();
+ FloatRect subregion = subregionBoundingBox;
+
+ if (effect->filterEffectType() != FilterEffectTypeTile) {
+ // FETurbulence, FEImage and FEFlood don't have input effects, take the filter region as unite rect.
+ if (unsigned numberOfInputEffects = effect->inputEffects().size()) {
+ for (unsigned i = 0; i < numberOfInputEffects; ++i)
+ uniteRect.unite(determineFilterPrimitiveSubregion(effect->inputEffect(i), filter));
+ } else
+ uniteRect = filter->filterRegionInUserSpace();
+ } else {
+ determineFilterPrimitiveSubregion(effect->inputEffect(0), filter);
+ uniteRect = filter->filterRegionInUserSpace();
+ }
+
+ if (filter->effectBoundingBoxMode()) {
+ subregion = uniteRect;
+ // Avoid the calling of a virtual method several times.
+ FloatRect targetBoundingBox = filter->targetBoundingBox();
+
+ if (effect->hasX())
+ subregion.setX(targetBoundingBox.x() + subregionBoundingBox.x() * targetBoundingBox.width());
+
+ if (effect->hasY())
+ subregion.setY(targetBoundingBox.y() + subregionBoundingBox.y() * targetBoundingBox.height());
+
+ if (effect->hasWidth())
+ subregion.setWidth(subregionBoundingBox.width() * targetBoundingBox.width());
+
+ if (effect->hasHeight())
+ subregion.setHeight(subregionBoundingBox.height() * targetBoundingBox.height());
+ } else {
+ if (!effect->hasX())
+ subregion.setX(uniteRect.x());
+
+ if (!effect->hasY())
+ subregion.setY(uniteRect.y());
+
+ if (!effect->hasWidth())
+ subregion.setWidth(uniteRect.width());
+
+ if (!effect->hasHeight())
+ subregion.setHeight(uniteRect.height());
+ }
+
+ effect->setFilterPrimitiveSubregion(subregion);
+
+ FloatRect absoluteSubregion = filter->mapLocalRectToAbsoluteRect(subregion);
+ FloatSize filterResolution = filter->filterResolution();
+ absoluteSubregion.scale(filterResolution.width(), filterResolution.height());
+
+ // FEImage needs the unclipped subregion in absolute coordinates to determine the correct
+ // destination rect in combination with preserveAspectRatio.
+ if (effect->filterEffectType() == FilterEffectTypeImage)
+ reinterpret_cast<FEImage*>(effect)->setAbsoluteSubregion(absoluteSubregion);
+
+ // Clip every filter effect to the filter region.
+ FloatRect absoluteScaledFilterRegion = filter->filterRegion();
+ absoluteScaledFilterRegion.scale(filterResolution.width(), filterResolution.height());
+ absoluteSubregion.intersect(absoluteScaledFilterRegion);
+
+ effect->setMaxEffectRect(enclosingIntRect(absoluteSubregion));
+ return subregion;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG) && ENABLE(FILTERS)
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h
new file mode 100644
index 0000000..f25f62e
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 University of Szeged
+ * Copyright (C) 2010 Zoltan Herczeg
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RenderSVGResourceFilterPrimitive_h
+#define RenderSVGResourceFilterPrimitive_h
+
+#if ENABLE(SVG) && ENABLE(FILTERS)
+
+#include "RenderSVGHiddenContainer.h"
+#include "SVGFilter.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace WebCore {
+
+class RenderSVGResourceFilterPrimitive : public RenderSVGHiddenContainer {
+public:
+
+ explicit RenderSVGResourceFilterPrimitive(SVGFilterPrimitiveStandardAttributes* filterPrimitiveElement)
+ : RenderSVGHiddenContainer(filterPrimitiveElement)
+ {
+ }
+
+ // They depend on the RenderObject argument of RenderSVGResourceFilter::applyResource.
+ static FloatRect determineFilterPrimitiveSubregion(FilterEffect*, SVGFilter*);
+
+private:
+ virtual const char* renderName() const { return "RenderSVGResourceFilterPrimitive"; }
+ virtual bool isSVGResourceFilterPrimitive() const { return true; }
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG) && ENABLE(FILTERS)
+
+#endif // RenderSVGResourceFilterPrimitive_h
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp
new file mode 100644
index 0000000..5ad5d84
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 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 "RenderSVGResourceGradient.h"
+
+#include "GradientAttributes.h"
+#include "GraphicsContext.h"
+#include "RenderSVGText.h"
+#include "SVGImageBufferTools.h"
+#include "SVGRenderSupport.h"
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+RenderSVGResourceGradient::RenderSVGResourceGradient(SVGGradientElement* node)
+ : RenderSVGResourceContainer(node)
+ , m_shouldCollectGradientAttributes(true)
+#if PLATFORM(CG)
+ , m_savedContext(0)
+#endif
+{
+}
+
+RenderSVGResourceGradient::~RenderSVGResourceGradient()
+{
+ if (m_gradient.isEmpty())
+ return;
+
+ deleteAllValues(m_gradient);
+ m_gradient.clear();
+}
+
+void RenderSVGResourceGradient::removeAllClientsFromCache(bool markForInvalidation)
+{
+ if (!m_gradient.isEmpty()) {
+ deleteAllValues(m_gradient);
+ m_gradient.clear();
+ }
+
+ m_shouldCollectGradientAttributes = true;
+ markAllClientsForInvalidation(markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation);
+}
+
+void RenderSVGResourceGradient::removeClientFromCache(RenderObject* client, bool markForInvalidation)
+{
+ ASSERT(client);
+
+ if (m_gradient.contains(client))
+ delete m_gradient.take(client);
+
+ markClientForInvalidation(client, markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation);
+}
+
+#if PLATFORM(CG)
+static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& context,
+ GraphicsContext*& savedContext,
+ OwnPtr<ImageBuffer>& imageBuffer,
+ RenderObject* object)
+{
+ RenderObject* textRootBlock = RenderSVGText::locateRenderSVGTextAncestor(object);
+ ASSERT(textRootBlock);
+
+ AffineTransform absoluteTransform;
+ SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform);
+
+ FloatRect absoluteTargetRect = absoluteTransform.mapRect(textRootBlock->repaintRectInLocalCoordinates());
+ FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(textRootBlock, absoluteTargetRect);
+ if (clampedAbsoluteTargetRect.isEmpty())
+ return false;
+
+ OwnPtr<ImageBuffer> maskImage;
+ if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, maskImage, ColorSpaceDeviceRGB))
+ return false;
+
+ GraphicsContext* maskImageContext = maskImage->context();
+ ASSERT(maskImageContext);
+
+ maskImageContext->translate(-clampedAbsoluteTargetRect.x(), -clampedAbsoluteTargetRect.y());
+ maskImageContext->concatCTM(absoluteTransform);
+
+ ASSERT(maskImage);
+ savedContext = context;
+ context = maskImageContext;
+ imageBuffer = maskImage.release();
+ return true;
+}
+
+static inline AffineTransform clipToTextMask(GraphicsContext* context,
+ OwnPtr<ImageBuffer>& imageBuffer,
+ FloatRect& targetRect,
+ RenderObject* object,
+ bool boundingBoxMode,
+ const AffineTransform& gradientTransform)
+{
+ RenderObject* textRootBlock = RenderSVGText::locateRenderSVGTextAncestor(object);
+ ASSERT(textRootBlock);
+
+ targetRect = textRootBlock->repaintRectInLocalCoordinates();
+
+ AffineTransform absoluteTransform;
+ SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform);
+
+ FloatRect absoluteTargetRect = absoluteTransform.mapRect(targetRect);
+ FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(textRootBlock, absoluteTargetRect);
+
+ SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, clampedAbsoluteTargetRect, imageBuffer);
+
+ AffineTransform matrix;
+ if (boundingBoxMode) {
+ FloatRect maskBoundingBox = textRootBlock->objectBoundingBox();
+ matrix.translate(maskBoundingBox.x(), maskBoundingBox.y());
+ matrix.scaleNonUniform(maskBoundingBox.width(), maskBoundingBox.height());
+ }
+ matrix.multLeft(gradientTransform);
+ return matrix;
+}
+#endif
+
+bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode)
+{
+ ASSERT(object);
+ ASSERT(style);
+ ASSERT(context);
+ ASSERT(resourceMode != ApplyToDefaultMode);
+
+ // Be sure to synchronize all SVG properties on the gradientElement _before_ processing any further.
+ // Otherwhise the call to collectGradientAttributes() in createTileImage(), may cause the SVG DOM property
+ // synchronization to kick in, which causes removeAllClientsFromCache() to be called, which in turn deletes our
+ // GradientData object! Leaving out the line below will cause svg/dynamic-updates/SVG*GradientElement-svgdom* to crash.
+ SVGGradientElement* gradientElement = static_cast<SVGGradientElement*>(node());
+ if (!gradientElement)
+ return false;
+
+ if (m_shouldCollectGradientAttributes) {
+ gradientElement->updateAnimatedSVGAttribute(anyQName());
+ collectGradientAttributes(gradientElement);
+ m_shouldCollectGradientAttributes = false;
+ }
+
+ // Spec: When the geometry of the applicable element has no width or height and objectBoundingBox is specified,
+ // then the given effect (e.g. a gradient or a filter) will be ignored.
+ FloatRect objectBoundingBox = object->objectBoundingBox();
+ if (boundingBoxMode() && objectBoundingBox.isEmpty())
+ return false;
+
+ if (!m_gradient.contains(object))
+ m_gradient.set(object, new GradientData);
+
+ GradientData* gradientData = m_gradient.get(object);
+ bool isPaintingText = resourceMode & ApplyToTextMode;
+
+ // Create gradient object
+ if (!gradientData->gradient) {
+ buildGradient(gradientData, gradientElement);
+
+ // CG platforms will handle the gradient space transform for text after applying the
+ // resource, so don't apply it here. For non-CG platforms, we want the text bounding
+ // box applied to the gradient space transform now, so the gradient shader can use it.
+#if PLATFORM(CG)
+ if (boundingBoxMode() && !objectBoundingBox.isEmpty() && !isPaintingText) {
+#else
+ if (boundingBoxMode() && !objectBoundingBox.isEmpty()) {
+#endif
+ gradientData->userspaceTransform.translate(objectBoundingBox.x(), objectBoundingBox.y());
+ gradientData->userspaceTransform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
+ }
+
+ AffineTransform gradientTransform;
+ calculateGradientTransform(gradientTransform);
+
+ gradientData->userspaceTransform.multLeft(gradientTransform);
+ gradientData->gradient->setGradientSpaceTransform(gradientData->userspaceTransform);
+ }
+
+ if (!gradientData->gradient)
+ return false;
+
+ // Draw gradient
+ context->save();
+
+ if (isPaintingText) {
+#if PLATFORM(CG)
+ if (!createMaskAndSwapContextForTextGradient(context, m_savedContext, m_imageBuffer, object)) {
+ context->restore();
+ return false;
+ }
+#endif
+
+ context->setTextDrawingMode(resourceMode & ApplyToFillMode ? TextModeFill : TextModeStroke);
+ }
+
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+ ASSERT(svgStyle);
+
+ if (resourceMode & ApplyToFillMode) {
+ context->setAlpha(svgStyle->fillOpacity());
+ context->setFillGradient(gradientData->gradient);
+ context->setFillRule(svgStyle->fillRule());
+ } else if (resourceMode & ApplyToStrokeMode) {
+ if (svgStyle->vectorEffect() == VE_NON_SCALING_STROKE)
+ gradientData->gradient->setGradientSpaceTransform(transformOnNonScalingStroke(object, gradientData->userspaceTransform));
+ context->setAlpha(svgStyle->strokeOpacity());
+ context->setStrokeGradient(gradientData->gradient);
+ SVGRenderSupport::applyStrokeStyleToContext(context, style, object);
+ }
+
+ return true;
+}
+
+void RenderSVGResourceGradient::postApplyResource(RenderObject* object, GraphicsContext*& context, unsigned short resourceMode, const Path* path)
+{
+ ASSERT(context);
+ ASSERT(resourceMode != ApplyToDefaultMode);
+
+ if (resourceMode & ApplyToTextMode) {
+#if PLATFORM(CG)
+ // CG requires special handling for gradient on text
+ if (m_savedContext && m_gradient.contains(object)) {
+ GradientData* gradientData = m_gradient.get(object);
+
+ // Restore on-screen drawing context
+ context = m_savedContext;
+ m_savedContext = 0;
+
+ AffineTransform gradientTransform;
+ calculateGradientTransform(gradientTransform);
+
+ FloatRect targetRect;
+ gradientData->gradient->setGradientSpaceTransform(clipToTextMask(context, m_imageBuffer, targetRect, object, boundingBoxMode(), gradientTransform));
+ context->setFillGradient(gradientData->gradient);
+
+ context->fillRect(targetRect);
+ m_imageBuffer.clear();
+ }
+#else
+ UNUSED_PARAM(object);
+#endif
+ } else if (path) {
+ if (resourceMode & ApplyToFillMode)
+ context->fillPath(*path);
+ else if (resourceMode & ApplyToStrokeMode)
+ context->strokePath(*path);
+ }
+
+ context->restore();
+}
+
+void RenderSVGResourceGradient::addStops(GradientData* gradientData, const Vector<Gradient::ColorStop>& stops) const
+{
+ ASSERT(gradientData->gradient);
+
+ const Vector<Gradient::ColorStop>::const_iterator end = stops.end();
+ for (Vector<Gradient::ColorStop>::const_iterator it = stops.begin(); it != end; ++it)
+ gradientData->gradient->addColorStop(*it);
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h
new file mode 100644
index 0000000..ad40b53
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2008 Eric Seidel <eric@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.
+ */
+
+#ifndef RenderSVGResourceGradient_h
+#define RenderSVGResourceGradient_h
+
+#if ENABLE(SVG)
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "Gradient.h"
+#include "ImageBuffer.h"
+#include "RenderSVGResourceContainer.h"
+#include "SVGGradientElement.h"
+
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+struct GradientData {
+ RefPtr<Gradient> gradient;
+ AffineTransform userspaceTransform;
+};
+
+class GraphicsContext;
+
+class RenderSVGResourceGradient : public RenderSVGResourceContainer {
+public:
+ RenderSVGResourceGradient(SVGGradientElement*);
+ virtual ~RenderSVGResourceGradient();
+
+ virtual void removeAllClientsFromCache(bool markForInvalidation = true);
+ virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true);
+
+ virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode);
+ virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*);
+ virtual FloatRect resourceBoundingBox(RenderObject*) { return FloatRect(); }
+
+protected:
+ void addStops(GradientData*, const Vector<Gradient::ColorStop>&) const;
+
+ virtual bool boundingBoxMode() const = 0;
+ virtual void calculateGradientTransform(AffineTransform&) = 0;
+ virtual void collectGradientAttributes(SVGGradientElement*) = 0;
+ virtual void buildGradient(GradientData*, SVGGradientElement*) const = 0;
+
+private:
+ bool m_shouldCollectGradientAttributes : 1;
+ HashMap<RenderObject*, GradientData*> m_gradient;
+
+#if PLATFORM(CG)
+ GraphicsContext* m_savedContext;
+ OwnPtr<ImageBuffer> m_imageBuffer;
+#endif
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp
new file mode 100644
index 0000000..14dbd8c
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.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 "RenderSVGResourceLinearGradient.h"
+
+#include "LinearGradientAttributes.h"
+#include "SVGLinearGradientElement.h"
+
+namespace WebCore {
+
+RenderSVGResourceType RenderSVGResourceLinearGradient::s_resourceType = LinearGradientResourceType;
+
+RenderSVGResourceLinearGradient::RenderSVGResourceLinearGradient(SVGLinearGradientElement* node)
+ : RenderSVGResourceGradient(node)
+{
+}
+
+RenderSVGResourceLinearGradient::~RenderSVGResourceLinearGradient()
+{
+}
+
+void RenderSVGResourceLinearGradient::collectGradientAttributes(SVGGradientElement* gradientElement)
+{
+ m_attributes = LinearGradientAttributes();
+ static_cast<SVGLinearGradientElement*>(gradientElement)->collectGradientAttributes(m_attributes);
+}
+
+void RenderSVGResourceLinearGradient::buildGradient(GradientData* gradientData, SVGGradientElement* gradientElement) const
+{
+ SVGLinearGradientElement* linearGradientElement = static_cast<SVGLinearGradientElement*>(gradientElement);
+
+ // Determine gradient start/end points
+ FloatPoint startPoint;
+ FloatPoint endPoint;
+ linearGradientElement->calculateStartEndPoints(m_attributes, startPoint, endPoint);
+
+ gradientData->gradient = Gradient::create(startPoint, endPoint);
+ gradientData->gradient->setSpreadMethod(m_attributes.spreadMethod());
+
+ // Add stops
+ addStops(gradientData, m_attributes.stops());
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.h b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.h
new file mode 100644
index 0000000..2d35418
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.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.
+ */
+
+#ifndef RenderSVGResourceLinearGradient_h
+#define RenderSVGResourceLinearGradient_h
+
+#if ENABLE(SVG)
+#include "LinearGradientAttributes.h"
+#include "RenderSVGResourceGradient.h"
+
+namespace WebCore {
+
+class SVGLinearGradientElement;
+
+class RenderSVGResourceLinearGradient : public RenderSVGResourceGradient {
+public:
+ RenderSVGResourceLinearGradient(SVGLinearGradientElement*);
+ virtual ~RenderSVGResourceLinearGradient();
+
+ virtual const char* renderName() const { return "RenderSVGResourceLinearGradient"; }
+
+ virtual RenderSVGResourceType resourceType() const { return s_resourceType; }
+ static RenderSVGResourceType s_resourceType;
+
+ virtual bool boundingBoxMode() const { return m_attributes.boundingBoxMode(); }
+ virtual void calculateGradientTransform(AffineTransform& transform) { transform = m_attributes.gradientTransform(); }
+ virtual void collectGradientAttributes(SVGGradientElement*);
+ virtual void buildGradient(GradientData*, SVGGradientElement*) const;
+
+private:
+ LinearGradientAttributes m_attributes;
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp
new file mode 100644
index 0000000..2a68d92
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Rob Buis <buis@kde.org>
+ * Copyright (C) Research In Motion Limited 2009-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 "RenderSVGResourceMarker.h"
+
+#include "GraphicsContext.h"
+#include "RenderSVGContainer.h"
+#include "SVGElement.h"
+#include "SVGMarkerElement.h"
+#include "SVGRenderSupport.h"
+#include "SVGStyledElement.h"
+#include "SVGStyledTransformableElement.h"
+
+namespace WebCore {
+
+RenderSVGResourceType RenderSVGResourceMarker::s_resourceType = MarkerResourceType;
+
+RenderSVGResourceMarker::RenderSVGResourceMarker(SVGMarkerElement* node)
+ : RenderSVGResourceContainer(node)
+{
+}
+
+RenderSVGResourceMarker::~RenderSVGResourceMarker()
+{
+}
+
+void RenderSVGResourceMarker::layout()
+{
+ // Invalidate all resources if our layout changed.
+ if (m_everHadLayout && selfNeedsLayout())
+ removeAllClientsFromCache();
+
+ // RenderSVGHiddenContainer overwrites layout(). We need the
+ // layouting of RenderSVGContainer for calculating local
+ // transformations and repaint.
+ RenderSVGContainer::layout();
+}
+
+void RenderSVGResourceMarker::removeAllClientsFromCache(bool markForInvalidation)
+{
+ markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
+}
+
+void RenderSVGResourceMarker::removeClientFromCache(RenderObject* client, bool markForInvalidation)
+{
+ ASSERT(client);
+ markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
+}
+
+void RenderSVGResourceMarker::applyViewportClip(PaintInfo& paintInfo)
+{
+ if (SVGRenderSupport::isOverflowHidden(this))
+ paintInfo.context->clip(m_viewport);
+}
+
+FloatRect RenderSVGResourceMarker::markerBoundaries(const AffineTransform& markerTransformation) const
+{
+ FloatRect coordinates = RenderSVGContainer::repaintRectInLocalCoordinates();
+
+ // Map repaint rect into parent coordinate space, in which the marker boundaries have to be evaluated
+ coordinates = localToParentTransform().mapRect(coordinates);
+
+ return markerTransformation.mapRect(coordinates);
+}
+
+const AffineTransform& RenderSVGResourceMarker::localToParentTransform() const
+{
+ AffineTransform viewportTranslation(viewportTransform());
+ m_localToParentTransform = viewportTranslation.translateRight(m_viewport.x(), m_viewport.y());
+ return m_localToParentTransform;
+ // If this class were ever given a localTransform(), then the above would read:
+ // return viewportTransform() * localTransform() * viewportTranslation;
+}
+
+FloatPoint RenderSVGResourceMarker::referencePoint() const
+{
+ SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node());
+ ASSERT(marker);
+
+ return FloatPoint(marker->refX().value(marker), marker->refY().value(marker));
+}
+
+float RenderSVGResourceMarker::angle() const
+{
+ SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node());
+ ASSERT(marker);
+
+ float angle = -1;
+ if (marker->orientType() == SVGMarkerElement::SVG_MARKER_ORIENT_ANGLE)
+ angle = marker->orientAngle().value();
+
+ return angle;
+}
+
+AffineTransform RenderSVGResourceMarker::markerTransformation(const FloatPoint& origin, float autoAngle, float strokeWidth) const
+{
+ SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node());
+ ASSERT(marker);
+
+ float markerAngle = angle();
+ bool useStrokeWidth = (marker->markerUnits() == SVGMarkerElement::SVG_MARKERUNITS_STROKEWIDTH);
+
+ AffineTransform transform;
+ transform.translate(origin.x(), origin.y());
+ transform.rotate(markerAngle == -1 ? autoAngle : markerAngle);
+ transform = markerContentTransformation(transform, referencePoint(), useStrokeWidth ? strokeWidth : -1);
+ return transform;
+}
+
+void RenderSVGResourceMarker::draw(PaintInfo& paintInfo, const AffineTransform& transform)
+{
+ PaintInfo info(paintInfo);
+ info.context->save();
+ info.applyTransform(transform);
+ RenderSVGContainer::paint(info, 0, 0);
+ info.context->restore();
+}
+
+AffineTransform RenderSVGResourceMarker::markerContentTransformation(const AffineTransform& contentTransformation, const FloatPoint& origin, float strokeWidth) const
+{
+ // The 'origin' coordinate maps to SVGs refX/refY, given in coordinates relative to the viewport established by the marker
+ FloatPoint mappedOrigin = viewportTransform().mapPoint(origin);
+
+ AffineTransform transformation = contentTransformation;
+ if (strokeWidth != -1)
+ transformation.scaleNonUniform(strokeWidth, strokeWidth);
+
+ transformation.translate(-mappedOrigin.x(), -mappedOrigin.y());
+ return transformation;
+}
+
+AffineTransform RenderSVGResourceMarker::viewportTransform() const
+{
+ SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node());
+ ASSERT(marker);
+
+ return marker->viewBoxToViewTransform(m_viewport.width(), m_viewport.height());
+}
+
+void RenderSVGResourceMarker::calcViewport()
+{
+ if (!selfNeedsLayout())
+ return;
+
+ SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node());
+ ASSERT(marker);
+
+ float w = marker->markerWidth().value(marker);
+ float h = marker->markerHeight().value(marker);
+ m_viewport = FloatRect(0, 0, w, h);
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h
new file mode 100644
index 0000000..fd3b5e3
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-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.
+ */
+
+#ifndef RenderSVGResourceMarker_h
+#define RenderSVGResourceMarker_h
+
+#if ENABLE(SVG)
+#include "FloatRect.h"
+#include "RenderObject.h"
+#include "RenderSVGResourceContainer.h"
+#include "SVGMarkerElement.h"
+#include "SVGStyledElement.h"
+
+#include <wtf/HashSet.h>
+
+namespace WebCore {
+
+class AffineTransform;
+
+class RenderSVGResourceMarker : public RenderSVGResourceContainer {
+public:
+ RenderSVGResourceMarker(SVGMarkerElement*);
+ virtual ~RenderSVGResourceMarker();
+
+ virtual const char* renderName() const { return "RenderSVGResourceMarker"; }
+
+ virtual void removeAllClientsFromCache(bool markForInvalidation = true);
+ virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true);
+
+ void draw(PaintInfo&, const AffineTransform&);
+
+ // Calculates marker boundaries, mapped to the target element's coordinate space
+ FloatRect markerBoundaries(const AffineTransform& markerTransformation) const;
+
+ virtual void applyViewportClip(PaintInfo&);
+ virtual void layout();
+ virtual void calcViewport();
+
+ virtual const AffineTransform& localToParentTransform() const;
+ AffineTransform markerTransformation(const FloatPoint& origin, float angle, float strokeWidth) const;
+
+ virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short) { return false; }
+ virtual FloatRect resourceBoundingBox(RenderObject*) { return FloatRect(); }
+
+ FloatPoint referencePoint() const;
+ float angle() const;
+ SVGMarkerElement::SVGMarkerUnitsType markerUnits() const { return static_cast<SVGMarkerElement::SVGMarkerUnitsType>(static_cast<SVGMarkerElement*>(node())->markerUnits()); }
+
+ virtual RenderSVGResourceType resourceType() const { return s_resourceType; }
+ static RenderSVGResourceType s_resourceType;
+
+private:
+ // Generates a transformation matrix usable to render marker content. Handles scaling the marker content
+ // acording to SVGs markerUnits="strokeWidth" concept, when a strokeWidth value != -1 is passed in.
+ AffineTransform markerContentTransformation(const AffineTransform& contentTransformation, const FloatPoint& origin, float strokeWidth = -1) const;
+
+ AffineTransform viewportTransform() const;
+
+ mutable AffineTransform m_localToParentTransform;
+ FloatRect m_viewport;
+};
+
+}
+#endif
+
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp
new file mode 100644
index 0000000..7b24248
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-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 "RenderSVGResourceMasker.h"
+
+#include "AffineTransform.h"
+#include "Element.h"
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "Image.h"
+#include "ImageBuffer.h"
+#include "IntRect.h"
+#include "RenderSVGResource.h"
+#include "SVGElement.h"
+#include "SVGImageBufferTools.h"
+#include "SVGMaskElement.h"
+#include "SVGStyledElement.h"
+#include "SVGUnitTypes.h"
+
+#include <wtf/ByteArray.h>
+#include <wtf/UnusedParam.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+RenderSVGResourceType RenderSVGResourceMasker::s_resourceType = MaskerResourceType;
+
+RenderSVGResourceMasker::RenderSVGResourceMasker(SVGMaskElement* node)
+ : RenderSVGResourceContainer(node)
+{
+}
+
+RenderSVGResourceMasker::~RenderSVGResourceMasker()
+{
+ if (m_masker.isEmpty())
+ return;
+
+ deleteAllValues(m_masker);
+ m_masker.clear();
+}
+
+void RenderSVGResourceMasker::removeAllClientsFromCache(bool markForInvalidation)
+{
+ m_maskContentBoundaries = FloatRect();
+ if (!m_masker.isEmpty()) {
+ deleteAllValues(m_masker);
+ m_masker.clear();
+ }
+
+ markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
+}
+
+void RenderSVGResourceMasker::removeClientFromCache(RenderObject* client, bool markForInvalidation)
+{
+ ASSERT(client);
+
+ if (m_masker.contains(client))
+ delete m_masker.take(client);
+
+ markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
+}
+
+bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode)
+{
+ ASSERT(object);
+ ASSERT(context);
+#ifndef NDEBUG
+ ASSERT(resourceMode == ApplyToDefaultMode);
+#else
+ UNUSED_PARAM(resourceMode);
+#endif
+
+ if (!m_masker.contains(object))
+ m_masker.set(object, new MaskerData);
+
+ MaskerData* maskerData = m_masker.get(object);
+
+ AffineTransform absoluteTransform;
+ SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform);
+
+ FloatRect absoluteTargetRect = absoluteTransform.mapRect(object->repaintRectInLocalCoordinates());
+ FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(object, absoluteTargetRect);
+
+ if (!maskerData->maskImage && !clampedAbsoluteTargetRect.isEmpty()) {
+ SVGMaskElement* maskElement = static_cast<SVGMaskElement*>(node());
+ if (!maskElement)
+ return false;
+
+ if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, maskerData->maskImage, ColorSpaceLinearRGB))
+ return false;
+
+ GraphicsContext* maskImageContext = maskerData->maskImage->context();
+ ASSERT(maskImageContext);
+
+ // The save/restore pair is needed for clipToImageBuffer - it doesn't work without it on non-Cg platforms.
+ maskImageContext->save();
+ maskImageContext->translate(-clampedAbsoluteTargetRect.x(), -clampedAbsoluteTargetRect.y());
+ maskImageContext->concatCTM(absoluteTransform);
+
+ drawContentIntoMaskImage(maskerData, maskElement, object);
+ }
+
+ if (!maskerData->maskImage)
+ return false;
+
+ SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, clampedAbsoluteTargetRect, maskerData->maskImage);
+ return true;
+}
+
+void RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, const SVGMaskElement* maskElement, RenderObject* object)
+{
+ GraphicsContext* maskImageContext = maskerData->maskImage->context();
+ ASSERT(maskImageContext);
+
+ // Eventually adjust the mask image context according to the target objectBoundingBox.
+ AffineTransform maskContentTransformation;
+ if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+ FloatRect objectBoundingBox = object->objectBoundingBox();
+ maskContentTransformation.translate(objectBoundingBox.x(), objectBoundingBox.y());
+ maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
+ maskImageContext->concatCTM(maskContentTransformation);
+ }
+
+ // Draw the content into the ImageBuffer.
+ for (Node* node = maskElement->firstChild(); node; node = node->nextSibling()) {
+ RenderObject* renderer = node->renderer();
+ if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !renderer)
+ continue;
+ RenderStyle* style = renderer->style();
+ if (!style || style->display() == NONE || style->visibility() != VISIBLE)
+ continue;
+ SVGImageBufferTools::renderSubtreeToImageBuffer(maskerData->maskImage.get(), renderer, maskContentTransformation);
+ }
+
+ maskImageContext->restore();
+
+#if !PLATFORM(CG)
+ maskerData->maskImage->transformColorSpace(ColorSpaceDeviceRGB, ColorSpaceLinearRGB);
+#endif
+
+ // Create the luminance mask.
+ IntRect maskImageRect(IntPoint(), maskerData->maskImage->size());
+ RefPtr<ByteArray> srcPixelArray = maskerData->maskImage->getUnmultipliedImageData(maskImageRect);
+
+ unsigned pixelArrayLength = srcPixelArray->length();
+ for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) {
+ unsigned char a = srcPixelArray->get(pixelOffset + 3);
+ if (!a)
+ continue;
+ unsigned char r = srcPixelArray->get(pixelOffset);
+ unsigned char g = srcPixelArray->get(pixelOffset + 1);
+ unsigned char b = srcPixelArray->get(pixelOffset + 2);
+
+ double luma = (r * 0.2125 + g * 0.7154 + b * 0.0721) * ((double)a / 255.0);
+ srcPixelArray->set(pixelOffset + 3, luma);
+ }
+
+ maskerData->maskImage->putUnmultipliedImageData(srcPixelArray.get(), maskImageRect.size(), maskImageRect, IntPoint());
+}
+
+void RenderSVGResourceMasker::calculateMaskContentRepaintRect()
+{
+ for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
+ RenderObject* renderer = childNode->renderer();
+ if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer)
+ continue;
+ RenderStyle* style = renderer->style();
+ if (!style || style->display() == NONE || style->visibility() != VISIBLE)
+ continue;
+ m_maskContentBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates()));
+ }
+}
+
+FloatRect RenderSVGResourceMasker::resourceBoundingBox(RenderObject* object)
+{
+ SVGMaskElement* maskElement = static_cast<SVGMaskElement*>(node());
+ ASSERT(maskElement);
+
+ FloatRect objectBoundingBox = object->objectBoundingBox();
+ FloatRect maskBoundaries = maskElement->maskBoundingBox(objectBoundingBox);
+
+ // Resource was not layouted yet. Give back clipping rect of the mask.
+ if (selfNeedsLayout())
+ return maskBoundaries;
+
+ if (m_maskContentBoundaries.isEmpty())
+ calculateMaskContentRepaintRect();
+
+ FloatRect maskRect = m_maskContentBoundaries;
+ if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
+ AffineTransform transform;
+ transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
+ transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
+ maskRect = transform.mapRect(maskRect);
+ }
+
+ maskRect.intersect(maskBoundaries);
+ return maskRect;
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.h b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.h
new file mode 100644
index 0000000..0a7deb1
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009-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.
+ */
+
+#ifndef RenderSVGResourceMasker_h
+#define RenderSVGResourceMasker_h
+
+#if ENABLE(SVG)
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "IntSize.h"
+#include "RenderSVGResourceContainer.h"
+#include "SVGMaskElement.h"
+#include "SVGUnitTypes.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+struct MaskerData {
+ OwnPtr<ImageBuffer> maskImage;
+};
+
+class RenderSVGResourceMasker : public RenderSVGResourceContainer {
+public:
+ RenderSVGResourceMasker(SVGMaskElement*);
+ virtual ~RenderSVGResourceMasker();
+
+ virtual const char* renderName() const { return "RenderSVGResourceMasker"; }
+
+ virtual void removeAllClientsFromCache(bool markForInvalidation = true);
+ virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true);
+ virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode);
+ virtual FloatRect resourceBoundingBox(RenderObject*);
+
+ SVGUnitTypes::SVGUnitType maskUnits() const { return toUnitType(static_cast<SVGMaskElement*>(node())->maskUnits()); }
+ SVGUnitTypes::SVGUnitType maskContentUnits() const { return toUnitType(static_cast<SVGMaskElement*>(node())->maskContentUnits()); }
+
+ virtual RenderSVGResourceType resourceType() const { return s_resourceType; }
+ static RenderSVGResourceType s_resourceType;
+
+private:
+ void drawContentIntoMaskImage(MaskerData*, const SVGMaskElement*, RenderObject*);
+ void calculateMaskContentRepaintRect();
+
+ FloatRect m_maskContentBoundaries;
+ HashMap<RenderObject*, MaskerData*> m_masker;
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp
new file mode 100644
index 0000000..330a21a
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.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 "RenderSVGResourcePattern.h"
+
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "PatternAttributes.h"
+#include "RenderSVGRoot.h"
+#include "SVGImageBufferTools.h"
+#include "SVGRenderSupport.h"
+
+namespace WebCore {
+
+RenderSVGResourceType RenderSVGResourcePattern::s_resourceType = PatternResourceType;
+
+RenderSVGResourcePattern::RenderSVGResourcePattern(SVGPatternElement* node)
+ : RenderSVGResourceContainer(node)
+ , m_shouldCollectPatternAttributes(true)
+{
+}
+
+RenderSVGResourcePattern::~RenderSVGResourcePattern()
+{
+ if (m_pattern.isEmpty())
+ return;
+
+ deleteAllValues(m_pattern);
+ m_pattern.clear();
+}
+
+void RenderSVGResourcePattern::removeAllClientsFromCache(bool markForInvalidation)
+{
+ if (!m_pattern.isEmpty()) {
+ deleteAllValues(m_pattern);
+ m_pattern.clear();
+ }
+
+ m_shouldCollectPatternAttributes = true;
+ markAllClientsForInvalidation(markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation);
+}
+
+void RenderSVGResourcePattern::removeClientFromCache(RenderObject* client, bool markForInvalidation)
+{
+ ASSERT(client);
+
+ if (m_pattern.contains(client))
+ delete m_pattern.take(client);
+
+ markClientForInvalidation(client, markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation);
+}
+
+bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode)
+{
+ ASSERT(object);
+ ASSERT(style);
+ ASSERT(context);
+ ASSERT(resourceMode != ApplyToDefaultMode);
+
+ // Be sure to synchronize all SVG properties on the patternElement _before_ processing any further.
+ // Otherwhise the call to collectPatternAttributes() below, may cause the SVG DOM property
+ // synchronization to kick in, which causes removeAllClientsFromCache() to be called, which in turn deletes our
+ // PatternData object! Leaving out the line below will cause svg/dynamic-updates/SVGPatternElement-svgdom* to crash.
+ SVGPatternElement* patternElement = static_cast<SVGPatternElement*>(node());
+ if (!patternElement)
+ return false;
+
+ if (m_shouldCollectPatternAttributes) {
+ patternElement->updateAnimatedSVGAttribute(anyQName());
+
+ m_attributes = PatternAttributes();
+ patternElement->collectPatternAttributes(m_attributes);
+ m_shouldCollectPatternAttributes = false;
+ }
+
+ // Spec: When the geometry of the applicable element has no width or height and objectBoundingBox is specified,
+ // then the given effect (e.g. a gradient or a filter) will be ignored.
+ FloatRect objectBoundingBox = object->objectBoundingBox();
+ if (m_attributes.boundingBoxMode() && objectBoundingBox.isEmpty())
+ return false;
+
+ if (!m_pattern.contains(object))
+ m_pattern.set(object, new PatternData);
+
+ PatternData* patternData = m_pattern.get(object);
+ if (!patternData->pattern) {
+ // If we couldn't determine the pattern content element root, stop here.
+ if (!m_attributes.patternContentElement())
+ return false;
+
+ // Compute all necessary transformations to build the tile image & the pattern.
+ FloatRect tileBoundaries;
+ AffineTransform tileImageTransform;
+ if (!buildTileImageTransform(object, m_attributes, patternElement, tileBoundaries, tileImageTransform))
+ return false;
+
+ AffineTransform absoluteTransform;
+ SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform);
+
+ FloatRect absoluteTileBoundaries = absoluteTransform.mapRect(tileBoundaries);
+
+ // Build tile image.
+ OwnPtr<ImageBuffer> tileImage = createTileImage(object, m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform);
+ if (!tileImage)
+ return false;
+
+ RefPtr<Image> copiedImage = tileImage->copyImage();
+ if (!copiedImage)
+ return false;
+
+ // Build pattern.
+ patternData->pattern = Pattern::create(copiedImage, true, true);
+ if (!patternData->pattern)
+ return false;
+
+ // Compute pattern space transformation.
+ patternData->transform.translate(tileBoundaries.x(), tileBoundaries.y());
+ patternData->transform.scale(tileBoundaries.width() / absoluteTileBoundaries.width(), tileBoundaries.height() / absoluteTileBoundaries.height());
+
+ AffineTransform patternTransform = m_attributes.patternTransform();
+ if (!patternTransform.isIdentity())
+ patternData->transform.multiply(patternTransform);
+
+ patternData->pattern->setPatternSpaceTransform(patternData->transform);
+ }
+
+ // Draw pattern
+ context->save();
+
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+ ASSERT(svgStyle);
+
+ if (resourceMode & ApplyToFillMode) {
+ context->setAlpha(svgStyle->fillOpacity());
+ context->setFillPattern(patternData->pattern);
+ context->setFillRule(svgStyle->fillRule());
+ } else if (resourceMode & ApplyToStrokeMode) {
+ if (svgStyle->vectorEffect() == VE_NON_SCALING_STROKE)
+ patternData->pattern->setPatternSpaceTransform(transformOnNonScalingStroke(object, patternData->transform));
+ context->setAlpha(svgStyle->strokeOpacity());
+ context->setStrokePattern(patternData->pattern);
+ SVGRenderSupport::applyStrokeStyleToContext(context, style, object);
+ }
+
+ if (resourceMode & ApplyToTextMode) {
+ if (resourceMode & ApplyToFillMode) {
+ context->setTextDrawingMode(TextModeFill);
+
+#if PLATFORM(CG)
+ context->applyFillPattern();
+#endif
+ } else if (resourceMode & ApplyToStrokeMode) {
+ context->setTextDrawingMode(TextModeStroke);
+
+#if PLATFORM(CG)
+ context->applyStrokePattern();
+#endif
+ }
+ }
+
+ return true;
+}
+
+void RenderSVGResourcePattern::postApplyResource(RenderObject*, GraphicsContext*& context, unsigned short resourceMode, const Path* path)
+{
+ ASSERT(context);
+ ASSERT(resourceMode != ApplyToDefaultMode);
+
+ if (path && !(resourceMode & ApplyToTextMode)) {
+ if (resourceMode & ApplyToFillMode)
+ context->fillPath(*path);
+ else if (resourceMode & ApplyToStrokeMode)
+ context->strokePath(*path);
+ }
+
+ context->restore();
+}
+
+static inline FloatRect calculatePatternBoundaries(const PatternAttributes& attributes,
+ const FloatRect& objectBoundingBox,
+ const SVGPatternElement* patternElement)
+{
+ ASSERT(patternElement);
+
+ if (attributes.boundingBoxMode())
+ return FloatRect(attributes.x().valueAsPercentage() * objectBoundingBox.width() + objectBoundingBox.x(),
+ attributes.y().valueAsPercentage() * objectBoundingBox.height() + objectBoundingBox.y(),
+ attributes.width().valueAsPercentage() * objectBoundingBox.width(),
+ attributes.height().valueAsPercentage() * objectBoundingBox.height());
+
+ return FloatRect(attributes.x().value(patternElement),
+ attributes.y().value(patternElement),
+ attributes.width().value(patternElement),
+ attributes.height().value(patternElement));
+}
+
+bool RenderSVGResourcePattern::buildTileImageTransform(RenderObject* renderer,
+ const PatternAttributes& attributes,
+ const SVGPatternElement* patternElement,
+ FloatRect& patternBoundaries,
+ AffineTransform& tileImageTransform) const
+{
+ ASSERT(renderer);
+ ASSERT(patternElement);
+
+ FloatRect objectBoundingBox = renderer->objectBoundingBox();
+ patternBoundaries = calculatePatternBoundaries(attributes, objectBoundingBox, patternElement);
+ if (patternBoundaries.width() <= 0 || patternBoundaries.height() <= 0)
+ return false;
+
+ AffineTransform viewBoxCTM = patternElement->viewBoxToViewTransform(patternElement->viewBox(), patternElement->preserveAspectRatio(), patternBoundaries.width(), patternBoundaries.height());
+
+ // Apply viewBox/objectBoundingBox transformations.
+ if (!viewBoxCTM.isIdentity())
+ tileImageTransform = viewBoxCTM;
+ else if (attributes.boundingBoxModeContent()) {
+ tileImageTransform.translate(objectBoundingBox.x(), objectBoundingBox.y());
+ tileImageTransform.scale(objectBoundingBox.width(), objectBoundingBox.height());
+ }
+
+ return true;
+}
+
+PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(RenderObject* object,
+ const PatternAttributes& attributes,
+ const FloatRect& tileBoundaries,
+ const FloatRect& absoluteTileBoundaries,
+ const AffineTransform& tileImageTransform) const
+{
+ ASSERT(object);
+
+ // Clamp tile image size against SVG viewport size, as last resort, to avoid allocating huge image buffers.
+ FloatRect contentBoxRect = SVGRenderSupport::findTreeRootObject(object)->contentBoxRect();
+
+ FloatRect clampedAbsoluteTileBoundaries = absoluteTileBoundaries;
+ if (clampedAbsoluteTileBoundaries.width() > contentBoxRect.width())
+ clampedAbsoluteTileBoundaries.setWidth(contentBoxRect.width());
+
+ if (clampedAbsoluteTileBoundaries.height() > contentBoxRect.height())
+ clampedAbsoluteTileBoundaries.setHeight(contentBoxRect.height());
+
+ OwnPtr<ImageBuffer> tileImage;
+
+ if (!SVGImageBufferTools::createImageBuffer(absoluteTileBoundaries, clampedAbsoluteTileBoundaries, tileImage, ColorSpaceDeviceRGB))
+ return PassOwnPtr<ImageBuffer>();
+
+ GraphicsContext* tileImageContext = tileImage->context();
+ ASSERT(tileImageContext);
+
+ // The image buffer represents the final rendered size, so the content has to be scaled (to avoid pixelation).
+ tileImageContext->scale(FloatSize(absoluteTileBoundaries.width() / tileBoundaries.width(),
+ absoluteTileBoundaries.height() / tileBoundaries.height()));
+
+ // Apply tile image transformations.
+ if (!tileImageTransform.isIdentity())
+ tileImageContext->concatCTM(tileImageTransform);
+
+ AffineTransform contentTransformation;
+
+ // Draw the content into the ImageBuffer.
+ for (Node* node = attributes.patternContentElement()->firstChild(); node; node = node->nextSibling()) {
+ if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !node->renderer())
+ continue;
+ SVGImageBufferTools::renderSubtreeToImageBuffer(tileImage.get(), node->renderer(), contentTransformation);
+ }
+
+ return tileImage.release();
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.h b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.h
new file mode 100644
index 0000000..a697c71
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.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.
+ */
+
+#ifndef RenderSVGResourcePattern_h
+#define RenderSVGResourcePattern_h
+
+#if ENABLE(SVG)
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "ImageBuffer.h"
+#include "Pattern.h"
+#include "PatternAttributes.h"
+#include "RenderSVGResourceContainer.h"
+#include "SVGPatternElement.h"
+#include "SVGUnitTypes.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+struct PatternData {
+ RefPtr<Pattern> pattern;
+ AffineTransform transform;
+};
+
+class RenderSVGResourcePattern : public RenderSVGResourceContainer {
+public:
+ RenderSVGResourcePattern(SVGPatternElement*);
+ virtual ~RenderSVGResourcePattern();
+
+ virtual const char* renderName() const { return "RenderSVGResourcePattern"; }
+
+ virtual void removeAllClientsFromCache(bool markForInvalidation = true);
+ virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true);
+
+ virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode);
+ virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*);
+ virtual FloatRect resourceBoundingBox(RenderObject*) { return FloatRect(); }
+
+ virtual RenderSVGResourceType resourceType() const { return s_resourceType; }
+ static RenderSVGResourceType s_resourceType;
+
+private:
+ bool buildTileImageTransform(RenderObject*, const PatternAttributes&, const SVGPatternElement*, FloatRect& patternBoundaries, AffineTransform& tileImageTransform) const;
+
+ PassOwnPtr<ImageBuffer> createTileImage(RenderObject*, const PatternAttributes&, const FloatRect& tileBoundaries,
+ const FloatRect& absoluteTileBoundaries, const AffineTransform& tileImageTransform) const;
+
+ bool m_shouldCollectPatternAttributes : 1;
+ PatternAttributes m_attributes;
+ HashMap<RenderObject*, PatternData*> m_pattern;
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp
new file mode 100644
index 0000000..a8830fc
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.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 "RenderSVGResourceRadialGradient.h"
+
+#include "RadialGradientAttributes.h"
+#include "SVGRadialGradientElement.h"
+
+namespace WebCore {
+
+RenderSVGResourceType RenderSVGResourceRadialGradient::s_resourceType = RadialGradientResourceType;
+
+RenderSVGResourceRadialGradient::RenderSVGResourceRadialGradient(SVGRadialGradientElement* node)
+ : RenderSVGResourceGradient(node)
+{
+}
+
+RenderSVGResourceRadialGradient::~RenderSVGResourceRadialGradient()
+{
+}
+
+void RenderSVGResourceRadialGradient::collectGradientAttributes(SVGGradientElement* gradientElement)
+{
+ m_attributes = RadialGradientAttributes();
+ static_cast<SVGRadialGradientElement*>(gradientElement)->collectGradientAttributes(m_attributes);
+}
+
+void RenderSVGResourceRadialGradient::buildGradient(GradientData* gradientData, SVGGradientElement* gradientElement) const
+{
+ SVGRadialGradientElement* radialGradientElement = static_cast<SVGRadialGradientElement*>(gradientElement);
+
+ // Determine gradient focal/center points and radius
+ FloatPoint focalPoint;
+ FloatPoint centerPoint;
+ float radius;
+ radialGradientElement->calculateFocalCenterPointsAndRadius(m_attributes, focalPoint, centerPoint, radius);
+
+ gradientData->gradient = Gradient::create(focalPoint,
+ 0, // SVG does not support a "focus radius"
+ centerPoint,
+ radius);
+
+ gradientData->gradient->setSpreadMethod(m_attributes.spreadMethod());
+
+ // Add stops
+ addStops(gradientData, m_attributes.stops());
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.h b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.h
new file mode 100644
index 0000000..9d37d11
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.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.
+ */
+
+#ifndef RenderSVGResourceRadialGradient_h
+#define RenderSVGResourceRadialGradient_h
+
+#if ENABLE(SVG)
+#include "RadialGradientAttributes.h"
+#include "RenderSVGResourceGradient.h"
+
+namespace WebCore {
+
+class SVGRadialGradientElement;
+
+class RenderSVGResourceRadialGradient : public RenderSVGResourceGradient {
+public:
+ RenderSVGResourceRadialGradient(SVGRadialGradientElement*);
+ virtual ~RenderSVGResourceRadialGradient();
+
+ virtual const char* renderName() const { return "RenderSVGResourceRadialGradient"; }
+
+ virtual RenderSVGResourceType resourceType() const { return s_resourceType; }
+ static RenderSVGResourceType s_resourceType;
+
+ virtual bool boundingBoxMode() const { return m_attributes.boundingBoxMode(); }
+ virtual void calculateGradientTransform(AffineTransform& transform) { transform = m_attributes.gradientTransform(); }
+ virtual void collectGradientAttributes(SVGGradientElement*);
+ virtual void buildGradient(GradientData*, SVGGradientElement*) const;
+
+private:
+ RadialGradientAttributes m_attributes;
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp
new file mode 100644
index 0000000..9f6c063
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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 "RenderSVGResourceSolidColor.h"
+
+#include "GraphicsContext.h"
+#include "RenderStyle.h"
+#include "SVGRenderSupport.h"
+
+#if PLATFORM(SKIA)
+#include "PlatformContextSkia.h"
+#endif
+
+namespace WebCore {
+
+RenderSVGResourceType RenderSVGResourceSolidColor::s_resourceType = SolidColorResourceType;
+
+RenderSVGResourceSolidColor::RenderSVGResourceSolidColor()
+{
+}
+
+RenderSVGResourceSolidColor::~RenderSVGResourceSolidColor()
+{
+}
+
+bool RenderSVGResourceSolidColor::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode)
+{
+ // We are NOT allowed to ASSERT(object) here, unlike all other resources.
+ // RenderSVGResourceSolidColor is the only resource which may be used from HTML, when rendering
+ // SVG Fonts for a HTML document. This will be indicated by a null RenderObject pointer.
+ ASSERT(context);
+ ASSERT(resourceMode != ApplyToDefaultMode);
+
+ const SVGRenderStyle* svgStyle = style ? style->svgStyle() : 0;
+ ColorSpace colorSpace = style ? style->colorSpace() : ColorSpaceDeviceRGB;
+
+ if (resourceMode & ApplyToFillMode) {
+ context->setAlpha(svgStyle ? svgStyle->fillOpacity() : 1.0f);
+ context->setFillColor(m_color, colorSpace);
+ context->setFillRule(svgStyle ? svgStyle->fillRule() : RULE_NONZERO);
+
+ if (resourceMode & ApplyToTextMode)
+ context->setTextDrawingMode(TextModeFill);
+ } else if (resourceMode & ApplyToStrokeMode) {
+ context->setAlpha(svgStyle ? svgStyle->strokeOpacity() : 1.0f);
+ context->setStrokeColor(m_color, colorSpace);
+
+ if (style)
+ SVGRenderSupport::applyStrokeStyleToContext(context, style, object);
+
+ if (resourceMode & ApplyToTextMode)
+ context->setTextDrawingMode(TextModeStroke);
+ }
+
+ return true;
+}
+
+void RenderSVGResourceSolidColor::postApplyResource(RenderObject*, GraphicsContext*& context, unsigned short resourceMode, const Path* path)
+{
+ ASSERT(context);
+ ASSERT(resourceMode != ApplyToDefaultMode);
+
+ if (path && !(resourceMode & ApplyToTextMode)) {
+ if (resourceMode & ApplyToFillMode)
+ context->fillPath(*path);
+ else if (resourceMode & ApplyToStrokeMode)
+ context->strokePath(*path);
+ }
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.h b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.h
new file mode 100644
index 0000000..02ceb31
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef RenderSVGResourceSolidColor_h
+#define RenderSVGResourceSolidColor_h
+
+#if ENABLE(SVG)
+#include "Color.h"
+#include "FloatRect.h"
+#include "RenderSVGResource.h"
+
+namespace WebCore {
+
+class RenderSVGResourceSolidColor : public RenderSVGResource {
+public:
+ RenderSVGResourceSolidColor();
+ virtual ~RenderSVGResourceSolidColor();
+
+ virtual void removeAllClientsFromCache(bool = true) { }
+ virtual void removeClientFromCache(RenderObject*, bool = true) { }
+
+ virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode);
+ virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*);
+ virtual FloatRect resourceBoundingBox(RenderObject*) { return FloatRect(); }
+
+ virtual RenderSVGResourceType resourceType() const { return s_resourceType; }
+ static RenderSVGResourceType s_resourceType;
+
+ const Color& color() const { return m_color; }
+ void setColor(const Color& color) { m_color = color; }
+
+private:
+ Color m_color;
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp
new file mode 100644
index 0000000..aa87b09
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005, 2007, 2008, 2009 Rob Buis <buis@kde.org>
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * 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 "RenderSVGRoot.h"
+
+#include "GraphicsContext.h"
+#include "HitTestResult.h"
+#include "RenderSVGContainer.h"
+#include "RenderSVGResource.h"
+#include "RenderView.h"
+#include "SVGLength.h"
+#include "SVGRenderSupport.h"
+#include "SVGResources.h"
+#include "SVGSVGElement.h"
+#include "SVGStyledElement.h"
+#include "TransformState.h"
+
+#if ENABLE(FILTERS)
+#include "RenderSVGResourceFilter.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+RenderSVGRoot::RenderSVGRoot(SVGStyledElement* node)
+ : RenderBox(node)
+ , m_isLayoutSizeChanged(false)
+ , m_needsBoundariesOrTransformUpdate(true)
+{
+ setReplaced(true);
+}
+
+RenderSVGRoot::~RenderSVGRoot()
+{
+}
+
+void RenderSVGRoot::computePreferredLogicalWidths()
+{
+ ASSERT(preferredLogicalWidthsDirty());
+
+ int borderAndPadding = borderAndPaddingWidth();
+ int width = computeReplacedLogicalWidth(false) + borderAndPadding;
+
+ if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength)
+ width = min(width, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? borderAndPadding : 0));
+
+ if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent())) {
+ m_minPreferredLogicalWidth = 0;
+ m_maxPreferredLogicalWidth = width;
+ } else
+ m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = width;
+
+ setPreferredLogicalWidthsDirty(false);
+}
+
+int RenderSVGRoot::computeReplacedLogicalWidth(bool includeMaxWidth) const
+{
+ int replacedWidth = RenderBox::computeReplacedLogicalWidth(includeMaxWidth);
+ if (!style()->logicalWidth().isPercent())
+ return replacedWidth;
+
+ // FIXME: Investigate in size rounding issues
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
+ return static_cast<int>(roundf(replacedWidth * svg->currentScale()));
+}
+
+int RenderSVGRoot::computeReplacedLogicalHeight() const
+{
+ int replacedHeight = RenderBox::computeReplacedLogicalHeight();
+ if (!style()->logicalHeight().isPercent())
+ return replacedHeight;
+
+ // FIXME: Investigate in size rounding issues
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
+ return static_cast<int>(roundf(replacedHeight * svg->currentScale()));
+}
+
+void RenderSVGRoot::layout()
+{
+ ASSERT(needsLayout());
+
+ // Arbitrary affine transforms are incompatible with LayoutState.
+ view()->disableLayoutState();
+
+ bool needsLayout = selfNeedsLayout();
+ LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && needsLayout);
+
+ IntSize oldSize(width(), height());
+ computeLogicalWidth();
+ computeLogicalHeight();
+ calcViewport();
+
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
+ m_isLayoutSizeChanged = svg->hasRelativeLengths() && oldSize != size();
+
+ SVGRenderSupport::layoutChildren(this, needsLayout);
+ m_isLayoutSizeChanged = false;
+
+ // At this point LayoutRepainter already grabbed the old bounds,
+ // recalculate them now so repaintAfterLayout() uses the new bounds.
+ if (m_needsBoundariesOrTransformUpdate) {
+ updateCachedBoundaries();
+ m_needsBoundariesOrTransformUpdate = false;
+ }
+
+ repainter.repaintAfterLayout();
+
+ view()->enableLayoutState();
+ setNeedsLayout(false);
+}
+
+bool RenderSVGRoot::selfWillPaint()
+{
+#if ENABLE(FILTERS)
+ SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this);
+ return resources && resources->filter();
+#else
+ return false;
+#endif
+}
+
+void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY)
+{
+ if (paintInfo.context->paintingDisabled())
+ return;
+
+ bool isVisible = style()->visibility() == VISIBLE;
+ IntPoint parentOriginInContainer(parentX, parentY);
+ IntPoint borderBoxOriginInContainer = parentOriginInContainer + parentOriginToBorderBox();
+
+ if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackground) && isVisible)
+ paintBoxDecorations(paintInfo, borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y());
+
+ if (paintInfo.phase == PaintPhaseBlockBackground)
+ return;
+
+ // An empty viewport disables rendering. FIXME: Should we still render filters?
+ if (m_viewportSize.isEmpty())
+ return;
+
+ // Don't paint if we don't have kids, except if we have filters we should paint those.
+ if (!firstChild() && !selfWillPaint())
+ return;
+
+ // Make a copy of the PaintInfo because applyTransform will modify the damage rect.
+ PaintInfo childPaintInfo(paintInfo);
+ childPaintInfo.context->save();
+
+ // Apply initial viewport clip - not affected by overflow handling
+ childPaintInfo.context->clip(overflowClipRect(borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y()));
+
+ // Convert from container offsets (html renderers) to a relative transform (svg renderers).
+ // Transform from our paint container's coordinate system to our local coords.
+ childPaintInfo.applyTransform(localToRepaintContainerTransform(parentOriginInContainer));
+
+ bool continueRendering = true;
+ if (childPaintInfo.phase == PaintPhaseForeground)
+ continueRendering = SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo);
+
+ if (continueRendering)
+ RenderBox::paint(childPaintInfo, 0, 0);
+
+ if (childPaintInfo.phase == PaintPhaseForeground)
+ SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, paintInfo.context);
+
+ childPaintInfo.context->restore();
+
+ if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && isVisible)
+ paintOutline(paintInfo.context, borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y(), width(), height());
+}
+
+void RenderSVGRoot::destroy()
+{
+ SVGResourcesCache::clientDestroyed(this);
+ RenderBox::destroy();
+}
+
+void RenderSVGRoot::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
+{
+ if (diff == StyleDifferenceLayout)
+ setNeedsBoundariesUpdate();
+ RenderBox::styleWillChange(diff, newStyle);
+}
+
+void RenderSVGRoot::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+ RenderBox::styleDidChange(diff, oldStyle);
+ SVGResourcesCache::clientStyleChanged(this, diff, style());
+}
+
+void RenderSVGRoot::updateFromElement()
+{
+ RenderBox::updateFromElement();
+ SVGResourcesCache::clientUpdatedFromElement(this, style());
+}
+
+void RenderSVGRoot::calcViewport()
+{
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
+
+ if (!svg->hasSetContainerSize()) {
+ // In the normal case of <svg> being stand-alone or in a CSSBoxModel object we use
+ // RenderBox::width()/height() (which pulls data from RenderStyle)
+ m_viewportSize = FloatSize(width(), height());
+ return;
+ }
+
+ // In the SVGImage case grab the SVGLength values off of SVGSVGElement and use
+ // the special relativeWidthValue accessors which respect the specified containerSize
+ // FIXME: Check how SVGImage + zooming is supposed to be handled?
+ SVGLength width = svg->width();
+ SVGLength height = svg->height();
+ m_viewportSize = FloatSize(width.unitType() == LengthTypePercentage ? svg->relativeWidthValue() : width.value(svg),
+ height.unitType() == LengthTypePercentage ? svg->relativeHeightValue() : height.value(svg));
+}
+
+// RenderBox methods will expect coordinates w/o any transforms in coordinates
+// relative to our borderBox origin. This method gives us exactly that.
+AffineTransform RenderSVGRoot::localToBorderBoxTransform() const
+{
+ IntSize borderAndPadding = borderOriginToContentBox();
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
+ float scale = svg->currentScale();
+ FloatPoint translate = svg->currentTranslate();
+ AffineTransform ctm(scale, 0, 0, scale, borderAndPadding.width() + translate.x(), borderAndPadding.height() + translate.y());
+ return svg->viewBoxToViewTransform(width() / scale, height() / scale) * ctm;
+}
+
+IntSize RenderSVGRoot::parentOriginToBorderBox() const
+{
+ return IntSize(x(), y());
+}
+
+IntSize RenderSVGRoot::borderOriginToContentBox() const
+{
+ return IntSize(borderLeft() + paddingLeft(), borderTop() + paddingTop());
+}
+
+AffineTransform RenderSVGRoot::localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const
+{
+ AffineTransform parentToContainer(localToParentTransform());
+ return parentToContainer.translateRight(parentOriginInContainer.x(), parentOriginInContainer.y());
+}
+
+const AffineTransform& RenderSVGRoot::localToParentTransform() const
+{
+ IntSize parentToBorderBoxOffset = parentOriginToBorderBox();
+
+ AffineTransform borderBoxOriginToParentOrigin(localToBorderBoxTransform());
+ borderBoxOriginToParentOrigin.translateRight(parentToBorderBoxOffset.width(), parentToBorderBoxOffset.height());
+
+ m_localToParentTransform = borderBoxOriginToParentOrigin;
+ return m_localToParentTransform;
+}
+
+IntRect RenderSVGRoot::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
+{
+ return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer);
+}
+
+void RenderSVGRoot::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
+{
+ // Apply our local transforms (except for x/y translation), then our shadow,
+ // and then call RenderBox's method to handle all the normal CSS Box model bits
+ repaintRect = localToBorderBoxTransform().mapRect(repaintRect);
+
+ // Apply initial viewport clip - not affected by overflow settings
+ repaintRect.intersect(enclosingIntRect(FloatRect(FloatPoint(), m_viewportSize)));
+
+ const SVGRenderStyle* svgStyle = style()->svgStyle();
+ if (const ShadowData* shadow = svgStyle->shadow())
+ shadow->adjustRectForShadow(repaintRect);
+
+ RenderBox::computeRectForRepaint(repaintContainer, repaintRect, fixed);
+}
+
+void RenderSVGRoot::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const
+{
+ 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.
+
+ // Transform to our border box and let RenderBox transform the rest of the way.
+ transformState.applyTransform(localToBorderBoxTransform());
+ RenderBox::mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
+}
+
+void RenderSVGRoot::updateCachedBoundaries()
+{
+ m_objectBoundingBox = FloatRect();
+ m_strokeBoundingBox = FloatRect();
+ m_repaintBoundingBox = FloatRect();
+
+ SVGRenderSupport::computeContainerBoundingBoxes(this, m_objectBoundingBox, m_strokeBoundingBox, m_repaintBoundingBox);
+ SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox);
+ m_repaintBoundingBox.inflate(borderAndPaddingWidth());
+}
+
+bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
+{
+ IntPoint pointInContainer(x, y);
+ IntSize containerToParentOffset(tx, ty);
+
+ IntPoint pointInParent = pointInContainer - containerToParentOffset;
+ IntPoint pointInBorderBox = pointInParent - parentOriginToBorderBox();
+
+ // Note: For now, we're ignoring hits to border and padding for <svg>
+ IntPoint pointInContentBox = pointInBorderBox - borderOriginToContentBox();
+ if (!contentBoxRect().contains(pointInContentBox))
+ return false;
+
+ IntPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent);
+
+ for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
+ if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) {
+ // FIXME: CSS/HTML assumes the local point is relative to the border box, right?
+ updateHitTestResult(result, pointInBorderBox);
+ // FIXME: nodeAtFloatPoint() doesn't handle rect-based hit tests yet.
+ result.addNodeToRectBasedTestResult(child->node(), x, y);
+ return true;
+ }
+ }
+
+ // If we didn't early exit above, we've just hit the container <svg> element. Unlike SVG 1.1, 2nd Edition allows container elements to be hit.
+ if (hitTestAction == HitTestBlockBackground) {
+ // Only return true here, if the last hit testing phase 'BlockBackground' is executed. If we'd return true in the 'Foreground' phase,
+ // hit testing would stop immediately. For SVG only trees this doesn't matter. Though when we have a <foreignObject> subtree we need
+ // to be able to detect hits on the background of a <div> element. If we'd return true here in the 'Foreground' phase, we are not able
+ // to detect these hits anymore.
+ updateHitTestResult(result, roundedIntPoint(localPoint));
+ return true;
+ }
+
+ return false;
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.h b/Source/WebCore/rendering/svg/RenderSVGRoot.h
new file mode 100644
index 0000000..7aec3f8
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGRoot.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005, 2007 Rob Buis <buis@kde.org>
+ * Copyright (C) 2009 Google, Inc. All rights reserved.
+ * Copyright (C) 2009 Apple Inc. 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.
+ */
+
+#ifndef RenderSVGRoot_h
+#define RenderSVGRoot_h
+
+#if ENABLE(SVG)
+#include "FloatRect.h"
+#include "RenderBox.h"
+
+#include "SVGRenderSupport.h"
+
+namespace WebCore {
+
+class SVGStyledElement;
+class AffineTransform;
+
+class RenderSVGRoot : public RenderBox {
+public:
+ explicit RenderSVGRoot(SVGStyledElement*);
+ virtual ~RenderSVGRoot();
+
+ const RenderObjectChildList* children() const { return &m_children; }
+ RenderObjectChildList* children() { return &m_children; }
+
+ bool isLayoutSizeChanged() const { return m_isLayoutSizeChanged; }
+ virtual void setNeedsBoundariesUpdate() { m_needsBoundariesOrTransformUpdate = true; }
+ virtual void setNeedsTransformUpdate() { m_needsBoundariesOrTransformUpdate = true; }
+
+private:
+ virtual RenderObjectChildList* virtualChildren() { return children(); }
+ virtual const RenderObjectChildList* virtualChildren() const { return children(); }
+
+ virtual bool isSVGRoot() const { return true; }
+ virtual const char* renderName() const { return "RenderSVGRoot"; }
+
+ virtual void computePreferredLogicalWidths();
+ virtual int computeReplacedLogicalWidth(bool includeMaxWidth = true) const;
+ virtual int computeReplacedLogicalHeight() const;
+ virtual void layout();
+ virtual void paint(PaintInfo&, int parentX, int parentY);
+
+ virtual void destroy();
+ virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
+ virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+ virtual void updateFromElement();
+
+ virtual const AffineTransform& localToParentTransform() const;
+
+ bool fillContains(const FloatPoint&) const;
+ bool strokeContains(const FloatPoint&) const;
+
+ virtual FloatRect objectBoundingBox() const { return m_objectBoundingBox; }
+ virtual FloatRect strokeBoundingBox() const { return m_strokeBoundingBox; }
+ virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; }
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
+ virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed);
+
+ virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const;
+
+ void calcViewport();
+
+ bool selfWillPaint();
+ void updateCachedBoundaries();
+
+ IntSize parentOriginToBorderBox() const;
+ IntSize borderOriginToContentBox() const;
+ AffineTransform localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const;
+ AffineTransform localToBorderBoxTransform() const;
+
+ RenderObjectChildList m_children;
+ FloatSize m_viewportSize;
+ FloatRect m_objectBoundingBox;
+ FloatRect m_strokeBoundingBox;
+ FloatRect m_repaintBoundingBox;
+ mutable AffineTransform m_localToParentTransform;
+ bool m_isLayoutSizeChanged : 1;
+ bool m_needsBoundariesOrTransformUpdate : 1;
+};
+
+inline RenderSVGRoot* toRenderSVGRoot(RenderObject* object)
+{
+ ASSERT(!object || object->isSVGRoot());
+ return static_cast<RenderSVGRoot*>(object);
+}
+
+inline const RenderSVGRoot* toRenderSVGRoot(const RenderObject* object)
+{
+ ASSERT(!object || object->isSVGRoot());
+ return static_cast<const RenderSVGRoot*>(object);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toRenderSVGRoot(const RenderSVGRoot*);
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGRoot_h
diff --git a/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp
new file mode 100644
index 0000000..5736333
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp
@@ -0,0 +1,108 @@
+/*
+ * 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 "RenderSVGShadowTreeRootContainer.h"
+
+#include "MouseEvent.h"
+#include "SVGShadowTreeElements.h"
+#include "SVGUseElement.h"
+
+namespace WebCore {
+
+RenderSVGShadowTreeRootContainer::RenderSVGShadowTreeRootContainer(SVGUseElement* node)
+ : RenderSVGTransformableContainer(node)
+ , m_recreateTree(false)
+{
+}
+
+RenderSVGShadowTreeRootContainer::~RenderSVGShadowTreeRootContainer()
+{
+ if (m_shadowRoot && m_shadowRoot->attached()) {
+ m_shadowRoot->detach();
+ m_shadowRoot->clearShadowHost();
+ }
+}
+
+void RenderSVGShadowTreeRootContainer::updateStyle(Node::StyleChange change)
+{
+ if (m_shadowRoot && m_shadowRoot->attached())
+ m_shadowRoot->recalcStyle(change);
+}
+
+void RenderSVGShadowTreeRootContainer::updateFromElement()
+{
+ bool hadExistingTree = m_shadowRoot;
+
+ SVGUseElement* useElement = static_cast<SVGUseElement*>(node());
+ if (!m_shadowRoot) {
+ ASSERT(!m_recreateTree);
+ m_shadowRoot = SVGShadowTreeRootElement::create(document(), useElement);
+ useElement->buildPendingResource();
+ }
+
+ ASSERT(m_shadowRoot->shadowHost() == useElement);
+
+ bool shouldRecreateTree = m_recreateTree;
+ if (m_recreateTree) {
+ ASSERT(hadExistingTree);
+
+ if (m_shadowRoot->attached())
+ m_shadowRoot->detach();
+
+ m_shadowRoot->removeAllChildren();
+ m_recreateTree = false;
+ }
+
+ // Only rebuild the shadow tree, if we a) never had a tree or b) we were specifically asked to do so
+ // If the use element is a pending resource, and a) or b) is true, do nothing, and wait for the use
+ // element to be asked to buildPendingResource(), this will call us again, with m_recreateTrue=true.
+ if ((shouldRecreateTree || !hadExistingTree) && !useElement->isPendingResource()) {
+ useElement->buildShadowAndInstanceTree(m_shadowRoot.get());
+
+ // Attach shadow root element
+ m_shadowRoot->attachElement(style(), renderArena());
+
+ // Attach subtree, as if it was a regular non-shadow tree
+ for (Node* child = m_shadowRoot->firstChild(); child; child = child->nextSibling())
+ child->attach();
+ }
+
+ ASSERT(!m_recreateTree);
+ RenderSVGTransformableContainer::updateFromElement();
+}
+
+void RenderSVGShadowTreeRootContainer::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+ RenderSVGTransformableContainer::styleDidChange(diff, oldStyle);
+
+ if (RenderObject* shadowRootRenderer = m_shadowRoot ? m_shadowRoot->renderer() : 0)
+ shadowRootRenderer->setStyle(style());
+}
+
+Node* RenderSVGShadowTreeRootContainer::rootElement() const
+{
+ return m_shadowRoot.get();
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.h b/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.h
new file mode 100644
index 0000000..cee8409
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#ifndef RenderSVGShadowTreeRootContainer_h
+#define RenderSVGShadowTreeRootContainer_h
+
+#if ENABLE(SVG)
+#include "RenderSVGTransformableContainer.h"
+
+namespace WebCore {
+
+class SVGUseElement;
+class SVGShadowTreeRootElement;
+
+class RenderSVGShadowTreeRootContainer : public RenderSVGTransformableContainer {
+public:
+ RenderSVGShadowTreeRootContainer(SVGUseElement*);
+ virtual ~RenderSVGShadowTreeRootContainer();
+
+ virtual bool isSVGShadowTreeRootContainer() const { return true; }
+
+ void markShadowTreeForRecreation() { m_recreateTree = true; }
+ void updateStyle(Node::StyleChange);
+ virtual void updateFromElement();
+
+ Node* rootElement() const;
+
+private:
+ virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+
+ bool m_recreateTree;
+ RefPtr<SVGShadowTreeRootElement> m_shadowRoot;
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGTSpan.cpp b/Source/WebCore/rendering/svg/RenderSVGTSpan.cpp
index 90ff36c..872d076 100644
--- a/Source/WebCore/rendering/svg/RenderSVGTSpan.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGTSpan.cpp
@@ -2,7 +2,7 @@
* This file is part of the WebKit project.
*
* Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
- * (C) 2006 Apple Computer Inc.
+ * Copyright (C) 2006 Apple Computer Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -18,7 +18,6 @@
* 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"
diff --git a/Source/WebCore/rendering/svg/RenderSVGTSpan.h b/Source/WebCore/rendering/svg/RenderSVGTSpan.h
index 97e0eb0..d5e2ed7 100644
--- a/Source/WebCore/rendering/svg/RenderSVGTSpan.h
+++ b/Source/WebCore/rendering/svg/RenderSVGTSpan.h
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
- * (C) 2006 Apple Computer Inc.
- * (C) 2009 Google Inc.
+ * Copyright (C) 2006 Apple Computer Inc.
+ * Copyright (C) 2009 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -17,7 +17,6 @@
* 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.
- *
*/
#ifndef RenderSVGTSpan_h
diff --git a/Source/WebCore/rendering/svg/RenderSVGText.cpp b/Source/WebCore/rendering/svg/RenderSVGText.cpp
index 01a92b0..dad0b70 100644
--- a/Source/WebCore/rendering/svg/RenderSVGText.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGText.cpp
@@ -21,7 +21,6 @@
* 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"
diff --git a/Source/WebCore/rendering/svg/RenderSVGText.h b/Source/WebCore/rendering/svg/RenderSVGText.h
index deae78c..188d5fc 100644
--- a/Source/WebCore/rendering/svg/RenderSVGText.h
+++ b/Source/WebCore/rendering/svg/RenderSVGText.h
@@ -17,7 +17,6 @@
* 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.
- *
*/
#ifndef RenderSVGText_h
diff --git a/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp b/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp
index 4ba2eeb..4712ddc 100644
--- a/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp
@@ -1,6 +1,4 @@
/*
- * This file is part of the WebKit project.
- *
* Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
*
* This library is free software; you can redistribute it and/or
@@ -17,7 +15,6 @@
* 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"
diff --git a/Source/WebCore/rendering/svg/RenderSVGTextPath.h b/Source/WebCore/rendering/svg/RenderSVGTextPath.h
index a71edf5..f1871b0 100644
--- a/Source/WebCore/rendering/svg/RenderSVGTextPath.h
+++ b/Source/WebCore/rendering/svg/RenderSVGTextPath.h
@@ -1,6 +1,4 @@
/*
- * This file is part of the WebKit project.
- *
* Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) 2009 Apple Inc. All rights reserved.
*
@@ -18,7 +16,6 @@
* 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.
- *
*/
#ifndef RenderSVGTextPath_h
diff --git a/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp
new file mode 100644
index 0000000..23aaa89
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * 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 "RenderSVGTransformableContainer.h"
+
+#include "SVGNames.h"
+#include "SVGShadowTreeElements.h"
+#include "SVGStyledTransformableElement.h"
+
+namespace WebCore {
+
+RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGStyledTransformableElement* node)
+ : RenderSVGContainer(node)
+ , m_needsTransformUpdate(true)
+{
+}
+
+bool RenderSVGTransformableContainer::calculateLocalTransform()
+{
+ SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(node());
+
+ bool needsUpdate = m_needsTransformUpdate;
+ if (needsUpdate) {
+ m_localTransform = element->animatedLocalTransform();
+ m_needsTransformUpdate = false;
+ }
+
+ if (!element->hasTagName(SVGNames::gTag) || !static_cast<SVGGElement*>(element)->isShadowTreeContainerElement())
+ return needsUpdate;
+
+ FloatSize translation = static_cast<SVGShadowTreeContainerElement*>(element)->containerTranslation();
+ if (!translation.width() && !translation.height())
+ return needsUpdate;
+
+ // FIXME: Could optimize this case for use to avoid refetching the animatedLocalTransform() here, if only the containerTranslation() changed.
+ if (!needsUpdate)
+ m_localTransform = element->animatedLocalTransform();
+
+ m_localTransform.translate(translation.width(), translation.height());
+ return true;
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h
new file mode 100644
index 0000000..401bfa8
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * 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.
+ */
+
+#ifndef RenderSVGTransformableContainer_h
+#define RenderSVGTransformableContainer_h
+
+#if ENABLE(SVG)
+#include "RenderSVGContainer.h"
+
+namespace WebCore {
+
+class SVGStyledTransformableElement;
+class RenderSVGTransformableContainer : public RenderSVGContainer {
+public:
+ explicit RenderSVGTransformableContainer(SVGStyledTransformableElement*);
+
+ virtual const AffineTransform& localToParentTransform() const { return m_localTransform; }
+ virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; }
+
+private:
+ virtual bool calculateLocalTransform();
+ virtual AffineTransform localTransform() const { return m_localTransform; }
+
+ bool m_needsTransformUpdate : 1;
+ AffineTransform m_localTransform;
+};
+}
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGTransformableContainer_h
diff --git a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp
new file mode 100644
index 0000000..7f4b6f7
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005, 2007 Rob Buis <buis@kde.org>
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * 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 "RenderSVGViewportContainer.h"
+
+#include "GraphicsContext.h"
+#include "RenderView.h"
+#include "SVGNames.h"
+#include "SVGSVGElement.h"
+
+namespace WebCore {
+
+RenderSVGViewportContainer::RenderSVGViewportContainer(SVGStyledElement* node)
+ : RenderSVGContainer(node)
+{
+}
+
+void RenderSVGViewportContainer::applyViewportClip(PaintInfo& paintInfo)
+{
+ if (SVGRenderSupport::isOverflowHidden(this))
+ paintInfo.context->clip(m_viewport);
+}
+
+void RenderSVGViewportContainer::calcViewport()
+{
+ SVGElement* element = static_cast<SVGElement*>(node());
+ if (element->hasTagName(SVGNames::svgTag)) {
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(element);
+
+ FloatRect oldViewport = m_viewport;
+ m_viewport = FloatRect(svg->x().value(svg)
+ , svg->y().value(svg)
+ , svg->width().value(svg)
+ , svg->height().value(svg));
+
+ if (oldViewport != m_viewport)
+ setNeedsBoundariesUpdate();
+ }
+}
+
+AffineTransform RenderSVGViewportContainer::viewportTransform() const
+{
+ if (node()->hasTagName(SVGNames::svgTag)) {
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
+ return svg->viewBoxToViewTransform(m_viewport.width(), m_viewport.height());
+ }
+
+ return AffineTransform();
+}
+
+const AffineTransform& RenderSVGViewportContainer::localToParentTransform() const
+{
+ AffineTransform viewportTranslation(viewportTransform());
+ m_localToParentTransform = viewportTranslation.translateRight(m_viewport.x(), m_viewport.y());
+ return m_localToParentTransform;
+ // If this class were ever given a localTransform(), then the above would read:
+ // return viewportTransform() * localTransform() * viewportTranslation;
+}
+
+bool RenderSVGViewportContainer::pointIsInsideViewportClip(const FloatPoint& pointInParent)
+{
+ // Respect the viewport clip (which is in parent coords)
+ if (!SVGRenderSupport::isOverflowHidden(this))
+ return true;
+
+ return m_viewport.contains(pointInParent);
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.h b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.h
new file mode 100644
index 0000000..66037e6
--- /dev/null
+++ b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005, 2007 Rob Buis <buis@kde.org>
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 Apple Inc. 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.
+ */
+
+#ifndef RenderSVGViewportContainer_h
+#define RenderSVGViewportContainer_h
+
+#if ENABLE(SVG)
+#include "RenderSVGContainer.h"
+
+namespace WebCore {
+
+// This is used for non-root <svg> elements and <marker> elements, neither of which are SVGTransformable
+// thus we inherit from RenderSVGContainer instead of RenderSVGTransformableContainer
+class RenderSVGViewportContainer : public RenderSVGContainer {
+public:
+ explicit RenderSVGViewportContainer(SVGStyledElement*);
+
+private:
+ virtual bool isSVGContainer() const { return true; }
+ virtual bool isSVGViewportContainer() const { return true; }
+ virtual const char* renderName() const { return "RenderSVGViewportContainer"; }
+
+ AffineTransform viewportTransform() const;
+ virtual const AffineTransform& localToParentTransform() const;
+
+ virtual void calcViewport();
+
+ virtual void applyViewportClip(PaintInfo&);
+ virtual bool pointIsInsideViewportClip(const FloatPoint& pointInParent);
+
+ FloatRect m_viewport;
+ mutable AffineTransform m_localToParentTransform;
+};
+
+inline RenderSVGViewportContainer* toRenderSVGViewportContainer(RenderObject* object)
+{
+ ASSERT(!object || !strcmp(object->renderName(), "RenderSVGViewportContainer"));
+ return static_cast<RenderSVGViewportContainer*>(object);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toRenderSVGViewportContainer(const RenderSVGViewportContainer*);
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGViewportContainer_h
diff --git a/Source/WebCore/rendering/svg/SVGImageBufferTools.cpp b/Source/WebCore/rendering/svg/SVGImageBufferTools.cpp
new file mode 100644
index 0000000..f0657af
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGImageBufferTools.cpp
@@ -0,0 +1,128 @@
+/*
+ * 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 "SVGImageBufferTools.h"
+
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "RenderObject.h"
+#include "RenderSVGContainer.h"
+#include "RenderSVGRoot.h"
+
+namespace WebCore {
+
+static AffineTransform& currentContentTransformation()
+{
+ DEFINE_STATIC_LOCAL(AffineTransform, s_currentContentTransformation, ());
+ return s_currentContentTransformation;
+}
+
+void SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(const RenderObject* renderer, AffineTransform& absoluteTransform)
+{
+ const RenderObject* current = renderer;
+ ASSERT(current);
+
+ absoluteTransform = currentContentTransformation();
+ while (current) {
+ absoluteTransform.multiply(current->localToParentTransform());
+ if (current->isSVGRoot())
+ break;
+ current = current->parent();
+ }
+}
+
+bool SVGImageBufferTools::createImageBuffer(const FloatRect& absoluteTargetRect, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>& imageBuffer, ColorSpace colorSpace)
+{
+ IntSize imageSize(roundedImageBufferSize(clampedAbsoluteTargetRect.size()));
+ IntSize unclampedImageSize(SVGImageBufferTools::roundedImageBufferSize(absoluteTargetRect.size()));
+
+ // Don't create empty ImageBuffers.
+ if (imageSize.isEmpty())
+ return false;
+
+ OwnPtr<ImageBuffer> image = ImageBuffer::create(imageSize, colorSpace);
+ if (!image)
+ return false;
+
+ GraphicsContext* imageContext = image->context();
+ ASSERT(imageContext);
+
+ // Compensate rounding effects, as the absolute target rect is using floating-point numbers and the image buffer size is integer.
+ imageContext->scale(FloatSize(unclampedImageSize.width() / absoluteTargetRect.width(), unclampedImageSize.height() / absoluteTargetRect.height()));
+
+ imageBuffer = image.release();
+ return true;
+}
+
+void SVGImageBufferTools::renderSubtreeToImageBuffer(ImageBuffer* image, RenderObject* item, const AffineTransform& subtreeContentTransformation)
+{
+ ASSERT(item);
+ ASSERT(image);
+ ASSERT(image->context());
+
+ PaintInfo info(image->context(), PaintInfo::infiniteRect(), PaintPhaseForeground, 0, 0, 0);
+
+ AffineTransform& contentTransformation = currentContentTransformation();
+ AffineTransform savedContentTransformation = contentTransformation;
+ contentTransformation.multiply(subtreeContentTransformation);
+
+ item->layoutIfNeeded();
+ item->paint(info, 0, 0);
+
+ contentTransformation = savedContentTransformation;
+}
+
+void SVGImageBufferTools::clipToImageBuffer(GraphicsContext* context, const AffineTransform& absoluteTransform, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>& imageBuffer)
+{
+ ASSERT(context);
+ ASSERT(imageBuffer);
+
+ // The mask image has been created in the absolute coordinate space, as the image should not be scaled.
+ // So the actual masking process has to be done in the absolute coordinate space as well.
+ context->concatCTM(absoluteTransform.inverse());
+ context->clipToImageBuffer(imageBuffer.get(), clampedAbsoluteTargetRect);
+ context->concatCTM(absoluteTransform);
+
+ // When nesting resources, with objectBoundingBox as content unit types, there's no use in caching the
+ // resulting image buffer as the parent resource already caches the result.
+ if (!currentContentTransformation().isIdentity())
+ imageBuffer.clear();
+}
+
+IntSize SVGImageBufferTools::roundedImageBufferSize(const FloatSize& size)
+{
+ return IntSize(static_cast<int>(lroundf(size.width())), static_cast<int>(lroundf(size.height())));
+}
+
+FloatRect SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(const RenderObject* renderer, const FloatRect& absoluteTargetRect)
+{
+ ASSERT(renderer);
+
+ const RenderSVGRoot* svgRoot = SVGRenderSupport::findTreeRootObject(renderer);
+ FloatRect clampedAbsoluteTargetRect = absoluteTargetRect;
+ clampedAbsoluteTargetRect.intersect(svgRoot->contentBoxRect());
+ return clampedAbsoluteTargetRect;
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/SVGImageBufferTools.h b/Source/WebCore/rendering/svg/SVGImageBufferTools.h
new file mode 100644
index 0000000..cfb15b2
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGImageBufferTools.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef SVGImageBufferTools_h
+#define SVGImageBufferTools_h
+
+#if ENABLE(SVG)
+#include "ImageBuffer.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class AffineTransform;
+class FloatRect;
+class FloatSize;
+class GraphicsContext;
+class RenderObject;
+
+class SVGImageBufferTools : public Noncopyable {
+public:
+ static bool createImageBuffer(const FloatRect& absoluteTargetRect, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>&, ColorSpace);
+ static void renderSubtreeToImageBuffer(ImageBuffer*, RenderObject*, const AffineTransform&);
+ static void clipToImageBuffer(GraphicsContext*, const AffineTransform& absoluteTransform, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>&);
+
+ static void calculateTransformationToOutermostSVGCoordinateSystem(const RenderObject*, AffineTransform& absoluteTransform);
+ static FloatRect clampedAbsoluteTargetRectForRenderer(const RenderObject*, const FloatRect& absoluteTargetRect);
+ static IntSize roundedImageBufferSize(const FloatSize&);
+
+private:
+ SVGImageBufferTools() { }
+ ~SVGImageBufferTools() { }
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp b/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp
index ea806c7..10735f6 100644
--- a/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp
+++ b/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
- * (C) 2006 Apple Computer Inc.
- * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2006 Apple Computer Inc.
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
@@ -18,7 +18,6 @@
* 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"
diff --git a/Source/WebCore/rendering/svg/SVGInlineFlowBox.h b/Source/WebCore/rendering/svg/SVGInlineFlowBox.h
index 2358f2d..0e56c9f 100644
--- a/Source/WebCore/rendering/svg/SVGInlineFlowBox.h
+++ b/Source/WebCore/rendering/svg/SVGInlineFlowBox.h
@@ -1,8 +1,6 @@
/*
- * This file is part of the WebKit project.
- *
* Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
- * (C) 2006 Apple Computer Inc.
+ * Copyright (C) 2006 Apple Computer Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -18,7 +16,6 @@
* 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.
- *
*/
#ifndef SVGInlineFlowBox_h
diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
index 5d0278b..f370310 100644
--- a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
+++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
@@ -1,6 +1,6 @@
/**
* Copyright (C) 2007 Rob Buis <buis@kde.org>
- * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
@@ -17,7 +17,6 @@
* 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"
diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.h b/Source/WebCore/rendering/svg/SVGInlineTextBox.h
index acc5e9f..0458de0 100644
--- a/Source/WebCore/rendering/svg/SVGInlineTextBox.h
+++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Rob Buis <buis@kde.org>
- * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
@@ -17,7 +17,6 @@
* 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.
- *
*/
#ifndef SVGInlineTextBox_h
diff --git a/Source/WebCore/rendering/svg/SVGMarkerData.h b/Source/WebCore/rendering/svg/SVGMarkerData.h
new file mode 100644
index 0000000..57c35cd
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGMarkerData.h
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#ifndef SVGMarkerData_h
+#define SVGMarkerData_h
+
+#if ENABLE(SVG)
+#include "FloatConversion.h"
+#include "Path.h"
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+class RenderSVGResourceMarker;
+
+class SVGMarkerData {
+public:
+ enum Type {
+ Unknown = 0,
+ Start,
+ Mid,
+ End
+ };
+
+ SVGMarkerData(const Type& type = Unknown, RenderSVGResourceMarker* marker = 0)
+ : m_type(type)
+ , m_marker(marker)
+ {
+ }
+
+ FloatPoint origin() const { return m_origin; }
+ RenderSVGResourceMarker* marker() const { return m_marker; }
+
+ float currentAngle() const
+ {
+ FloatSize inslopeChange = m_inslopePoints[1] - m_inslopePoints[0];
+ FloatSize outslopeChange = m_outslopePoints[1] - m_outslopePoints[0];
+
+ double inslope = rad2deg(atan2(inslopeChange.height(), inslopeChange.width()));
+ double outslope = rad2deg(atan2(outslopeChange.height(), outslopeChange.width()));
+
+ double angle = 0;
+ switch (m_type) {
+ case Start:
+ angle = outslope;
+ break;
+ case Mid:
+ angle = (inslope + outslope) / 2;
+ break;
+ case End:
+ angle = inslope;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ return narrowPrecisionToFloat(angle);
+ }
+
+ void updateTypeAndMarker(const Type& type, RenderSVGResourceMarker* marker)
+ {
+ m_type = type;
+ m_marker = marker;
+ }
+
+ void updateOutslope(const FloatPoint& point)
+ {
+ m_outslopePoints[0] = m_origin;
+ m_outslopePoints[1] = point;
+ }
+
+ void updateMarkerDataForPathElement(const PathElement* element)
+ {
+ FloatPoint* points = element->points;
+
+ switch (element->type) {
+ case PathElementAddQuadCurveToPoint:
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=33115 (PathElementAddQuadCurveToPoint not handled for <marker>)
+ m_origin = points[1];
+ break;
+ case PathElementAddCurveToPoint:
+ m_inslopePoints[0] = points[1];
+ m_inslopePoints[1] = points[2];
+ m_origin = points[2];
+ break;
+ case PathElementMoveToPoint:
+ m_subpathStart = points[0];
+ case PathElementAddLineToPoint:
+ updateInslope(points[0]);
+ m_origin = points[0];
+ break;
+ case PathElementCloseSubpath:
+ updateInslope(points[0]);
+ m_origin = m_subpathStart;
+ m_subpathStart = FloatPoint();
+ }
+ }
+
+private:
+ void updateInslope(const FloatPoint& point)
+ {
+ m_inslopePoints[0] = m_origin;
+ m_inslopePoints[1] = point;
+ }
+
+ Type m_type;
+ RenderSVGResourceMarker* m_marker;
+ FloatPoint m_origin;
+ FloatPoint m_subpathStart;
+ FloatPoint m_inslopePoints[2];
+ FloatPoint m_outslopePoints[2];
+};
+
+}
+
+#endif // ENABLE(SVG)
+#endif // SVGMarkerData_h
diff --git a/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp
new file mode 100644
index 0000000..dea5a0c
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2004, 2005, 2008 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005, 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * 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 "SVGMarkerLayoutInfo.h"
+
+#include "RenderSVGResourceMarker.h"
+
+namespace WebCore {
+
+SVGMarkerLayoutInfo::SVGMarkerLayoutInfo()
+ : m_midMarker(0)
+ , m_elementIndex(0)
+ , m_strokeWidth(0)
+{
+}
+
+SVGMarkerLayoutInfo::~SVGMarkerLayoutInfo()
+{
+}
+
+static inline void processStartAndMidMarkers(void* infoPtr, const PathElement* element)
+{
+ SVGMarkerLayoutInfo& info = *reinterpret_cast<SVGMarkerLayoutInfo*>(infoPtr);
+ SVGMarkerData& markerData = info.markerData();
+ int& elementIndex = info.elementIndex();
+
+ // First update the outslope for the previous element
+ markerData.updateOutslope(element->points[0]);
+
+ // Draw the marker for the previous element
+ RenderSVGResourceMarker* marker = markerData.marker();
+ if (elementIndex > 0 && marker)
+ info.addLayoutedMarker(marker, markerData.origin(), markerData.currentAngle());
+
+ // Update our marker data for this element
+ markerData.updateMarkerDataForPathElement(element);
+
+ // After drawing the start marker, switch to drawing mid markers
+ if (elementIndex == 1)
+ markerData.updateTypeAndMarker(SVGMarkerData::Mid, info.midMarker());
+
+ ++elementIndex;
+}
+
+FloatRect SVGMarkerLayoutInfo::calculateBoundaries(RenderSVGResourceMarker* startMarker, RenderSVGResourceMarker* midMarker, RenderSVGResourceMarker* endMarker, float strokeWidth, const Path& path)
+{
+ m_layout.clear();
+ m_midMarker = midMarker;
+ m_strokeWidth = strokeWidth;
+ m_elementIndex = 0;
+ m_markerData = SVGMarkerData(SVGMarkerData::Start, startMarker);
+ path.apply(this, processStartAndMidMarkers);
+
+ if (endMarker) {
+ m_markerData.updateTypeAndMarker(SVGMarkerData::End, endMarker);
+ addLayoutedMarker(endMarker, m_markerData.origin(), m_markerData.currentAngle());
+ }
+
+ if (m_layout.isEmpty())
+ return FloatRect();
+
+ Vector<MarkerLayout>::iterator it = m_layout.begin();
+ Vector<MarkerLayout>::iterator end = m_layout.end();
+
+ FloatRect bounds;
+ for (; it != end; ++it) {
+ MarkerLayout& layout = *it;
+
+ RenderSVGResourceMarker* markerContent = layout.marker;
+ ASSERT(markerContent);
+
+ bounds.unite(markerContent->markerBoundaries(layout.matrix));
+ }
+
+ return bounds;
+}
+
+void SVGMarkerLayoutInfo::drawMarkers(PaintInfo& paintInfo)
+{
+ if (m_layout.isEmpty())
+ return;
+
+ Vector<MarkerLayout>::iterator it = m_layout.begin();
+ Vector<MarkerLayout>::iterator end = m_layout.end();
+
+ for (; it != end; ++it) {
+ MarkerLayout& layout = *it;
+ layout.marker->draw(paintInfo, layout.matrix);
+ }
+}
+
+void SVGMarkerLayoutInfo::addLayoutedMarker(RenderSVGResourceMarker* marker, const FloatPoint& origin, float angle)
+{
+ ASSERT(marker);
+ m_layout.append(MarkerLayout(marker, marker->markerTransformation(origin, angle, m_strokeWidth)));
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h
new file mode 100644
index 0000000..0eb3689
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#ifndef SVGMarkerLayoutInfo_h
+#define SVGMarkerLayoutInfo_h
+
+#if ENABLE(SVG)
+#include "RenderObject.h"
+#include "SVGMarkerData.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class Path;
+class RenderSVGResourceMarker;
+
+struct MarkerLayout {
+ MarkerLayout(RenderSVGResourceMarker* markerObj = 0, AffineTransform matrixObj = AffineTransform())
+ : marker(markerObj)
+ , matrix(matrixObj)
+ {
+ ASSERT(marker);
+ }
+
+ RenderSVGResourceMarker* marker;
+ AffineTransform matrix;
+};
+
+class SVGMarkerLayoutInfo : public Noncopyable {
+public:
+ SVGMarkerLayoutInfo();
+ ~SVGMarkerLayoutInfo();
+
+ FloatRect calculateBoundaries(RenderSVGResourceMarker* startMarker, RenderSVGResourceMarker* midMarker, RenderSVGResourceMarker* endMarker, float strokeWidth, const Path&);
+ void drawMarkers(PaintInfo&);
+
+ // Used by static inline helper functions in SVGMarkerLayoutInfo.cpp
+ SVGMarkerData& markerData() { return m_markerData; }
+ RenderSVGResourceMarker* midMarker() const { return m_midMarker; }
+ int& elementIndex() { return m_elementIndex; }
+ void addLayoutedMarker(RenderSVGResourceMarker*, const FloatPoint& origin, float angle);
+
+private:
+ RenderSVGResourceMarker* m_midMarker;
+
+ // Used while layouting markers
+ int m_elementIndex;
+ SVGMarkerData m_markerData;
+ float m_strokeWidth;
+
+ // Holds the final computed result
+ Vector<MarkerLayout> m_layout;
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/SVGRenderSupport.cpp b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp
new file mode 100644
index 0000000..bfc74f0
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2007, 2008 Rob Buis <buis@kde.org>
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Google, Inc. All rights reserved.
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) Research In Motion Limited 2009-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 "SVGRenderSupport.h"
+
+#include "FrameView.h"
+#include "ImageBuffer.h"
+#include "NodeRenderStyle.h"
+#include "RenderLayer.h"
+#include "RenderSVGPath.h"
+#include "RenderSVGResource.h"
+#include "RenderSVGResourceClipper.h"
+#include "RenderSVGResourceFilter.h"
+#include "RenderSVGResourceMarker.h"
+#include "RenderSVGResourceMasker.h"
+#include "RenderSVGRoot.h"
+#include "SVGResources.h"
+#include "SVGStyledElement.h"
+#include "TransformState.h"
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+IntRect SVGRenderSupport::clippedOverflowRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer)
+{
+ // Return early for any cases where we don't actually paint
+ if (object->style()->visibility() != VISIBLE && !object->enclosingLayer()->hasVisibleContent())
+ return IntRect();
+
+ // Pass our local paint rect to computeRectForRepaint() which will
+ // map to parent coords and recurse up the parent chain.
+ IntRect repaintRect = enclosingIntRect(object->repaintRectInLocalCoordinates());
+ object->computeRectForRepaint(repaintContainer, repaintRect);
+ return repaintRect;
+}
+
+void SVGRenderSupport::computeRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
+{
+ const SVGRenderStyle* svgStyle = object->style()->svgStyle();
+ if (const ShadowData* shadow = svgStyle->shadow())
+ shadow->adjustRectForShadow(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);
+}
+
+void SVGRenderSupport::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 transforms is useless.
+ transformState.applyTransform(object->localToParentTransform());
+ object->parent()->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
+}
+
+bool SVGRenderSupport::prepareToRenderSVGContent(RenderObject* object, PaintInfo& paintInfo)
+{
+ ASSERT(object);
+
+ RenderStyle* style = object->style();
+ ASSERT(style);
+
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+ ASSERT(svgStyle);
+
+ // Setup transparency layers before setting up SVG resources!
+ float opacity = style->opacity();
+ const ShadowData* shadow = svgStyle->shadow();
+ if (opacity < 1 || shadow) {
+ FloatRect repaintRect = object->repaintRectInLocalCoordinates();
+
+ if (opacity < 1) {
+ paintInfo.context->clip(repaintRect);
+ paintInfo.context->beginTransparencyLayer(opacity);
+ }
+
+ if (shadow) {
+ paintInfo.context->clip(repaintRect);
+ paintInfo.context->setShadow(IntSize(shadow->x(), shadow->y()), shadow->blur(), shadow->color(), style->colorSpace());
+ paintInfo.context->beginTransparencyLayer(1);
+ }
+ }
+
+ SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
+ if (!resources)
+ return true;
+
+ if (RenderSVGResourceMasker* masker = resources->masker()) {
+ if (!masker->applyResource(object, style, paintInfo.context, ApplyToDefaultMode))
+ return false;
+ }
+
+ if (RenderSVGResourceClipper* clipper = resources->clipper()) {
+ if (!clipper->applyResource(object, style, paintInfo.context, ApplyToDefaultMode))
+ return false;
+ }
+
+#if ENABLE(FILTERS)
+ if (RenderSVGResourceFilter* filter = resources->filter()) {
+ if (!filter->applyResource(object, style, paintInfo.context, ApplyToDefaultMode))
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+void SVGRenderSupport::finishRenderSVGContent(RenderObject* object, PaintInfo& paintInfo, GraphicsContext* savedContext)
+{
+#if !ENABLE(FILTERS)
+ UNUSED_PARAM(savedContext);
+#endif
+
+ ASSERT(object);
+
+ const RenderStyle* style = object->style();
+ ASSERT(style);
+
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+ ASSERT(svgStyle);
+
+#if ENABLE(FILTERS)
+ SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
+ if (resources) {
+ if (RenderSVGResourceFilter* filter = resources->filter()) {
+ filter->postApplyResource(object, paintInfo.context, ApplyToDefaultMode, /* path */0);
+ paintInfo.context = savedContext;
+ }
+ }
+#endif
+
+ if (style->opacity() < 1)
+ paintInfo.context->endTransparencyLayer();
+
+ if (svgStyle->shadow())
+ paintInfo.context->endTransparencyLayer();
+}
+
+void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObject* container, FloatRect& objectBoundingBox, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox)
+{
+ for (RenderObject* current = container->firstChild(); current; current = current->nextSibling()) {
+ if (current->isSVGHiddenContainer())
+ continue;
+
+ const AffineTransform& transform = current->localToParentTransform();
+ if (transform.isIdentity()) {
+ objectBoundingBox.unite(current->objectBoundingBox());
+ strokeBoundingBox.unite(current->strokeBoundingBox());
+ repaintBoundingBox.unite(current->repaintRectInLocalCoordinates());
+ } else {
+ objectBoundingBox.unite(transform.mapRect(current->objectBoundingBox()));
+ strokeBoundingBox.unite(transform.mapRect(current->strokeBoundingBox()));
+ repaintBoundingBox.unite(transform.mapRect(current->repaintRectInLocalCoordinates()));
+ }
+ }
+}
+
+bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo& paintInfo)
+{
+ if (localTransform.isIdentity())
+ return localRepaintRect.intersects(paintInfo.rect);
+
+ return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect);
+}
+
+const RenderSVGRoot* SVGRenderSupport::findTreeRootObject(const RenderObject* start)
+{
+ while (start && !start->isSVGRoot())
+ start = start->parent();
+
+ ASSERT(start);
+ ASSERT(start->isSVGRoot());
+ return toRenderSVGRoot(start);
+}
+
+static inline void invalidateResourcesOfChildren(RenderObject* start)
+{
+ ASSERT(!start->needsLayout());
+ if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(start))
+ resources->removeClientFromCache(start, false);
+
+ for (RenderObject* child = start->firstChild(); child; child = child->nextSibling())
+ invalidateResourcesOfChildren(child);
+}
+
+void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout)
+{
+ bool layoutSizeChanged = findTreeRootObject(start)->isLayoutSizeChanged();
+ HashSet<RenderObject*> notlayoutedObjects;
+
+ for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
+ bool needsLayout = selfNeedsLayout;
+
+ if (layoutSizeChanged) {
+ // When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths
+ if (SVGElement* element = child->node()->isSVGElement() ? static_cast<SVGElement*>(child->node()) : 0) {
+ if (element->isStyled() && static_cast<SVGStyledElement*>(element)->hasRelativeLengths()) {
+ // When the layout size changed and when using relative values tell the RenderSVGPath to update its Path object
+ if (child->isSVGPath())
+ toRenderSVGPath(child)->setNeedsPathUpdate();
+
+ needsLayout = true;
+ }
+ }
+ }
+
+ if (needsLayout) {
+ child->setNeedsLayout(true, false);
+ child->layout();
+ } else {
+ if (child->needsLayout())
+ child->layout();
+ else if (layoutSizeChanged)
+ notlayoutedObjects.add(child);
+ }
+
+ ASSERT(!child->needsLayout());
+ }
+
+ if (!layoutSizeChanged) {
+ ASSERT(notlayoutedObjects.isEmpty());
+ return;
+ }
+
+ // If the layout size changed, invalidate all resources of all children that didn't go through the layout() code path.
+ HashSet<RenderObject*>::iterator end = notlayoutedObjects.end();
+ for (HashSet<RenderObject*>::iterator it = notlayoutedObjects.begin(); it != end; ++it)
+ invalidateResourcesOfChildren(*it);
+}
+
+bool SVGRenderSupport::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;
+}
+
+void SVGRenderSupport::intersectRepaintRectWithResources(const RenderObject* object, FloatRect& repaintRect)
+{
+ ASSERT(object);
+
+ RenderStyle* style = object->style();
+ ASSERT(style);
+
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+ ASSERT(svgStyle);
+
+ RenderObject* renderer = const_cast<RenderObject*>(object);
+ SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer);
+ if (!resources) {
+ if (const ShadowData* shadow = svgStyle->shadow())
+ shadow->adjustRectForShadow(repaintRect);
+ return;
+ }
+
+#if ENABLE(FILTERS)
+ if (RenderSVGResourceFilter* filter = resources->filter())
+ repaintRect = filter->resourceBoundingBox(renderer);
+#endif
+
+ if (RenderSVGResourceClipper* clipper = resources->clipper())
+ repaintRect.intersect(clipper->resourceBoundingBox(renderer));
+
+ if (RenderSVGResourceMasker* masker = resources->masker())
+ repaintRect.intersect(masker->resourceBoundingBox(renderer));
+
+ if (const ShadowData* shadow = svgStyle->shadow())
+ shadow->adjustRectForShadow(repaintRect);
+}
+
+bool SVGRenderSupport::pointInClippingArea(RenderObject* object, const FloatPoint& point)
+{
+ ASSERT(object);
+
+ // We just take clippers into account to determine if a point is on the node. The Specification may
+ // change later and we also need to check maskers.
+ SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
+ if (!resources)
+ return true;
+
+ if (RenderSVGResourceClipper* clipper = resources->clipper())
+ return clipper->hitTestClipContent(object->objectBoundingBox(), point);
+
+ return true;
+}
+
+void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const RenderStyle* style, const RenderObject* object)
+{
+ ASSERT(context);
+ ASSERT(style);
+ ASSERT(object);
+ ASSERT(object->node());
+ ASSERT(object->node()->isSVGElement());
+
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+ ASSERT(svgStyle);
+
+ SVGElement* lengthContext = static_cast<SVGElement*>(object->node());
+ context->setStrokeThickness(svgStyle->strokeWidth().value(lengthContext));
+ context->setLineCap(svgStyle->capStyle());
+ context->setLineJoin(svgStyle->joinStyle());
+ if (svgStyle->joinStyle() == MiterJoin)
+ context->setMiterLimit(svgStyle->strokeMiterLimit());
+
+ const Vector<SVGLength>& dashes = svgStyle->strokeDashArray();
+ if (dashes.isEmpty())
+ context->setStrokeStyle(SolidStroke);
+ else {
+ DashArray dashArray;
+ const Vector<SVGLength>::const_iterator end = dashes.end();
+ for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it)
+ dashArray.append((*it).value(lengthContext));
+
+ context->setLineDash(dashArray, svgStyle->strokeDashOffset().value(lengthContext));
+ }
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/svg/SVGRenderSupport.h b/Source/WebCore/rendering/svg/SVGRenderSupport.h
new file mode 100644
index 0000000..9e6aa5c
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGRenderSupport.h
@@ -0,0 +1,83 @@
+/**
+ * Copyright (C) 2007 Rob Buis <buis@kde.org>
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Google, Inc. All rights reserved.
+ * 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.
+ */
+
+#ifndef SVGRenderSupport_h
+#define SVGRenderSupport_h
+
+#if ENABLE(SVG)
+#include "PaintInfo.h"
+
+namespace WebCore {
+
+class FloatPoint;
+class FloatRect;
+class ImageBuffer;
+class RenderBoxModelObject;
+class RenderObject;
+class RenderStyle;
+class RenderSVGRoot;
+class TransformState;
+
+// SVGRendererSupport is a helper class sharing code between all SVG renderers.
+class SVGRenderSupport {
+public:
+ // Used by all SVG renderers who apply clip/filter/etc. resources to the renderer content
+ static bool prepareToRenderSVGContent(RenderObject*, PaintInfo&);
+ static void finishRenderSVGContent(RenderObject*, PaintInfo&, GraphicsContext* savedContext);
+
+ // Shares child layouting code between RenderSVGRoot/RenderSVG(Hidden)Container
+ static void layoutChildren(RenderObject*, bool selfNeedsLayout);
+
+ // Helper function determining wheter overflow is hidden
+ static bool isOverflowHidden(const RenderObject*);
+
+ // Calculates the repaintRect in combination with filter, clipper and masker in local coordinates.
+ static void intersectRepaintRectWithResources(const RenderObject*, FloatRect&);
+
+ // Determines whether the passed point lies in a clipping area
+ static bool pointInClippingArea(RenderObject*, const FloatPoint&);
+
+ static void computeContainerBoundingBoxes(const RenderObject* container, FloatRect& objectBoundingBox, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox);
+ static bool paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo&);
+
+ // Important functions used by nearly all SVG renderers centralizing coordinate transformations / repaint rect calculations
+ static IntRect clippedOverflowRectForRepaint(RenderObject*, RenderBoxModelObject* repaintContainer);
+ static void computeRectForRepaint(RenderObject*, RenderBoxModelObject* repaintContainer, IntRect&, bool fixed);
+ static void mapLocalToContainer(const RenderObject*, RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&);
+
+ // Shared between SVG renderers and resources.
+ static void applyStrokeStyleToContext(GraphicsContext*, const RenderStyle*, const RenderObject*);
+
+ // FIXME: These methods do not belong here.
+ static const RenderSVGRoot* findTreeRootObject(const RenderObject*);
+
+private:
+ // This class is not constructable.
+ SVGRenderSupport();
+ ~SVGRenderSupport();
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif // SVGRenderSupport_h
diff --git a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp
new file mode 100644
index 0000000..97e15af
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp
@@ -0,0 +1,748 @@
+/*
+ * Copyright (C) 2004, 2005, 2007, 2009 Apple Inc. All rights reserved.
+ * (C) 2005 Rob Buis <buis@kde.org>
+ * (C) 2006 Alexander Kellett <lypanov@kde.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGRenderTreeAsText.h"
+
+#include "GraphicsTypes.h"
+#include "HTMLNames.h"
+#include "InlineTextBox.h"
+#include "LinearGradientAttributes.h"
+#include "NodeRenderStyle.h"
+#include "Path.h"
+#include "PatternAttributes.h"
+#include "RadialGradientAttributes.h"
+#include "RenderImage.h"
+#include "RenderSVGContainer.h"
+#include "RenderSVGGradientStop.h"
+#include "RenderSVGImage.h"
+#include "RenderSVGInlineText.h"
+#include "RenderSVGPath.h"
+#include "RenderSVGResourceClipper.h"
+#include "RenderSVGResourceFilter.h"
+#include "RenderSVGResourceGradient.h"
+#include "RenderSVGResourceLinearGradient.h"
+#include "RenderSVGResourceMarker.h"
+#include "RenderSVGResourceMasker.h"
+#include "RenderSVGResourcePattern.h"
+#include "RenderSVGResourceRadialGradient.h"
+#include "RenderSVGResourceSolidColor.h"
+#include "RenderSVGRoot.h"
+#include "RenderSVGText.h"
+#include "RenderTreeAsText.h"
+#include "SVGCircleElement.h"
+#include "SVGEllipseElement.h"
+#include "SVGInlineTextBox.h"
+#include "SVGLineElement.h"
+#include "SVGLinearGradientElement.h"
+#include "SVGNames.h"
+#include "SVGPathElement.h"
+#include "SVGPathParserFactory.h"
+#include "SVGPatternElement.h"
+#include "SVGPointList.h"
+#include "SVGPolyElement.h"
+#include "SVGRadialGradientElement.h"
+#include "SVGRectElement.h"
+#include "SVGRootInlineBox.h"
+#include "SVGStopElement.h"
+#include "SVGStyledElement.h"
+
+#include <math.h>
+
+namespace WebCore {
+
+/** class + iomanip to help streaming list separators, i.e. ", " in string "a, b, c, d"
+ * Can be used in cases where you don't know which item in the list is the first
+ * one to be printed, but still want to avoid strings like ", b, c".
+ */
+class TextStreamSeparator {
+public:
+ TextStreamSeparator(const String& s)
+ : m_separator(s)
+ , m_needToSeparate(false)
+ {
+ }
+
+private:
+ friend TextStream& operator<<(TextStream&, TextStreamSeparator&);
+
+ String m_separator;
+ bool m_needToSeparate;
+};
+
+TextStream& operator<<(TextStream& ts, TextStreamSeparator& sep)
+{
+ if (sep.m_needToSeparate)
+ ts << sep.m_separator;
+ else
+ sep.m_needToSeparate = true;
+ return ts;
+}
+
+template<typename ValueType>
+static void writeNameValuePair(TextStream& ts, const char* name, ValueType value)
+{
+ ts << " [" << name << "=" << value << "]";
+}
+
+template<typename ValueType>
+static void writeNameAndQuotedValue(TextStream& ts, const char* name, ValueType value)
+{
+ ts << " [" << name << "=\"" << value << "\"]";
+}
+
+static void writeIfNotEmpty(TextStream& ts, const char* name, const String& value)
+{
+ if (!value.isEmpty())
+ writeNameValuePair(ts, name, value);
+}
+
+template<typename ValueType>
+static void writeIfNotDefault(TextStream& ts, const char* name, ValueType value, ValueType defaultValue)
+{
+ if (value != defaultValue)
+ writeNameValuePair(ts, name, value);
+}
+
+TextStream& operator<<(TextStream& ts, const FloatRect &r)
+{
+ ts << "at (";
+ if (hasFractions(r.x()))
+ ts << r.x();
+ else
+ ts << int(r.x());
+ ts << ",";
+ if (hasFractions(r.y()))
+ ts << r.y();
+ else
+ ts << int(r.y());
+ ts << ") size ";
+ if (hasFractions(r.width()))
+ ts << r.width();
+ else
+ ts << int(r.width());
+ ts << "x";
+ if (hasFractions(r.height()))
+ ts << r.height();
+ else
+ ts << int(r.height());
+ return ts;
+}
+
+TextStream& operator<<(TextStream& ts, const AffineTransform& transform)
+{
+ if (transform.isIdentity())
+ ts << "identity";
+ else
+ ts << "{m=(("
+ << transform.a() << "," << transform.b()
+ << ")("
+ << transform.c() << "," << transform.d()
+ << ")) t=("
+ << transform.e() << "," << transform.f()
+ << ")}";
+
+ return ts;
+}
+
+static TextStream& operator<<(TextStream& ts, const WindRule rule)
+{
+ switch (rule) {
+ case RULE_NONZERO:
+ ts << "NON-ZERO";
+ break;
+ case RULE_EVENODD:
+ ts << "EVEN-ODD";
+ break;
+ }
+
+ return ts;
+}
+
+static TextStream& operator<<(TextStream& ts, const SVGUnitTypes::SVGUnitType& unitType)
+{
+ switch (unitType) {
+ case SVGUnitTypes::SVG_UNIT_TYPE_UNKNOWN:
+ ts << "unknown";
+ break;
+ case SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE:
+ ts << "userSpaceOnUse";
+ break;
+ case SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX:
+ ts << "objectBoundingBox";
+ break;
+ }
+
+ return ts;
+}
+
+static TextStream& operator<<(TextStream& ts, const SVGMarkerElement::SVGMarkerUnitsType& markerUnit)
+{
+ switch (markerUnit) {
+ case SVGMarkerElement::SVG_MARKERUNITS_UNKNOWN:
+ ts << "unknown";
+ break;
+ case SVGMarkerElement::SVG_MARKERUNITS_USERSPACEONUSE:
+ ts << "userSpaceOnUse";
+ break;
+ case SVGMarkerElement::SVG_MARKERUNITS_STROKEWIDTH:
+ ts << "strokeWidth";
+ break;
+ }
+
+ return ts;
+}
+
+TextStream& operator<<(TextStream& ts, const Color& c)
+{
+ return ts << c.name();
+}
+
+// FIXME: Maybe this should be in KCanvasRenderingStyle.cpp
+static TextStream& operator<<(TextStream& ts, const DashArray& a)
+{
+ ts << "{";
+ DashArray::const_iterator end = a.end();
+ for (DashArray::const_iterator it = a.begin(); it != end; ++it) {
+ if (it != a.begin())
+ ts << ", ";
+ ts << *it;
+ }
+ ts << "}";
+ return ts;
+}
+
+// FIXME: Maybe this should be in GraphicsTypes.cpp
+static TextStream& operator<<(TextStream& ts, LineCap style)
+{
+ switch (style) {
+ case ButtCap:
+ ts << "BUTT";
+ break;
+ case RoundCap:
+ ts << "ROUND";
+ break;
+ case SquareCap:
+ ts << "SQUARE";
+ break;
+ }
+ return ts;
+}
+
+// FIXME: Maybe this should be in GraphicsTypes.cpp
+static TextStream& operator<<(TextStream& ts, LineJoin style)
+{
+ switch (style) {
+ case MiterJoin:
+ ts << "MITER";
+ break;
+ case RoundJoin:
+ ts << "ROUND";
+ break;
+ case BevelJoin:
+ ts << "BEVEL";
+ break;
+ }
+ return ts;
+}
+
+// FIXME: Maybe this should be in Gradient.cpp
+static TextStream& operator<<(TextStream& ts, GradientSpreadMethod mode)
+{
+ switch (mode) {
+ case SpreadMethodPad:
+ ts << "PAD";
+ break;
+ case SpreadMethodRepeat:
+ ts << "REPEAT";
+ break;
+ case SpreadMethodReflect:
+ ts << "REFLECT";
+ break;
+ }
+
+ return ts;
+}
+
+static void writeSVGPaintingResource(TextStream& ts, RenderSVGResource* resource)
+{
+ if (resource->resourceType() == SolidColorResourceType) {
+ ts << "[type=SOLID] [color=" << static_cast<RenderSVGResourceSolidColor*>(resource)->color() << "]";
+ return;
+ }
+
+ // All other resources derive from RenderSVGResourceContainer
+ RenderSVGResourceContainer* container = static_cast<RenderSVGResourceContainer*>(resource);
+ Node* node = container->node();
+ ASSERT(node);
+ ASSERT(node->isSVGElement());
+
+ if (resource->resourceType() == PatternResourceType)
+ ts << "[type=PATTERN]";
+ else if (resource->resourceType() == LinearGradientResourceType)
+ ts << "[type=LINEAR-GRADIENT]";
+ else if (resource->resourceType() == RadialGradientResourceType)
+ ts << "[type=RADIAL-GRADIENT]";
+
+ ts << " [id=\"" << static_cast<SVGElement*>(node)->getIdAttribute() << "\"]";
+}
+
+static void writeStyle(TextStream& ts, const RenderObject& object)
+{
+ const RenderStyle* style = object.style();
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+
+ if (!object.localTransform().isIdentity())
+ writeNameValuePair(ts, "transform", object.localTransform());
+ writeIfNotDefault(ts, "image rendering", svgStyle->imageRendering(), SVGRenderStyle::initialImageRendering());
+ writeIfNotDefault(ts, "opacity", style->opacity(), RenderStyle::initialOpacity());
+ if (object.isSVGPath()) {
+ const RenderSVGPath& path = static_cast<const RenderSVGPath&>(object);
+ ASSERT(path.node());
+ ASSERT(path.node()->isSVGElement());
+
+ Color fallbackColor;
+ if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(const_cast<RenderSVGPath*>(&path), path.style(), fallbackColor)) {
+ TextStreamSeparator s(" ");
+ ts << " [stroke={" << s;
+ writeSVGPaintingResource(ts, strokePaintingResource);
+
+ SVGElement* element = static_cast<SVGElement*>(path.node());
+ double dashOffset = svgStyle->strokeDashOffset().value(element);
+ double strokeWidth = svgStyle->strokeWidth().value(element);
+ const Vector<SVGLength>& dashes = svgStyle->strokeDashArray();
+
+ DashArray dashArray;
+ const Vector<SVGLength>::const_iterator end = dashes.end();
+ for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it)
+ dashArray.append((*it).value(element));
+
+ writeIfNotDefault(ts, "opacity", svgStyle->strokeOpacity(), 1.0f);
+ writeIfNotDefault(ts, "stroke width", strokeWidth, 1.0);
+ writeIfNotDefault(ts, "miter limit", svgStyle->strokeMiterLimit(), 4.0f);
+ writeIfNotDefault(ts, "line cap", svgStyle->capStyle(), ButtCap);
+ writeIfNotDefault(ts, "line join", svgStyle->joinStyle(), MiterJoin);
+ writeIfNotDefault(ts, "dash offset", dashOffset, 0.0);
+ if (!dashArray.isEmpty())
+ writeNameValuePair(ts, "dash array", dashArray);
+
+ ts << "}]";
+ }
+
+ if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(const_cast<RenderSVGPath*>(&path), path.style(), fallbackColor)) {
+ TextStreamSeparator s(" ");
+ ts << " [fill={" << s;
+ writeSVGPaintingResource(ts, fillPaintingResource);
+
+ writeIfNotDefault(ts, "opacity", svgStyle->fillOpacity(), 1.0f);
+ writeIfNotDefault(ts, "fill rule", svgStyle->fillRule(), RULE_NONZERO);
+ ts << "}]";
+ }
+ writeIfNotDefault(ts, "clip rule", svgStyle->clipRule(), RULE_NONZERO);
+ }
+
+ writeIfNotEmpty(ts, "start marker", svgStyle->markerStartResource());
+ writeIfNotEmpty(ts, "middle marker", svgStyle->markerMidResource());
+ writeIfNotEmpty(ts, "end marker", svgStyle->markerEndResource());
+}
+
+static TextStream& writePositionAndStyle(TextStream& ts, const RenderObject& object)
+{
+ ts << " " << const_cast<RenderObject&>(object).absoluteClippedOverflowRect();
+ writeStyle(ts, object);
+ return ts;
+}
+
+static TextStream& operator<<(TextStream& ts, const RenderSVGPath& path)
+{
+ writePositionAndStyle(ts, path);
+
+ ASSERT(path.node()->isSVGElement());
+ SVGElement* svgElement = static_cast<SVGElement*>(path.node());
+
+ if (svgElement->hasTagName(SVGNames::rectTag)) {
+ SVGRectElement* element = static_cast<SVGRectElement*>(svgElement);
+ writeNameValuePair(ts, "x", element->x().value(element));
+ writeNameValuePair(ts, "y", element->y().value(element));
+ writeNameValuePair(ts, "width", element->width().value(element));
+ writeNameValuePair(ts, "height", element->height().value(element));
+ } else if (svgElement->hasTagName(SVGNames::lineTag)) {
+ SVGLineElement* element = static_cast<SVGLineElement*>(svgElement);
+ writeNameValuePair(ts, "x1", element->x1().value(element));
+ writeNameValuePair(ts, "y1", element->y1().value(element));
+ writeNameValuePair(ts, "x2", element->x2().value(element));
+ writeNameValuePair(ts, "y2", element->y2().value(element));
+ } else if (svgElement->hasTagName(SVGNames::ellipseTag)) {
+ SVGEllipseElement* element = static_cast<SVGEllipseElement*>(svgElement);
+ writeNameValuePair(ts, "cx", element->cx().value(element));
+ writeNameValuePair(ts, "cy", element->cy().value(element));
+ writeNameValuePair(ts, "rx", element->rx().value(element));
+ writeNameValuePair(ts, "ry", element->ry().value(element));
+ } else if (svgElement->hasTagName(SVGNames::circleTag)) {
+ SVGCircleElement* element = static_cast<SVGCircleElement*>(svgElement);
+ writeNameValuePair(ts, "cx", element->cx().value(element));
+ writeNameValuePair(ts, "cy", element->cy().value(element));
+ writeNameValuePair(ts, "r", element->r().value(element));
+ } else if (svgElement->hasTagName(SVGNames::polygonTag) || svgElement->hasTagName(SVGNames::polylineTag)) {
+ SVGPolyElement* element = static_cast<SVGPolyElement*>(svgElement);
+ writeNameAndQuotedValue(ts, "points", element->pointList().valueAsString());
+ } else if (svgElement->hasTagName(SVGNames::pathTag)) {
+ SVGPathElement* element = static_cast<SVGPathElement*>(svgElement);
+ String pathString;
+ // FIXME: We should switch to UnalteredParsing here - this will affect the path dumping output of dozens of tests.
+ SVGPathParserFactory::self()->buildStringFromByteStream(element->pathByteStream(), pathString, NormalizedParsing);
+ writeNameAndQuotedValue(ts, "data", pathString);
+ } else
+ ASSERT_NOT_REACHED();
+ return ts;
+}
+
+static TextStream& operator<<(TextStream& ts, const RenderSVGRoot& root)
+{
+ return writePositionAndStyle(ts, root);
+}
+
+static void writeRenderSVGTextBox(TextStream& ts, const RenderBlock& text)
+{
+ SVGRootInlineBox* box = static_cast<SVGRootInlineBox*>(text.firstRootBox());
+ if (!box)
+ return;
+
+ ts << " at (" << text.x() << "," << text.y() << ") size " << box->logicalWidth() << "x" << box->logicalHeight();
+
+ // FIXME: Remove this hack, once the new text layout engine is completly landed. We want to preserve the old layout test results for now.
+ ts << " contains 1 chunk(s)";
+
+ if (text.parent() && (text.parent()->style()->visitedDependentColor(CSSPropertyColor) != text.style()->visitedDependentColor(CSSPropertyColor)))
+ writeNameValuePair(ts, "color", text.style()->visitedDependentColor(CSSPropertyColor).name());
+}
+
+static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textBox, int indent)
+{
+ Vector<SVGTextFragment>& fragments = textBox->textFragments();
+ if (fragments.isEmpty())
+ return;
+
+ RenderSVGInlineText* textRenderer = toRenderSVGInlineText(textBox->textRenderer());
+ ASSERT(textRenderer);
+
+ const SVGRenderStyle* svgStyle = textRenderer->style()->svgStyle();
+ String text = textBox->textRenderer()->text();
+
+ unsigned fragmentsSize = fragments.size();
+ for (unsigned i = 0; i < fragmentsSize; ++i) {
+ SVGTextFragment& fragment = fragments.at(i);
+ writeIndent(ts, indent + 1);
+
+ unsigned startOffset = fragment.positionListOffset;
+ unsigned endOffset = fragment.positionListOffset + fragment.length;
+
+ // FIXME: Remove this hack, once the new text layout engine is completly landed. We want to preserve the old layout test results for now.
+ ts << "chunk 1 ";
+ ETextAnchor anchor = svgStyle->textAnchor();
+ bool isVerticalText = svgStyle->isVerticalWritingMode();
+ if (anchor == TA_MIDDLE) {
+ ts << "(middle anchor";
+ if (isVerticalText)
+ ts << ", vertical";
+ ts << ") ";
+ } else if (anchor == TA_END) {
+ ts << "(end anchor";
+ if (isVerticalText)
+ ts << ", vertical";
+ ts << ") ";
+ } else if (isVerticalText)
+ ts << "(vertical) ";
+ startOffset -= textBox->start();
+ endOffset -= textBox->start();
+ // </hack>
+
+ ts << "text run " << i + 1 << " at (" << fragment.x << "," << fragment.y << ")";
+ ts << " startOffset " << startOffset << " endOffset " << endOffset;
+ if (isVerticalText)
+ ts << " height " << fragment.height;
+ else
+ ts << " width " << fragment.width;
+
+ if (!textBox->isLeftToRightDirection() || textBox->m_dirOverride) {
+ ts << (textBox->isLeftToRightDirection() ? " LTR" : " RTL");
+ if (textBox->m_dirOverride)
+ ts << " override";
+ }
+
+ ts << ": " << quoteAndEscapeNonPrintables(text.substring(fragment.positionListOffset, fragment.length)) << "\n";
+ }
+}
+
+static inline void writeSVGInlineTextBoxes(TextStream& ts, const RenderText& text, int indent)
+{
+ for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox())
+ writeSVGInlineTextBox(ts, static_cast<SVGInlineTextBox*>(box), indent);
+}
+
+static void writeStandardPrefix(TextStream& ts, const RenderObject& object, int indent)
+{
+ writeIndent(ts, indent);
+ ts << object.renderName();
+
+ if (object.node())
+ ts << " {" << object.node()->nodeName() << "}";
+}
+
+static void writeChildren(TextStream& ts, const RenderObject& object, int indent)
+{
+ for (RenderObject* child = object.firstChild(); child; child = child->nextSibling())
+ write(ts, *child, indent + 1);
+}
+
+static inline String boundingBoxModeString(bool boundingBoxMode)
+{
+ return boundingBoxMode ? "objectBoundingBox" : "userSpaceOnUse";
+}
+
+static inline void writeCommonGradientProperties(TextStream& ts, GradientSpreadMethod spreadMethod, const AffineTransform& gradientTransform, bool boundingBoxMode)
+{
+ writeNameValuePair(ts, "gradientUnits", boundingBoxModeString(boundingBoxMode));
+
+ if (spreadMethod != SpreadMethodPad)
+ ts << " [spreadMethod=" << spreadMethod << "]";
+
+ if (!gradientTransform.isIdentity())
+ ts << " [gradientTransform=" << gradientTransform << "]";
+}
+
+void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int indent)
+{
+ writeStandardPrefix(ts, object, indent);
+
+ Element* element = static_cast<Element*>(object.node());
+ const AtomicString& id = element->getIdAttribute();
+ writeNameAndQuotedValue(ts, "id", id);
+
+ RenderSVGResourceContainer* resource = const_cast<RenderObject&>(object).toRenderSVGResourceContainer();
+ ASSERT(resource);
+
+ if (resource->resourceType() == MaskerResourceType) {
+ RenderSVGResourceMasker* masker = static_cast<RenderSVGResourceMasker*>(resource);
+ writeNameValuePair(ts, "maskUnits", masker->maskUnits());
+ writeNameValuePair(ts, "maskContentUnits", masker->maskContentUnits());
+ ts << "\n";
+#if ENABLE(FILTERS)
+ } else if (resource->resourceType() == FilterResourceType) {
+ RenderSVGResourceFilter* filter = static_cast<RenderSVGResourceFilter*>(resource);
+ writeNameValuePair(ts, "filterUnits", filter->filterUnits());
+ writeNameValuePair(ts, "primitiveUnits", filter->primitiveUnits());
+ ts << "\n";
+ // Creating a placeholder filter which is passed to the builder.
+ FloatRect dummyRect;
+ RefPtr<SVGFilter> dummyFilter = SVGFilter::create(AffineTransform(), dummyRect, dummyRect, dummyRect, true);
+ if (RefPtr<SVGFilterBuilder> builder = filter->buildPrimitives(dummyFilter.get())) {
+ if (FilterEffect* lastEffect = builder->lastEffect())
+ lastEffect->externalRepresentation(ts, indent + 1);
+ }
+#endif
+ } else if (resource->resourceType() == ClipperResourceType) {
+ RenderSVGResourceClipper* clipper = static_cast<RenderSVGResourceClipper*>(resource);
+ writeNameValuePair(ts, "clipPathUnits", clipper->clipPathUnits());
+ ts << "\n";
+ } else if (resource->resourceType() == MarkerResourceType) {
+ RenderSVGResourceMarker* marker = static_cast<RenderSVGResourceMarker*>(resource);
+ writeNameValuePair(ts, "markerUnits", marker->markerUnits());
+ ts << " [ref at " << marker->referencePoint() << "]";
+ ts << " [angle=";
+ if (marker->angle() == -1)
+ ts << "auto" << "]\n";
+ else
+ ts << marker->angle() << "]\n";
+ } else if (resource->resourceType() == PatternResourceType) {
+ RenderSVGResourcePattern* pattern = static_cast<RenderSVGResourcePattern*>(resource);
+
+ // Dump final results that are used for rendering. No use in asking SVGPatternElement for its patternUnits(), as it may
+ // link to other patterns using xlink:href, we need to build the full inheritance chain, aka. collectPatternProperties()
+ PatternAttributes attributes;
+ static_cast<SVGPatternElement*>(pattern->node())->collectPatternAttributes(attributes);
+
+ writeNameValuePair(ts, "patternUnits", boundingBoxModeString(attributes.boundingBoxMode()));
+ writeNameValuePair(ts, "patternContentUnits", boundingBoxModeString(attributes.boundingBoxModeContent()));
+
+ AffineTransform transform = attributes.patternTransform();
+ if (!transform.isIdentity())
+ ts << " [patternTransform=" << transform << "]";
+ ts << "\n";
+ } else if (resource->resourceType() == LinearGradientResourceType) {
+ RenderSVGResourceLinearGradient* gradient = static_cast<RenderSVGResourceLinearGradient*>(resource);
+
+ // Dump final results that are used for rendering. No use in asking SVGGradientElement for its gradientUnits(), as it may
+ // link to other gradients using xlink:href, we need to build the full inheritance chain, aka. collectGradientProperties()
+ SVGLinearGradientElement* linearGradientElement = static_cast<SVGLinearGradientElement*>(gradient->node());
+
+ LinearGradientAttributes attributes;
+ linearGradientElement->collectGradientAttributes(attributes);
+ writeCommonGradientProperties(ts, attributes.spreadMethod(), attributes.gradientTransform(), attributes.boundingBoxMode());
+
+ FloatPoint startPoint;
+ FloatPoint endPoint;
+ linearGradientElement->calculateStartEndPoints(attributes, startPoint, endPoint);
+
+ ts << " [start=" << startPoint << "] [end=" << endPoint << "]\n";
+ } else if (resource->resourceType() == RadialGradientResourceType) {
+ RenderSVGResourceRadialGradient* gradient = static_cast<RenderSVGResourceRadialGradient*>(resource);
+
+ // Dump final results that are used for rendering. No use in asking SVGGradientElement for its gradientUnits(), as it may
+ // link to other gradients using xlink:href, we need to build the full inheritance chain, aka. collectGradientProperties()
+ SVGRadialGradientElement* radialGradientElement = static_cast<SVGRadialGradientElement*>(gradient->node());
+
+ RadialGradientAttributes attributes;
+ radialGradientElement->collectGradientAttributes(attributes);
+ writeCommonGradientProperties(ts, attributes.spreadMethod(), attributes.gradientTransform(), attributes.boundingBoxMode());
+
+ FloatPoint focalPoint;
+ FloatPoint centerPoint;
+ float radius;
+ radialGradientElement->calculateFocalCenterPointsAndRadius(attributes, focalPoint, centerPoint, radius);
+
+ ts << " [center=" << centerPoint << "] [focal=" << focalPoint << "] [radius=" << radius << "]\n";
+ } else
+ ts << "\n";
+ writeChildren(ts, object, indent);
+}
+
+void writeSVGContainer(TextStream& ts, const RenderObject& container, int indent)
+{
+ // Currently RenderSVGResourceFilterPrimitive has no meaningful output.
+ if (container.isSVGResourceFilterPrimitive())
+ return;
+ writeStandardPrefix(ts, container, indent);
+ writePositionAndStyle(ts, container);
+ ts << "\n";
+ writeResources(ts, container, indent);
+ writeChildren(ts, container, indent);
+}
+
+void write(TextStream& ts, const RenderSVGRoot& root, int indent)
+{
+ writeStandardPrefix(ts, root, indent);
+ ts << root << "\n";
+ writeChildren(ts, root, indent);
+}
+
+void writeSVGText(TextStream& ts, const RenderBlock& text, int indent)
+{
+ writeStandardPrefix(ts, text, indent);
+ writeRenderSVGTextBox(ts, text);
+ ts << "\n";
+ writeResources(ts, text, indent);
+ writeChildren(ts, text, indent);
+}
+
+void writeSVGInlineText(TextStream& ts, const RenderText& text, int indent)
+{
+ writeStandardPrefix(ts, text, indent);
+
+ // Why not just linesBoundingBox()?
+ ts << " " << FloatRect(text.firstRunOrigin(), text.linesBoundingBox().size()) << "\n";
+ writeResources(ts, text, indent);
+ writeSVGInlineTextBoxes(ts, text, indent);
+}
+
+void writeSVGImage(TextStream& ts, const RenderSVGImage& image, int indent)
+{
+ writeStandardPrefix(ts, image, indent);
+ writePositionAndStyle(ts, image);
+ ts << "\n";
+ writeResources(ts, image, indent);
+}
+
+void write(TextStream& ts, const RenderSVGPath& path, int indent)
+{
+ writeStandardPrefix(ts, path, indent);
+ ts << path << "\n";
+ writeResources(ts, path, indent);
+}
+
+void writeSVGGradientStop(TextStream& ts, const RenderSVGGradientStop& stop, int indent)
+{
+ writeStandardPrefix(ts, stop, indent);
+
+ SVGStopElement* stopElement = static_cast<SVGStopElement*>(stop.node());
+ ASSERT(stopElement);
+
+ RenderStyle* style = stop.style();
+ if (!style)
+ return;
+
+ ts << " [offset=" << stopElement->offset() << "] [color=" << stopElement->stopColorIncludingOpacity() << "]\n";
+}
+
+void writeResources(TextStream& ts, const RenderObject& object, int indent)
+{
+ const RenderStyle* style = object.style();
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+
+ // FIXME: We want to use SVGResourcesCache to determine which resources are present, instead of quering the resource <-> id cache.
+ // For now leave the DRT output as is, but later on we should change this so cycles are properly ignored in the DRT output.
+ RenderObject& renderer = const_cast<RenderObject&>(object);
+ if (!svgStyle->maskerResource().isEmpty()) {
+ if (RenderSVGResourceMasker* masker = getRenderSVGResourceById<RenderSVGResourceMasker>(object.document(), svgStyle->maskerResource())) {
+ writeIndent(ts, indent);
+ ts << " ";
+ writeNameAndQuotedValue(ts, "masker", svgStyle->maskerResource());
+ ts << " ";
+ writeStandardPrefix(ts, *masker, 0);
+ ts << " " << masker->resourceBoundingBox(&renderer) << "\n";
+ }
+ }
+ if (!svgStyle->clipperResource().isEmpty()) {
+ if (RenderSVGResourceClipper* clipper = getRenderSVGResourceById<RenderSVGResourceClipper>(object.document(), svgStyle->clipperResource())) {
+ writeIndent(ts, indent);
+ ts << " ";
+ writeNameAndQuotedValue(ts, "clipPath", svgStyle->clipperResource());
+ ts << " ";
+ writeStandardPrefix(ts, *clipper, 0);
+ ts << " " << clipper->resourceBoundingBox(&renderer) << "\n";
+ }
+ }
+#if ENABLE(FILTERS)
+ if (!svgStyle->filterResource().isEmpty()) {
+ if (RenderSVGResourceFilter* filter = getRenderSVGResourceById<RenderSVGResourceFilter>(object.document(), svgStyle->filterResource())) {
+ writeIndent(ts, indent);
+ ts << " ";
+ writeNameAndQuotedValue(ts, "filter", svgStyle->filterResource());
+ ts << " ";
+ writeStandardPrefix(ts, *filter, 0);
+ ts << " " << filter->resourceBoundingBox(&renderer) << "\n";
+ }
+ }
+#endif
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.h b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.h
new file mode 100644
index 0000000..ce07a5c
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2004, 2005, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SVGRenderTreeAsText_h
+#define SVGRenderTreeAsText_h
+
+#if ENABLE(SVG)
+
+#include "TextStream.h"
+
+namespace WebCore {
+
+class Color;
+class FloatRect;
+class FloatSize;
+class Node;
+class RenderBlock;
+class RenderImage;
+class RenderObject;
+class RenderSVGGradientStop;
+class RenderSVGImage;
+class RenderSVGPath;
+class RenderSVGRoot;
+class RenderText;
+class AffineTransform;
+class SVGUnitTypes;
+
+// functions used by the main RenderTreeAsText code
+void write(TextStream&, const RenderSVGPath&, int indent);
+void write(TextStream&, const RenderSVGRoot&, int indent);
+void writeSVGGradientStop(TextStream&, const RenderSVGGradientStop&, int indent);
+void writeSVGResourceContainer(TextStream&, const RenderObject&, int indent);
+void writeSVGContainer(TextStream&, const RenderObject&, int indent);
+void writeSVGImage(TextStream&, const RenderSVGImage&, int indent);
+void writeSVGInlineText(TextStream&, const RenderText&, int indent);
+void writeSVGText(TextStream&, const RenderBlock&, int indent);
+void writeResources(TextStream&, const RenderObject&, int indent);
+
+// helper operators defined used in various classes to dump the render tree.
+TextStream& operator<<(TextStream&, const AffineTransform&);
+TextStream& operator<<(TextStream&, const Color&);
+TextStream& operator<<(TextStream&, const FloatRect&);
+
+// helper operators specific to dumping the render tree. these are used in various classes to dump the render tree
+// these could be defined in separate namespace to avoid matching these generic signatures unintentionally.
+
+template<typename Item>
+TextStream& operator<<(TextStream& ts, const Vector<Item*>& v)
+{
+ ts << "[";
+
+ for (unsigned i = 0; i < v.size(); i++) {
+ ts << *v[i];
+ if (i < v.size() - 1)
+ ts << ", ";
+ }
+
+ ts << "]";
+ return ts;
+}
+
+template<typename Pointer>
+TextStream& operator<<(TextStream& ts, Pointer* t)
+{
+ ts << reinterpret_cast<intptr_t>(t);
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+
+#endif // SVGRenderTreeAsText_h
diff --git a/Source/WebCore/rendering/svg/SVGResources.cpp b/Source/WebCore/rendering/svg/SVGResources.cpp
new file mode 100644
index 0000000..9a2c999
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGResources.cpp
@@ -0,0 +1,684 @@
+/*
+ * 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"
+#include "SVGResources.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGResourceClipper.h"
+#include "RenderSVGResourceFilter.h"
+#include "RenderSVGResourceMarker.h"
+#include "RenderSVGResourceMasker.h"
+#include "SVGFilterElement.h"
+#include "SVGGradientElement.h"
+#include "SVGNames.h"
+#include "SVGPaint.h"
+#include "SVGPatternElement.h"
+#include "SVGRenderStyle.h"
+#include "SVGURIReference.h"
+
+namespace WebCore {
+
+SVGResources::SVGResources()
+ : m_clipperFilterMaskerData(0)
+ , m_markerData(0)
+ , m_fillStrokeData(0)
+ , m_linkedResource(0)
+{
+}
+
+static HashSet<AtomicStringImpl*>& clipperFilterMaskerTags()
+{
+ DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, s_tagList, ());
+ if (s_tagList.isEmpty()) {
+ // "container elements": http://www.w3.org/TR/SVG11/intro.html#TermContainerElement
+ // "graphics elements" : http://www.w3.org/TR/SVG11/intro.html#TermGraphicsElement
+ s_tagList.add(SVGNames::aTag.localName().impl());
+ s_tagList.add(SVGNames::circleTag.localName().impl());
+ s_tagList.add(SVGNames::ellipseTag.localName().impl());
+ s_tagList.add(SVGNames::glyphTag.localName().impl());
+ s_tagList.add(SVGNames::gTag.localName().impl());
+ s_tagList.add(SVGNames::imageTag.localName().impl());
+ s_tagList.add(SVGNames::lineTag.localName().impl());
+ s_tagList.add(SVGNames::markerTag.localName().impl());
+ s_tagList.add(SVGNames::maskTag.localName().impl());
+ s_tagList.add(SVGNames::missing_glyphTag.localName().impl());
+ s_tagList.add(SVGNames::pathTag.localName().impl());
+ s_tagList.add(SVGNames::polygonTag.localName().impl());
+ s_tagList.add(SVGNames::polylineTag.localName().impl());
+ s_tagList.add(SVGNames::rectTag.localName().impl());
+ s_tagList.add(SVGNames::svgTag.localName().impl());
+ s_tagList.add(SVGNames::textTag.localName().impl());
+ s_tagList.add(SVGNames::useTag.localName().impl());
+
+ // Not listed in the definitions is the clipPath element, the SVG spec says though:
+ // The "clipPath" element or any of its children can specify property "clip-path".
+ // So we have to add clipPathTag here, otherwhise clip-path on clipPath will fail.
+ // (Already mailed SVG WG, waiting for a solution)
+ s_tagList.add(SVGNames::clipPathTag.localName().impl());
+
+ // Not listed in the definitions are the text content elements, though filter/clipper/masker on tspan/text/.. is allowed.
+ // (Already mailed SVG WG, waiting for a solution)
+ s_tagList.add(SVGNames::altGlyphTag.localName().impl());
+ s_tagList.add(SVGNames::textPathTag.localName().impl());
+ s_tagList.add(SVGNames::trefTag.localName().impl());
+ s_tagList.add(SVGNames::tspanTag.localName().impl());
+
+ // Elements that we ignore, as it doesn't make any sense.
+ // defs, pattern, switch (FIXME: Mail SVG WG about these)
+ // symbol (is converted to a svg element, when referenced by use, we can safely ignore it.)
+ }
+
+ return s_tagList;
+}
+
+static HashSet<AtomicStringImpl*>& markerTags()
+{
+ DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, s_tagList, ());
+ if (s_tagList.isEmpty()) {
+ s_tagList.add(SVGNames::lineTag.localName().impl());
+ s_tagList.add(SVGNames::pathTag.localName().impl());
+ s_tagList.add(SVGNames::polygonTag.localName().impl());
+ s_tagList.add(SVGNames::polylineTag.localName().impl());
+ }
+
+ return s_tagList;
+}
+
+static HashSet<AtomicStringImpl*>& fillAndStrokeTags()
+{
+ DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, s_tagList, ());
+ if (s_tagList.isEmpty()) {
+ s_tagList.add(SVGNames::altGlyphTag.localName().impl());
+ s_tagList.add(SVGNames::circleTag.localName().impl());
+ s_tagList.add(SVGNames::ellipseTag.localName().impl());
+ s_tagList.add(SVGNames::lineTag.localName().impl());
+ s_tagList.add(SVGNames::pathTag.localName().impl());
+ s_tagList.add(SVGNames::polygonTag.localName().impl());
+ s_tagList.add(SVGNames::polylineTag.localName().impl());
+ s_tagList.add(SVGNames::rectTag.localName().impl());
+ s_tagList.add(SVGNames::textTag.localName().impl());
+ s_tagList.add(SVGNames::textPathTag.localName().impl());
+ s_tagList.add(SVGNames::trefTag.localName().impl());
+ s_tagList.add(SVGNames::tspanTag.localName().impl());
+ }
+
+ return s_tagList;
+}
+
+static HashSet<AtomicStringImpl*>& chainableResourceTags()
+{
+ DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, s_tagList, ());
+ if (s_tagList.isEmpty()) {
+ s_tagList.add(SVGNames::linearGradientTag.localName().impl());
+ s_tagList.add(SVGNames::filterTag.localName().impl());
+ s_tagList.add(SVGNames::patternTag.localName().impl());
+ s_tagList.add(SVGNames::radialGradientTag.localName().impl());
+ }
+
+ return s_tagList;
+}
+
+static inline String targetReferenceFromResource(SVGElement* element)
+{
+ String target;
+ if (element->hasTagName(SVGNames::patternTag))
+ target = static_cast<SVGPatternElement*>(element)->href();
+ else if (element->hasTagName(SVGNames::linearGradientTag) || element->hasTagName(SVGNames::radialGradientTag))
+ target = static_cast<SVGGradientElement*>(element)->href();
+#if ENABLE(FILTERS)
+ else if (element->hasTagName(SVGNames::filterTag))
+ target = static_cast<SVGFilterElement*>(element)->href();
+#endif
+ else
+ ASSERT_NOT_REACHED();
+
+ return SVGURIReference::getTarget(target);
+}
+
+static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document* document, SVGPaint* paint, AtomicString& id, bool& hasPendingResource)
+{
+ ASSERT(paint);
+
+ SVGPaint::SVGPaintType paintType = paint->paintType();
+ if (paintType != SVGPaint::SVG_PAINTTYPE_URI && paintType != SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR)
+ return 0;
+
+ id = SVGURIReference::getTarget(paint->uri());
+ RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id);
+ if (!container) {
+ hasPendingResource = true;
+ return 0;
+ }
+
+ RenderSVGResourceType resourceType = container->resourceType();
+ if (resourceType != PatternResourceType && resourceType != LinearGradientResourceType && resourceType != RadialGradientResourceType)
+ return 0;
+
+ return container;
+}
+
+static inline void registerPendingResource(SVGDocumentExtensions* extensions, const AtomicString& id, SVGElement* element)
+{
+ ASSERT(element);
+ if (!element->isStyled())
+ return;
+
+ extensions->addPendingResource(id, static_cast<SVGStyledElement*>(element));
+}
+
+bool SVGResources::buildCachedResources(const RenderObject* object, const SVGRenderStyle* style)
+{
+ ASSERT(object);
+ ASSERT(style);
+
+ Node* node = object->node();
+ ASSERT(node);
+ ASSERT(node->isSVGElement());
+
+ SVGElement* element = static_cast<SVGElement*>(node);
+ if (!element)
+ return false;
+
+ Document* document = object->document();
+ ASSERT(document);
+
+ SVGDocumentExtensions* extensions = document->accessSVGExtensions();
+ ASSERT(extensions);
+
+ AtomicStringImpl* tagNameImpl = element->tagQName().localName().impl();
+ if (!tagNameImpl)
+ return false;
+
+ bool foundResources = false;
+ if (clipperFilterMaskerTags().contains(tagNameImpl)) {
+ if (style->hasClipper()) {
+ AtomicString id(style->clipperResource());
+ if (setClipper(getRenderSVGResourceById<RenderSVGResourceClipper>(document, id)))
+ foundResources = true;
+ else
+ registerPendingResource(extensions, id, element);
+ }
+
+#if ENABLE(FILTERS)
+ if (style->hasFilter()) {
+ AtomicString id(style->filterResource());
+ if (setFilter(getRenderSVGResourceById<RenderSVGResourceFilter>(document, id)))
+ foundResources = true;
+ else
+ registerPendingResource(extensions, id, element);
+ }
+#endif
+
+ if (style->hasMasker()) {
+ AtomicString id(style->maskerResource());
+ if (setMasker(getRenderSVGResourceById<RenderSVGResourceMasker>(document, id)))
+ foundResources = true;
+ else
+ registerPendingResource(extensions, id, element);
+ }
+ }
+
+ if (markerTags().contains(tagNameImpl) && style->hasMarkers()) {
+ AtomicString markerStartId(style->markerStartResource());
+ if (setMarkerStart(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerStartId)))
+ foundResources = true;
+ else
+ registerPendingResource(extensions, markerStartId, element);
+
+ AtomicString markerMidId(style->markerMidResource());
+ if (setMarkerMid(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerMidId)))
+ foundResources = true;
+ else
+ registerPendingResource(extensions, markerMidId, element);
+
+ AtomicString markerEndId(style->markerEndResource());
+ if (setMarkerEnd(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerEndId)))
+ foundResources = true;
+ else
+ registerPendingResource(extensions, markerEndId, element);
+ }
+
+ if (fillAndStrokeTags().contains(tagNameImpl)) {
+ if (style->hasFill()) {
+ bool hasPendingResource = false;
+ AtomicString id;
+ if (setFill(paintingResourceFromSVGPaint(document, style->fillPaint(), id, hasPendingResource)))
+ foundResources = true;
+ else if (hasPendingResource)
+ registerPendingResource(extensions, id, element);
+ }
+
+ if (style->hasStroke()) {
+ bool hasPendingResource = false;
+ AtomicString id;
+ if (setStroke(paintingResourceFromSVGPaint(document, style->strokePaint(), id, hasPendingResource)))
+ foundResources = true;
+ else if (hasPendingResource)
+ registerPendingResource(extensions, id, element);
+ }
+ }
+
+ if (chainableResourceTags().contains(tagNameImpl)) {
+ AtomicString id(targetReferenceFromResource(element));
+ if (setLinkedResource(getRenderSVGResourceContainerById(document, id)))
+ foundResources = true;
+ else
+ registerPendingResource(extensions, id, element);
+ }
+
+ return foundResources;
+}
+
+void SVGResources::removeClientFromCache(RenderObject* object, bool markForInvalidation) const
+{
+ if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
+ return;
+
+ if (m_linkedResource) {
+ ASSERT(!m_clipperFilterMaskerData);
+ ASSERT(!m_markerData);
+ ASSERT(!m_fillStrokeData);
+ m_linkedResource->removeClientFromCache(object, markForInvalidation);
+ return;
+ }
+
+ if (m_clipperFilterMaskerData) {
+ if (m_clipperFilterMaskerData->clipper)
+ m_clipperFilterMaskerData->clipper->removeClientFromCache(object, markForInvalidation);
+#if ENABLE(FILTERS)
+ if (m_clipperFilterMaskerData->filter)
+ m_clipperFilterMaskerData->filter->removeClientFromCache(object, markForInvalidation);
+#endif
+ if (m_clipperFilterMaskerData->masker)
+ m_clipperFilterMaskerData->masker->removeClientFromCache(object, markForInvalidation);
+ }
+
+ if (m_markerData) {
+ if (m_markerData->markerStart)
+ m_markerData->markerStart->removeClientFromCache(object, markForInvalidation);
+ if (m_markerData->markerMid)
+ m_markerData->markerMid->removeClientFromCache(object, markForInvalidation);
+ if (m_markerData->markerEnd)
+ m_markerData->markerEnd->removeClientFromCache(object, markForInvalidation);
+ }
+
+ if (m_fillStrokeData) {
+ if (m_fillStrokeData->fill)
+ m_fillStrokeData->fill->removeClientFromCache(object, markForInvalidation);
+ if (m_fillStrokeData->stroke)
+ m_fillStrokeData->stroke->removeClientFromCache(object, markForInvalidation);
+ }
+}
+
+void SVGResources::resourceDestroyed(RenderSVGResourceContainer* resource)
+{
+ ASSERT(resource);
+ if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
+ return;
+
+ if (m_linkedResource == resource) {
+ ASSERT(!m_clipperFilterMaskerData);
+ ASSERT(!m_markerData);
+ ASSERT(!m_fillStrokeData);
+ m_linkedResource->removeAllClientsFromCache();
+ m_linkedResource = 0;
+ return;
+ }
+
+ switch (resource->resourceType()) {
+ case MaskerResourceType:
+ if (!m_clipperFilterMaskerData)
+ break;
+ if (m_clipperFilterMaskerData->masker == resource) {
+ m_clipperFilterMaskerData->masker->removeAllClientsFromCache();
+ m_clipperFilterMaskerData->masker = 0;
+ }
+ break;
+ case MarkerResourceType:
+ if (!m_markerData)
+ break;
+ if (m_markerData->markerStart == resource) {
+ m_markerData->markerStart->removeAllClientsFromCache();
+ m_markerData->markerStart = 0;
+ }
+ if (m_markerData->markerMid == resource) {
+ m_markerData->markerMid->removeAllClientsFromCache();
+ m_markerData->markerMid = 0;
+ }
+ if (m_markerData->markerEnd == resource) {
+ m_markerData->markerEnd->removeAllClientsFromCache();
+ m_markerData->markerEnd = 0;
+ }
+ break;
+ case PatternResourceType:
+ case LinearGradientResourceType:
+ case RadialGradientResourceType:
+ if (!m_fillStrokeData)
+ break;
+ if (m_fillStrokeData->fill == resource) {
+ m_fillStrokeData->fill->removeAllClientsFromCache();
+ m_fillStrokeData->fill = 0;
+ }
+ if (m_fillStrokeData->stroke == resource) {
+ m_fillStrokeData->stroke->removeAllClientsFromCache();
+ m_fillStrokeData->stroke = 0;
+ }
+ break;
+ case FilterResourceType:
+#if ENABLE(FILTERS)
+ if (!m_clipperFilterMaskerData)
+ break;
+ if (m_clipperFilterMaskerData->filter == resource) {
+ m_clipperFilterMaskerData->filter->removeAllClientsFromCache();
+ m_clipperFilterMaskerData->filter = 0;
+ }
+#else
+ ASSERT_NOT_REACHED();
+#endif
+ break;
+ case ClipperResourceType:
+ if (!m_clipperFilterMaskerData)
+ break;
+ if (m_clipperFilterMaskerData->clipper == resource) {
+ m_clipperFilterMaskerData->clipper->removeAllClientsFromCache();
+ m_clipperFilterMaskerData->clipper = 0;
+ }
+ break;
+ case SolidColorResourceType:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void SVGResources::buildSetOfResources(HashSet<RenderSVGResourceContainer*>& set)
+{
+ if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
+ return;
+
+ if (m_linkedResource) {
+ ASSERT(!m_clipperFilterMaskerData);
+ ASSERT(!m_markerData);
+ ASSERT(!m_fillStrokeData);
+ set.add(m_linkedResource);
+ return;
+ }
+
+ if (m_clipperFilterMaskerData) {
+ if (m_clipperFilterMaskerData->clipper)
+ set.add(m_clipperFilterMaskerData->clipper);
+#if ENABLE(FILTERS)
+ if (m_clipperFilterMaskerData->filter)
+ set.add(m_clipperFilterMaskerData->filter);
+#endif
+ if (m_clipperFilterMaskerData->masker)
+ set.add(m_clipperFilterMaskerData->masker);
+ }
+
+ if (m_markerData) {
+ if (m_markerData->markerStart)
+ set.add(m_markerData->markerStart);
+ if (m_markerData->markerMid)
+ set.add(m_markerData->markerMid);
+ if (m_markerData->markerEnd)
+ set.add(m_markerData->markerEnd);
+ }
+
+ if (m_fillStrokeData) {
+ if (m_fillStrokeData->fill)
+ set.add(m_fillStrokeData->fill);
+ if (m_fillStrokeData->stroke)
+ set.add(m_fillStrokeData->stroke);
+ }
+}
+
+bool SVGResources::setClipper(RenderSVGResourceClipper* clipper)
+{
+ if (!clipper)
+ return false;
+
+ ASSERT(clipper->resourceType() == ClipperResourceType);
+
+ if (!m_clipperFilterMaskerData)
+ m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
+
+ m_clipperFilterMaskerData->clipper = clipper;
+ return true;
+}
+
+void SVGResources::resetClipper()
+{
+ ASSERT(m_clipperFilterMaskerData);
+ ASSERT(m_clipperFilterMaskerData->clipper);
+ m_clipperFilterMaskerData->clipper = 0;
+}
+
+#if ENABLE(FILTERS)
+bool SVGResources::setFilter(RenderSVGResourceFilter* filter)
+{
+ if (!filter)
+ return false;
+
+ ASSERT(filter->resourceType() == FilterResourceType);
+
+ if (!m_clipperFilterMaskerData)
+ m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
+
+ m_clipperFilterMaskerData->filter = filter;
+ return true;
+}
+
+void SVGResources::resetFilter()
+{
+ ASSERT(m_clipperFilterMaskerData);
+ ASSERT(m_clipperFilterMaskerData->filter);
+ m_clipperFilterMaskerData->filter = 0;
+}
+#endif
+
+bool SVGResources::setMarkerStart(RenderSVGResourceMarker* markerStart)
+{
+ if (!markerStart)
+ return false;
+
+ ASSERT(markerStart->resourceType() == MarkerResourceType);
+
+ if (!m_markerData)
+ m_markerData = MarkerData::create();
+
+ m_markerData->markerStart = markerStart;
+ return true;
+}
+
+void SVGResources::resetMarkerStart()
+{
+ ASSERT(m_markerData);
+ ASSERT(m_markerData->markerStart);
+ m_markerData->markerStart = 0;
+}
+
+bool SVGResources::setMarkerMid(RenderSVGResourceMarker* markerMid)
+{
+ if (!markerMid)
+ return false;
+
+ ASSERT(markerMid->resourceType() == MarkerResourceType);
+
+ if (!m_markerData)
+ m_markerData = MarkerData::create();
+
+ m_markerData->markerMid = markerMid;
+ return true;
+}
+
+void SVGResources::resetMarkerMid()
+{
+ ASSERT(m_markerData);
+ ASSERT(m_markerData->markerMid);
+ m_markerData->markerMid = 0;
+}
+
+bool SVGResources::setMarkerEnd(RenderSVGResourceMarker* markerEnd)
+{
+ if (!markerEnd)
+ return false;
+
+ ASSERT(markerEnd->resourceType() == MarkerResourceType);
+
+ if (!m_markerData)
+ m_markerData = MarkerData::create();
+
+ m_markerData->markerEnd = markerEnd;
+ return true;
+}
+
+void SVGResources::resetMarkerEnd()
+{
+ ASSERT(m_markerData);
+ ASSERT(m_markerData->markerEnd);
+ m_markerData->markerEnd = 0;
+}
+
+bool SVGResources::setMasker(RenderSVGResourceMasker* masker)
+{
+ if (!masker)
+ return false;
+
+ ASSERT(masker->resourceType() == MaskerResourceType);
+
+ if (!m_clipperFilterMaskerData)
+ m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
+
+ m_clipperFilterMaskerData->masker = masker;
+ return true;
+}
+
+void SVGResources::resetMasker()
+{
+ ASSERT(m_clipperFilterMaskerData);
+ ASSERT(m_clipperFilterMaskerData->masker);
+ m_clipperFilterMaskerData->masker = 0;
+}
+
+bool SVGResources::setFill(RenderSVGResourceContainer* fill)
+{
+ if (!fill)
+ return false;
+
+ ASSERT(fill->resourceType() == PatternResourceType
+ || fill->resourceType() == LinearGradientResourceType
+ || fill->resourceType() == RadialGradientResourceType);
+
+ if (!m_fillStrokeData)
+ m_fillStrokeData = FillStrokeData::create();
+
+ m_fillStrokeData->fill = fill;
+ return true;
+}
+
+void SVGResources::resetFill()
+{
+ ASSERT(m_fillStrokeData);
+ ASSERT(m_fillStrokeData->fill);
+ m_fillStrokeData->fill = 0;
+}
+
+bool SVGResources::setStroke(RenderSVGResourceContainer* stroke)
+{
+ if (!stroke)
+ return false;
+
+ ASSERT(stroke->resourceType() == PatternResourceType
+ || stroke->resourceType() == LinearGradientResourceType
+ || stroke->resourceType() == RadialGradientResourceType);
+
+ if (!m_fillStrokeData)
+ m_fillStrokeData = FillStrokeData::create();
+
+ m_fillStrokeData->stroke = stroke;
+ return true;
+}
+
+void SVGResources::resetStroke()
+{
+ ASSERT(m_fillStrokeData);
+ ASSERT(m_fillStrokeData->stroke);
+ m_fillStrokeData->stroke = 0;
+}
+
+bool SVGResources::setLinkedResource(RenderSVGResourceContainer* linkedResource)
+{
+ if (!linkedResource)
+ return false;
+
+ m_linkedResource = linkedResource;
+ return true;
+}
+
+void SVGResources::resetLinkedResource()
+{
+ ASSERT(m_linkedResource);
+ m_linkedResource = 0;
+}
+
+#ifndef NDEBUG
+void SVGResources::dump(const RenderObject* object)
+{
+ ASSERT(object);
+ ASSERT(object->node());
+
+ fprintf(stderr, "-> this=%p, SVGResources(renderer=%p, node=%p)\n", this, object, object->node());
+ fprintf(stderr, " | DOM Tree:\n");
+ object->node()->showTreeForThis();
+
+ fprintf(stderr, "\n | List of resources:\n");
+ if (m_clipperFilterMaskerData) {
+ if (RenderSVGResourceClipper* clipper = m_clipperFilterMaskerData->clipper)
+ fprintf(stderr, " |-> Clipper : %p (node=%p)\n", clipper, clipper->node());
+#if ENABLE(FILTERS)
+ if (RenderSVGResourceFilter* filter = m_clipperFilterMaskerData->filter)
+ fprintf(stderr, " |-> Filter : %p (node=%p)\n", filter, filter->node());
+#endif
+ if (RenderSVGResourceMasker* masker = m_clipperFilterMaskerData->masker)
+ fprintf(stderr, " |-> Masker : %p (node=%p)\n", masker, masker->node());
+ }
+
+ if (m_markerData) {
+ if (RenderSVGResourceMarker* markerStart = m_markerData->markerStart)
+ fprintf(stderr, " |-> MarkerStart: %p (node=%p)\n", markerStart, markerStart->node());
+ if (RenderSVGResourceMarker* markerMid = m_markerData->markerMid)
+ fprintf(stderr, " |-> MarkerMid : %p (node=%p)\n", markerMid, markerMid->node());
+ if (RenderSVGResourceMarker* markerEnd = m_markerData->markerEnd)
+ fprintf(stderr, " |-> MarkerEnd : %p (node=%p)\n", markerEnd, markerEnd->node());
+ }
+
+ if (m_fillStrokeData) {
+ if (RenderSVGResourceContainer* fill = m_fillStrokeData->fill)
+ fprintf(stderr, " |-> Fill : %p (node=%p)\n", fill, fill->node());
+ if (RenderSVGResourceContainer* stroke = m_fillStrokeData->stroke)
+ fprintf(stderr, " |-> Stroke : %p (node=%p)\n", stroke, stroke->node());
+ }
+
+ if (m_linkedResource)
+ fprintf(stderr, " |-> xlink:href : %p (node=%p)\n", m_linkedResource, m_linkedResource->node());
+}
+#endif
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/svg/SVGResources.h b/Source/WebCore/rendering/svg/SVGResources.h
new file mode 100644
index 0000000..dd328b8
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGResources.h
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+#ifndef SVGResources_h
+#define SVGResources_h
+
+#if ENABLE(SVG)
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class Document;
+class RenderObject;
+class RenderSVGResourceClipper;
+class RenderSVGResourceContainer;
+class RenderSVGResourceFilter;
+class RenderSVGResourceMarker;
+class RenderSVGResourceMasker;
+class SVGRenderStyle;
+
+// Holds a set of resources associated with a RenderObject
+class SVGResources : public Noncopyable {
+public:
+ SVGResources();
+
+ bool buildCachedResources(const RenderObject*, const SVGRenderStyle*);
+
+ // Ordinary resources
+ RenderSVGResourceClipper* clipper() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->clipper : 0; }
+#if ENABLE(FILTERS)
+ RenderSVGResourceFilter* filter() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->filter : 0; }
+#endif
+ RenderSVGResourceMarker* markerStart() const { return m_markerData ? m_markerData->markerStart : 0; }
+ RenderSVGResourceMarker* markerMid() const { return m_markerData ? m_markerData->markerMid : 0; }
+ RenderSVGResourceMarker* markerEnd() const { return m_markerData ? m_markerData->markerEnd : 0; }
+ RenderSVGResourceMasker* masker() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->masker : 0; }
+
+ // Paint servers
+ RenderSVGResourceContainer* fill() const { return m_fillStrokeData ? m_fillStrokeData->fill : 0; }
+ RenderSVGResourceContainer* stroke() const { return m_fillStrokeData ? m_fillStrokeData->stroke : 0; }
+
+ // Chainable resources - linked through xlink:href
+ RenderSVGResourceContainer* linkedResource() const { return m_linkedResource; }
+
+ void buildSetOfResources(HashSet<RenderSVGResourceContainer*>&);
+
+ // Methods operating on all cached resources
+ void removeClientFromCache(RenderObject*, bool markForInvalidation = true) const;
+ void resourceDestroyed(RenderSVGResourceContainer*);
+
+#ifndef NDEBUG
+ void dump(const RenderObject*);
+#endif
+
+private:
+ friend class SVGResourcesCycleSolver;
+
+ // Only used by SVGResourcesCache cycle detection logic
+ void resetClipper();
+#if ENABLE(FILTERS)
+ void resetFilter();
+#endif
+ void resetMarkerStart();
+ void resetMarkerMid();
+ void resetMarkerEnd();
+ void resetMasker();
+ void resetFill();
+ void resetStroke();
+ void resetLinkedResource();
+
+private:
+ bool setClipper(RenderSVGResourceClipper*);
+#if ENABLE(FILTERS)
+ bool setFilter(RenderSVGResourceFilter*);
+#endif
+ bool setMarkerStart(RenderSVGResourceMarker*);
+ bool setMarkerMid(RenderSVGResourceMarker*);
+ bool setMarkerEnd(RenderSVGResourceMarker*);
+ bool setMasker(RenderSVGResourceMasker*);
+ bool setFill(RenderSVGResourceContainer*);
+ bool setStroke(RenderSVGResourceContainer*);
+ bool setLinkedResource(RenderSVGResourceContainer*);
+
+ // From SVG 1.1 2nd Edition
+ // clipper: 'container elements' and 'graphics elements'
+ // filter: 'container elements' and 'graphics elements'
+ // masker: 'container elements' and 'graphics elements'
+ // -> a, circle, defs, ellipse, glyph, g, image, line, marker, mask, missing-glyph, path, pattern, polygon, polyline, rect, svg, switch, symbol, text, use
+ struct ClipperFilterMaskerData {
+ ClipperFilterMaskerData()
+ : clipper(0)
+#if ENABLE(FILTERS)
+ , filter(0)
+#endif
+ , masker(0)
+ {
+ }
+
+ static PassOwnPtr<ClipperFilterMaskerData> create()
+ {
+ return new ClipperFilterMaskerData;
+ }
+
+ RenderSVGResourceClipper* clipper;
+#if ENABLE(FILTERS)
+ RenderSVGResourceFilter* filter;
+#endif
+ RenderSVGResourceMasker* masker;
+ };
+
+ // From SVG 1.1 2nd Edition
+ // marker: line, path, polygon, polyline
+ struct MarkerData {
+ MarkerData()
+ : markerStart(0)
+ , markerMid(0)
+ , markerEnd(0)
+ {
+ }
+
+ static PassOwnPtr<MarkerData> create()
+ {
+ return new MarkerData;
+ }
+
+ RenderSVGResourceMarker* markerStart;
+ RenderSVGResourceMarker* markerMid;
+ RenderSVGResourceMarker* markerEnd;
+ };
+
+ // From SVG 1.1 2nd Edition
+ // fill: 'shapes' and 'text content elements'
+ // stroke: 'shapes' and 'text content elements'
+ // -> altGlyph, circle, ellipse, line, path, polygon, polyline, rect, text, textPath, tref, tspan
+ struct FillStrokeData {
+ FillStrokeData()
+ : fill(0)
+ , stroke(0)
+ {
+ }
+
+ static PassOwnPtr<FillStrokeData> create()
+ {
+ return new FillStrokeData;
+ }
+
+ RenderSVGResourceContainer* fill;
+ RenderSVGResourceContainer* stroke;
+ };
+
+ OwnPtr<ClipperFilterMaskerData> m_clipperFilterMaskerData;
+ OwnPtr<MarkerData> m_markerData;
+ OwnPtr<FillStrokeData> m_fillStrokeData;
+ RenderSVGResourceContainer* m_linkedResource;
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/SVGResourcesCache.cpp b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp
new file mode 100644
index 0000000..886f76a
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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"
+#include "SVGResourcesCache.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGResourceContainer.h"
+#include "SVGDocumentExtensions.h"
+#include "SVGResources.h"
+#include "SVGResourcesCycleSolver.h"
+
+namespace WebCore {
+
+SVGResourcesCache::SVGResourcesCache()
+{
+}
+
+SVGResourcesCache::~SVGResourcesCache()
+{
+ deleteAllValues(m_cache);
+}
+
+void SVGResourcesCache::addResourcesFromRenderObject(RenderObject* object, const RenderStyle* style)
+{
+ ASSERT(object);
+ ASSERT(style);
+ ASSERT(!m_cache.contains(object));
+
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+ ASSERT(svgStyle);
+
+ // Build a list of all resources associated with the passed RenderObject
+ SVGResources* resources = new SVGResources;
+ if (!resources->buildCachedResources(object, svgStyle)) {
+ delete resources;
+ return;
+ }
+
+ // Put object in cache.
+ m_cache.set(object, resources);
+
+ // Run cycle-detection _afterwards_, so self-references can be caught as well.
+ SVGResourcesCycleSolver solver(object, resources);
+ solver.resolveCycles();
+
+ // Walk resources and register the render object at each resources.
+ HashSet<RenderSVGResourceContainer*> resourceSet;
+ resources->buildSetOfResources(resourceSet);
+
+ HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end();
+ for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it)
+ (*it)->addClient(object);
+}
+
+void SVGResourcesCache::removeResourcesFromRenderObject(RenderObject* object)
+{
+ if (!m_cache.contains(object))
+ return;
+
+ SVGResources* resources = m_cache.get(object);
+
+ // Walk resources and register the render object at each resources.
+ HashSet<RenderSVGResourceContainer*> resourceSet;
+ resources->buildSetOfResources(resourceSet);
+
+ HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end();
+ for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it)
+ (*it)->removeClient(object);
+
+ delete m_cache.take(object);
+}
+
+static inline SVGResourcesCache* resourcesCacheFromRenderObject(RenderObject* renderer)
+{
+ Document* document = renderer->document();
+ ASSERT(document);
+
+ SVGDocumentExtensions* extensions = document->accessSVGExtensions();
+ ASSERT(extensions);
+
+ SVGResourcesCache* cache = extensions->resourcesCache();
+ ASSERT(cache);
+
+ return cache;
+}
+
+SVGResources* SVGResourcesCache::cachedResourcesForRenderObject(RenderObject* renderer)
+{
+ ASSERT(renderer);
+ SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer);
+ if (!cache->m_cache.contains(renderer))
+ return 0;
+
+ return cache->m_cache.get(renderer);
+}
+
+void SVGResourcesCache::clientLayoutChanged(RenderObject* object)
+{
+ SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
+ if (!resources)
+ return;
+
+ resources->removeClientFromCache(object);
+}
+
+void SVGResourcesCache::clientStyleChanged(RenderObject* renderer, StyleDifference diff, const RenderStyle* newStyle)
+{
+ ASSERT(renderer);
+ if (diff == StyleDifferenceEqual)
+ return;
+
+ clientUpdatedFromElement(renderer, newStyle);
+ RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false);
+}
+
+void SVGResourcesCache::clientUpdatedFromElement(RenderObject* renderer, const RenderStyle* newStyle)
+{
+ ASSERT(renderer);
+ ASSERT(renderer->parent());
+
+ SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer);
+ cache->removeResourcesFromRenderObject(renderer);
+ cache->addResourcesFromRenderObject(renderer, newStyle);
+}
+
+void SVGResourcesCache::clientDestroyed(RenderObject* renderer)
+{
+ ASSERT(renderer);
+ SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer);
+ cache->removeResourcesFromRenderObject(renderer);
+}
+
+void SVGResourcesCache::resourceDestroyed(RenderSVGResourceContainer* resource)
+{
+ ASSERT(resource);
+ SVGResourcesCache* cache = resourcesCacheFromRenderObject(resource);
+
+ // The resource itself may have clients, that need to be notified.
+ cache->removeResourcesFromRenderObject(resource);
+
+ HashMap<RenderObject*, SVGResources*>::iterator end = cache->m_cache.end();
+ for (HashMap<RenderObject*, SVGResources*>::iterator it = cache->m_cache.begin(); it != end; ++it)
+ it->second->resourceDestroyed(resource);
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/svg/SVGResourcesCache.h b/Source/WebCore/rendering/svg/SVGResourcesCache.h
new file mode 100644
index 0000000..30eaeca
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGResourcesCache.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#ifndef SVGResourcesCache_h
+#define SVGResourcesCache_h
+
+#if ENABLE(SVG)
+#include "RenderStyleConstants.h"
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+class RenderObject;
+class RenderStyle;
+class RenderSVGResourceContainer;
+class SVGResources;
+
+class SVGResourcesCache : public Noncopyable {
+public:
+ SVGResourcesCache();
+ ~SVGResourcesCache();
+
+ void addResourcesFromRenderObject(RenderObject*, const RenderStyle*);
+ void removeResourcesFromRenderObject(RenderObject*);
+ static SVGResources* cachedResourcesForRenderObject(RenderObject*);
+
+ // Called from all SVG renderers destroy() methods - except for RenderSVGResourceContainer.
+ static void clientDestroyed(RenderObject*);
+
+ // Called from all SVG renderers layout() methods.
+ static void clientLayoutChanged(RenderObject*);
+
+ // Called from all SVG renderers styleDidChange() methods.
+ static void clientStyleChanged(RenderObject*, StyleDifference, const RenderStyle* newStyle);
+
+ // Called from all SVG renderers updateFromElement() methods.
+ static void clientUpdatedFromElement(RenderObject*, const RenderStyle* newStyle);
+
+ // Called from RenderSVGResourceContainer::destroy().
+ static void resourceDestroyed(RenderSVGResourceContainer*);
+
+private:
+ HashMap<RenderObject*, SVGResources*> m_cache;
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.cpp b/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.cpp
new file mode 100644
index 0000000..fa91e80
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.cpp
@@ -0,0 +1,213 @@
+/*
+ * 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"
+#include "SVGResourcesCycleSolver.h"
+
+// Set to a value > 0, to debug the resource cache.
+#define DEBUG_CYCLE_DETECTION 0
+
+#if ENABLE(SVG)
+#include "RenderSVGResourceClipper.h"
+#include "RenderSVGResourceFilter.h"
+#include "RenderSVGResourceMarker.h"
+#include "RenderSVGResourceMasker.h"
+#include "SVGFilterElement.h"
+#include "SVGGradientElement.h"
+#include "SVGPatternElement.h"
+#include "SVGResources.h"
+#include "SVGResourcesCache.h"
+
+namespace WebCore {
+
+SVGResourcesCycleSolver::SVGResourcesCycleSolver(RenderObject* renderer, SVGResources* resources)
+ : m_renderer(renderer)
+ , m_resources(resources)
+{
+ ASSERT(m_renderer);
+ ASSERT(m_resources);
+}
+
+SVGResourcesCycleSolver::~SVGResourcesCycleSolver()
+{
+}
+
+bool SVGResourcesCycleSolver::resourceContainsCycles(RenderObject* renderer) const
+{
+ ASSERT(renderer);
+
+ // First operate on the resources of the given renderer.
+ // <marker id="a"> <path marker-start="url(#b)"/> ...
+ // <marker id="b" marker-start="url(#a)"/>
+ if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer)) {
+ HashSet<RenderSVGResourceContainer*> resourceSet;
+ resources->buildSetOfResources(resourceSet);
+
+ // Walk all resources and check wheter they reference any resource contained in the resources set.
+ HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end();
+ for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it) {
+ if (m_allResources.contains(*it))
+ return true;
+ }
+ }
+
+ // Then operate on the child resources of the given renderer.
+ // <marker id="a"> <path marker-start="url(#b)"/> ...
+ // <marker id="b"> <path marker-start="url(#a)"/> ...
+ for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling()) {
+ SVGResources* childResources = SVGResourcesCache::cachedResourcesForRenderObject(child);
+ if (!childResources)
+ continue;
+
+ // A child of the given 'resource' contains resources.
+ HashSet<RenderSVGResourceContainer*> childSet;
+ childResources->buildSetOfResources(childSet);
+
+ // Walk all child resources and check wheter they reference any resource contained in the resources set.
+ HashSet<RenderSVGResourceContainer*>::iterator end = childSet.end();
+ for (HashSet<RenderSVGResourceContainer*>::iterator it = childSet.begin(); it != end; ++it) {
+ if (m_allResources.contains(*it))
+ return true;
+ }
+
+ // Walk children recursively, stop immediately if we found a cycle
+ if (resourceContainsCycles(child))
+ return true;
+ }
+
+ return false;
+}
+
+void SVGResourcesCycleSolver::resolveCycles()
+{
+ ASSERT(m_allResources.isEmpty());
+
+#if DEBUG_CYCLE_DETECTION > 0
+ fprintf(stderr, "\nBefore cycle detection:\n");
+ m_resources->dump(m_renderer);
+#endif
+
+ // Stash all resources into a HashSet for the ease of traversing.
+ HashSet<RenderSVGResourceContainer*> localResources;
+ m_resources->buildSetOfResources(localResources);
+ ASSERT(!localResources.isEmpty());
+
+ // Add all parent resource containers to the HashSet.
+ HashSet<RenderSVGResourceContainer*> parentResources;
+ RenderObject* parent = m_renderer->parent();
+ while (parent) {
+ if (parent->isSVGResourceContainer())
+ parentResources.add(parent->toRenderSVGResourceContainer());
+ parent = parent->parent();
+ }
+
+#if DEBUG_CYCLE_DETECTION > 0
+ fprintf(stderr, "\nDetecting wheter any resources references any of following objects:\n");
+ {
+ fprintf(stderr, "Local resources:\n");
+ HashSet<RenderSVGResourceContainer*>::iterator end = localResources.end();
+ for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it)
+ fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node());
+
+ fprintf(stderr, "Parent resources:\n");
+ end = parentResources.end();
+ for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it)
+ fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node());
+ }
+#endif
+
+ // Build combined set of local and parent resources.
+ m_allResources = localResources;
+ HashSet<RenderSVGResourceContainer*>::iterator end = parentResources.end();
+ for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it)
+ m_allResources.add(*it);
+
+ // If we're a resource, add ourselves to the HashSet.
+ if (m_renderer->isSVGResourceContainer())
+ m_allResources.add(m_renderer->toRenderSVGResourceContainer());
+
+ ASSERT(!m_allResources.isEmpty());
+
+ // The job of this function is to determine wheter any of the 'resources' associated with the given 'renderer'
+ // references us (or wheter any of its kids references us) -> that's a cycle, we need to find and break it.
+ end = localResources.end();
+ for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it) {
+ RenderSVGResourceContainer* resource = *it;
+ if (parentResources.contains(resource) || resourceContainsCycles(resource))
+ breakCycle(resource);
+ }
+
+#if DEBUG_CYCLE_DETECTION > 0
+ fprintf(stderr, "\nAfter cycle detection:\n");
+ m_resources->dump(m_renderer);
+#endif
+
+ m_allResources.clear();
+}
+
+void SVGResourcesCycleSolver::breakCycle(RenderSVGResourceContainer* resourceLeadingToCycle)
+{
+ ASSERT(resourceLeadingToCycle);
+ if (resourceLeadingToCycle == m_resources->linkedResource()) {
+ m_resources->resetLinkedResource();
+ return;
+ }
+
+ switch (resourceLeadingToCycle->resourceType()) {
+ case MaskerResourceType:
+ ASSERT(resourceLeadingToCycle == m_resources->masker());
+ m_resources->resetMasker();
+ break;
+ case MarkerResourceType:
+ ASSERT(resourceLeadingToCycle == m_resources->markerStart() || resourceLeadingToCycle == m_resources->markerMid() || resourceLeadingToCycle == m_resources->markerEnd());
+ if (m_resources->markerStart() == resourceLeadingToCycle)
+ m_resources->resetMarkerStart();
+ if (m_resources->markerMid() == resourceLeadingToCycle)
+ m_resources->resetMarkerMid();
+ if (m_resources->markerEnd() == resourceLeadingToCycle)
+ m_resources->resetMarkerEnd();
+ break;
+ case PatternResourceType:
+ case LinearGradientResourceType:
+ case RadialGradientResourceType:
+ ASSERT(resourceLeadingToCycle == m_resources->fill() || resourceLeadingToCycle == m_resources->stroke());
+ if (m_resources->fill() == resourceLeadingToCycle)
+ m_resources->resetFill();
+ if (m_resources->stroke() == resourceLeadingToCycle)
+ m_resources->resetStroke();
+ break;
+ case FilterResourceType:
+#if ENABLE(FILTERS)
+ ASSERT(resourceLeadingToCycle == m_resources->filter());
+ m_resources->resetFilter();
+#endif
+ break;
+ case ClipperResourceType:
+ ASSERT(resourceLeadingToCycle == m_resources->clipper());
+ m_resources->resetClipper();
+ break;
+ case SolidColorResourceType:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.h b/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.h
new file mode 100644
index 0000000..0653304
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#ifndef SVGResourcesCycleSolver_h
+#define SVGResourcesCycleSolver_h
+
+#if ENABLE(SVG)
+#include <wtf/HashSet.h>
+
+namespace WebCore {
+
+class RenderObject;
+class RenderSVGResourceContainer;
+class SVGResources;
+
+class SVGResourcesCycleSolver : public Noncopyable {
+public:
+ SVGResourcesCycleSolver(RenderObject*, SVGResources*);
+ ~SVGResourcesCycleSolver();
+
+ void resolveCycles();
+
+private:
+ bool resourceContainsCycles(RenderObject*) const;
+ void breakCycle(RenderSVGResourceContainer*);
+
+ RenderObject* m_renderer;
+ SVGResources* m_resources;
+ HashSet<RenderSVGResourceContainer*> m_allResources;
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp b/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp
index 49c76de..c2289d6 100644
--- a/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp
+++ b/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp
@@ -18,7 +18,6 @@
* 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"
diff --git a/Source/WebCore/rendering/svg/SVGRootInlineBox.h b/Source/WebCore/rendering/svg/SVGRootInlineBox.h
index 418c289..2e073c9 100644
--- a/Source/WebCore/rendering/svg/SVGRootInlineBox.h
+++ b/Source/WebCore/rendering/svg/SVGRootInlineBox.h
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
- * (C) 2006 Apple Computer Inc.
- * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2006 Apple Computer Inc.
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
@@ -18,7 +18,6 @@
* 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.
- *
*/
#ifndef SVGRootInlineBox_h
diff --git a/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp b/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp
new file mode 100644
index 0000000..2d84c48
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 "SVGShadowTreeElements.h"
+
+#include "Document.h"
+#include "FloatSize.h"
+#include "RenderObject.h"
+#include "SVGNames.h"
+#include "SVGUseElement.h"
+
+namespace WebCore {
+
+// SVGShadowTreeContainerElement
+
+SVGShadowTreeContainerElement::SVGShadowTreeContainerElement(Document* document)
+ : SVGGElement(SVGNames::gTag, document)
+{
+}
+
+PassRefPtr<SVGShadowTreeContainerElement> SVGShadowTreeContainerElement::create(Document* document)
+{
+ return adoptRef(new SVGShadowTreeContainerElement(document));
+}
+
+FloatSize SVGShadowTreeContainerElement::containerTranslation() const
+{
+ return FloatSize(m_xOffset.value(this), m_yOffset.value(this));
+}
+
+// SVGShadowTreeRootElement
+
+inline SVGShadowTreeRootElement::SVGShadowTreeRootElement(Document* document, SVGUseElement* shadowParent)
+ : SVGShadowTreeContainerElement(document)
+{
+ setShadowHost(shadowParent);
+ setInDocument();
+}
+
+PassRefPtr<SVGShadowTreeRootElement> SVGShadowTreeRootElement::create(Document* document, SVGUseElement* shadowParent)
+{
+ return adoptRef(new SVGShadowTreeRootElement(document, shadowParent));
+}
+
+void SVGShadowTreeRootElement::attachElement(PassRefPtr<RenderStyle> style, RenderArena* arena)
+{
+ ASSERT(shadowHost());
+
+ // Create the renderer with the specified style
+ RenderObject* renderer = createRenderer(arena, style.get());
+ if (renderer) {
+ setRenderer(renderer);
+ renderer->setStyle(style);
+ }
+
+ // Set these explicitly since this normally happens during an attach()
+ setAttached();
+
+ // Add the renderer to the render tree
+ if (renderer)
+ shadowHost()->renderer()->addChild(renderer);
+}
+
+void SVGShadowTreeRootElement::clearShadowHost()
+{
+ setShadowHost(0);
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/svg/SVGShadowTreeElements.h b/Source/WebCore/rendering/svg/SVGShadowTreeElements.h
new file mode 100644
index 0000000..3406f95
--- /dev/null
+++ b/Source/WebCore/rendering/svg/SVGShadowTreeElements.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#ifndef SVGShadowTreeElements_h
+#define SVGShadowTreeElements_h
+
+#if ENABLE(SVG)
+#include "SVGGElement.h"
+#include "SVGLength.h"
+
+namespace WebCore {
+
+class FloatSize;
+class SVGUseElement;
+
+class SVGShadowTreeContainerElement : public SVGGElement {
+public:
+ static PassRefPtr<SVGShadowTreeContainerElement> create(Document*);
+
+ FloatSize containerTranslation() const;
+ void setContainerOffset(const SVGLength& x, const SVGLength& y)
+ {
+ m_xOffset = x;
+ m_yOffset = y;
+ }
+
+protected:
+ SVGShadowTreeContainerElement(Document*);
+
+private:
+ virtual bool isShadowTreeContainerElement() const { return true; }
+
+ SVGLength m_xOffset;
+ SVGLength m_yOffset;
+};
+
+class SVGShadowTreeRootElement : public SVGShadowTreeContainerElement {
+public:
+ static PassRefPtr<SVGShadowTreeRootElement> create(Document*, SVGUseElement* shadowParent);
+
+ void attachElement(PassRefPtr<RenderStyle>, RenderArena*);
+ void clearShadowHost();
+
+private:
+ SVGShadowTreeRootElement(Document*, SVGUseElement* shadowParent);
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp
index 7060ac6..3863322 100644
--- a/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp
@@ -154,8 +154,7 @@ float SVGTextLayoutEngineBaseline::calculateGlyphOrientationAngle(bool isVertica
ASSERT(style);
switch (isVerticalText ? style->glyphOrientationVertical() : style->glyphOrientationHorizontal()) {
- case GO_AUTO:
- {
+ case GO_AUTO: {
// Spec: Fullwidth ideographic and fullwidth Latin text will be set with a glyph-orientation of 0-degrees.
// Text which is not fullwidth will be set with a glyph-orientation of 90-degrees.
unsigned int unicodeRange = findCharUnicodeRange(character);
diff --git a/Source/WebCore/rendering/svg/SVGTextQuery.cpp b/Source/WebCore/rendering/svg/SVGTextQuery.cpp
index fcc7924..42d511b 100644
--- a/Source/WebCore/rendering/svg/SVGTextQuery.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextQuery.cpp
@@ -1,21 +1,21 @@
/*
- 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.
-*/
+ * 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"
#include "SVGTextQuery.h"
diff --git a/Source/WebCore/rendering/svg/SVGTextQuery.h b/Source/WebCore/rendering/svg/SVGTextQuery.h
index 9a671f4..331dd94 100644
--- a/Source/WebCore/rendering/svg/SVGTextQuery.h
+++ b/Source/WebCore/rendering/svg/SVGTextQuery.h
@@ -1,21 +1,21 @@
/*
- 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.
-*/
+ * 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.
+ */
#ifndef SVGTextQuery_h
#define SVGTextQuery_h