A crash reproducible in Path::isEmpty() under RenderSVGShape::paint()
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Jan 2016 17:50:26 +0000 (17:50 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Jan 2016 17:50:26 +0000 (17:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=149613

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2016-01-21
Reviewed by Darin Adler.
Source/WebCore:

When RenderSVGRoot::layout() realizes its layout size has changed and
it has resources which have relative sizes, it marks all the clients of
the resources for invalidates regardless whether they belong to the
same RenderSVGRoot or not. But it reruns the layout only for its children.
If one of these clients comes before the current RenderSVGRoot in the render
tree, ee end up having renderer marked for invalidation at rendering time.
This also prevents scheduling the layout if the same renderer is marked
for another invalidation later. We prevent this because we do not want
to schedule another layout for a renderer which is already marked for
invalidation. This can cause crash if the renderer is an RenderSVGPath.

The fix is to mark "only" the clients of a resource which belong to the
same RenderSVGRoot of the resource. Also we need to run the layout for
all the resources which belong to different RenderSVGRoots before running
the layout for an SVG renderer.

Tests: svg/custom/filter-update-different-root.html
       svg/custom/pattern-update-different-root.html

* rendering/svg/RenderSVGResourceContainer.cpp:
(WebCore::RenderSVGResourceContainer::markAllClientsForInvalidation):
We should not mark any client outside the current root for invalidation

* rendering/svg/RenderSVGResourceContainer.h: Remove unneeded private keyword.

* rendering/svg/RenderSVGRoot.cpp:
(WebCore::RenderSVGRoot::addResourceForClientInvalidation):
Code clean up; use findTreeRootObject() instead of repeating the same code.

* rendering/svg/RenderSVGShape.cpp:
(WebCore::RenderSVGShape::isEmpty): Avoid crashing if RenderSVGShape::isEmpty()
is called before calling RenderSVGShape::layout().

* rendering/svg/RenderSVGText.cpp:
(WebCore::RenderSVGText::layout): findTreeRootObject() now returns a pointer.

* rendering/svg/SVGRenderSupport.cpp:
(WebCore::SVGRenderSupport::findTreeRootObject): I do think nothing
guarantees that an SVG renderer has to have an RenderSVGRoot in its
ancestors. So change this function to return a pointer. Also Provide
the non-const version of this function.

(WebCore::SVGRenderSupport::layoutDifferentRootIfNeeded): Runs the layout
if needed for all the resources which belong to different RenderSVGRoots.

(WebCore::SVGRenderSupport::layoutChildren): Make sure all the renderer's
resources which belong to different RenderSVGRoots are laid out before
running the layout for this renderer.

* rendering/svg/SVGRenderSupport.h: Remove a mysterious comment.

* rendering/svg/SVGResources.cpp:
(WebCore::SVGResources::layoutDifferentRootIfNeeded): Run the layout for
all the resources which belong to different RenderSVGRoots outside the
context of their RenderSVGRoots.

* rendering/svg/SVGResources.h:
(WebCore::SVGResources::clipper):
(WebCore::SVGResources::markerStart):
(WebCore::SVGResources::markerMid):
(WebCore::SVGResources::markerEnd):
(WebCore::SVGResources::masker):
(WebCore::SVGResources::filter):
(WebCore::SVGResources::fill):
(WebCore::SVGResources::stroke):
Code clean up; use nullptr instead of 0.

LayoutTests:

When running the layout of an SVG root and it has resources which are
referenced by clients in other SVG roots, make sure we run the layout
for these resources before running the layout for their clients.

* svg/custom/filter-update-different-root-expected.html: Added.
* svg/custom/filter-update-different-root.html: Added.
Without this patch this test crashes because we paint a dirty RenderSVGShape.

* svg/custom/pattern-update-different-root-expected.html: Added.
* svg/custom/pattern-update-different-root.html: Added.
Without this patch this test works fine but it is good to have it to catch
cases where the SVG root needs to run re-layout for its children resources
and hence their clients if its size has changed.

* svg/custom/unicode-in-tspan-multi-svg-crash-expected.txt:
* svg/custom/unicode-in-tspan-multi-svg-crash.html:
This test was ported from Blink in http://trac.webkit.org/changeset/166420.
The expectation of this test was changed in Blink:
https://src.chromium.org/viewvc/blink?revision=158480&view=revision.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@195411 268f45cc-cd09-0410-ab3c-d52691b4dbfc

17 files changed:
LayoutTests/ChangeLog
LayoutTests/svg/custom/filter-update-different-root-expected.html [new file with mode: 0644]
LayoutTests/svg/custom/filter-update-different-root.html [new file with mode: 0644]
LayoutTests/svg/custom/pattern-update-different-root-expected.html [new file with mode: 0644]
LayoutTests/svg/custom/pattern-update-different-root.html [new file with mode: 0644]
LayoutTests/svg/custom/unicode-in-tspan-multi-svg-crash-expected.txt
LayoutTests/svg/custom/unicode-in-tspan-multi-svg-crash.html
Source/WebCore/ChangeLog
Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp
Source/WebCore/rendering/svg/RenderSVGResourceContainer.h
Source/WebCore/rendering/svg/RenderSVGRoot.cpp
Source/WebCore/rendering/svg/RenderSVGShape.cpp
Source/WebCore/rendering/svg/RenderSVGText.cpp
Source/WebCore/rendering/svg/SVGRenderSupport.cpp
Source/WebCore/rendering/svg/SVGRenderSupport.h
Source/WebCore/rendering/svg/SVGResources.cpp
Source/WebCore/rendering/svg/SVGResources.h

index 4a81710..9bd2f44 100644 (file)
@@ -1,3 +1,31 @@
+2016-01-21  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        A crash reproducible in Path::isEmpty() under RenderSVGShape::paint()
+        https://bugs.webkit.org/show_bug.cgi?id=149613
+
+        Reviewed by Darin Adler.
+        
+        When running the layout of an SVG root and it has resources which are
+        referenced by clients in other SVG roots, make sure we run the layout
+        for these resources before running the layout for their clients.
+
+        * svg/custom/filter-update-different-root-expected.html: Added.
+        * svg/custom/filter-update-different-root.html: Added.
+        Without this patch this test crashes because we paint a dirty RenderSVGShape.
+        
+        * svg/custom/pattern-update-different-root-expected.html: Added.
+        * svg/custom/pattern-update-different-root.html: Added.
+        Without this patch this test works fine but it is good to have it to catch
+        cases where the SVG root needs to run re-layout for its children resources
+        and hence their clients if its size has changed.
+
+        * svg/custom/unicode-in-tspan-multi-svg-crash-expected.txt:
+        * svg/custom/unicode-in-tspan-multi-svg-crash.html:
+        This test was ported from Blink in http://trac.webkit.org/changeset/166420.
+        The expectation of this test was changed in Blink:
+        https://src.chromium.org/viewvc/blink?revision=158480&view=revision.
+        
+
 2016-01-21  Nan Wang  <n_wang@apple.com>
 
         AX: [IOS] Implement next/previous text marker functions using TextIterator
diff --git a/LayoutTests/svg/custom/filter-update-different-root-expected.html b/LayoutTests/svg/custom/filter-update-different-root-expected.html
new file mode 100644 (file)
index 0000000..2dddf82
--- /dev/null
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <svg>
+        <rect width="200" height="100" fill="green"/>
+    </svg>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/svg/custom/filter-update-different-root.html b/LayoutTests/svg/custom/filter-update-different-root.html
new file mode 100644 (file)
index 0000000..f05d130
--- /dev/null
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <style>
+    .dummy { }
+    .hide-second-path > .second-path { display: none; }
+  </style>
+</head>
+<body>
+    <svg style="background-color: #fff">
+        <g id="parent-group" class="hide-second-path">
+            <path id="id1" d="m 0,0 H 100 V 100 H 0 z" fill="red"/>
+            <path id="id2" d="m 0,0 H 100 V 100 H 0 z" fill="green" class="second-path"/>
+            <g id="child-group" filter="url(#nop-filter)">
+                <path id="id3" d="m 100,0 H 200 V 100 H 100 z" fill="green"/>
+                <path id="id4" d="m 100,0 H 200 V 100 H 100 z" fill="red" class="second-path"/>
+            </g>
+        </g>
+    </svg>
+    <svg>
+        <filter id="nop-filter">
+            <feOffset dx="0" dy="0"/>
+        </filter>
+    </svg>
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+        setTimeout(function() {
+            document.styleSheets[0].deleteRule(0);
+            setTimeout(function() {
+                document.getElementById('parent-group').removeAttribute('class');
+                document.getElementById('child-group').setAttribute('class', 'hide-second-path');
+                if (window.testRunner)
+                    testRunner.notifyDone();
+              }, 50);
+          }, 50);
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/svg/custom/pattern-update-different-root-expected.html b/LayoutTests/svg/custom/pattern-update-different-root-expected.html
new file mode 100644 (file)
index 0000000..5c7362c
--- /dev/null
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    svg {
+        width: 100px;
+        height: 100px;
+    }
+</style>
+</head>
+<body>
+    <svg>
+        <rect width="100%" height="100%" fill="green"/>
+    </svg>
+</body>
+</html>
diff --git a/LayoutTests/svg/custom/pattern-update-different-root.html b/LayoutTests/svg/custom/pattern-update-different-root.html
new file mode 100644 (file)
index 0000000..ac5a32a
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    svg {
+        width: 100px;
+        height: 100px;
+    }
+</style>
+</head>
+<body>
+    <svg>
+        <pattern id="r1" width="100%" height="100%" xlink:href="#r2" patternUnits="userSpaceOnUse"/>
+        <rect width="100%" height="100%" fill="url(#r1)"/>
+    </svg>
+    <svg>
+        <pattern id="r2">
+            <rect width="100%" height="100%" fill="green"/>
+        </pattern>
+    </svg>
+</body>
+</html>
index 3d04a18..f1432d0 100644 (file)
@@ -1,2 +1,3 @@
+
  
-Test Passes if there is no crash in Debug or Asan builds. There should be no characters preceding "Test".
+Test Passes if there is no crash in Debug or Asan builds.
index 19b4301..2d1246d 100644 (file)
@@ -33,6 +33,6 @@
       <filter id="filterInSecondRoot"/>
     </svg>
 
-    <p>Test Passes if there is no crash in Debug or Asan builds. There should be no characters preceding "Test".</p>
+    <p>Test Passes if there is no crash in Debug or Asan builds.</p>
   </body>
 </html>
index d313c37..c22c770 100644 (file)
@@ -1,3 +1,77 @@
+2016-01-21  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        A crash reproducible in Path::isEmpty() under RenderSVGShape::paint()
+        https://bugs.webkit.org/show_bug.cgi?id=149613
+
+        Reviewed by Darin Adler.
+
+        When RenderSVGRoot::layout() realizes its layout size has changed and
+        it has resources which have relative sizes, it marks all the clients of
+        the resources for invalidates regardless whether they belong to the
+        same RenderSVGRoot or not. But it reruns the layout only for its children.
+        If one of these clients comes before the current RenderSVGRoot in the render
+        tree, ee end up having renderer marked for invalidation at rendering time.
+        This also prevents scheduling the layout if the same renderer is marked
+        for another invalidation later. We prevent this because we do not want
+        to schedule another layout for a renderer which is already marked for
+        invalidation. This can cause crash if the renderer is an RenderSVGPath.
+        
+        The fix is to mark "only" the clients of a resource which belong to the
+        same RenderSVGRoot of the resource. Also we need to run the layout for
+        all the resources which belong to different RenderSVGRoots before running
+        the layout for an SVG renderer.
+         
+        Tests: svg/custom/filter-update-different-root.html
+               svg/custom/pattern-update-different-root.html
+
+        * rendering/svg/RenderSVGResourceContainer.cpp:
+        (WebCore::RenderSVGResourceContainer::markAllClientsForInvalidation):
+        We should not mark any client outside the current root for invalidation
+        
+        * rendering/svg/RenderSVGResourceContainer.h: Remove unneeded private keyword.
+        
+        * rendering/svg/RenderSVGRoot.cpp:
+        (WebCore::RenderSVGRoot::addResourceForClientInvalidation):
+        Code clean up; use findTreeRootObject() instead of repeating the same code.
+        
+        * rendering/svg/RenderSVGShape.cpp:
+        (WebCore::RenderSVGShape::isEmpty): Avoid crashing if RenderSVGShape::isEmpty()
+        is called before calling RenderSVGShape::layout().
+         
+        * rendering/svg/RenderSVGText.cpp:
+        (WebCore::RenderSVGText::layout): findTreeRootObject() now returns a pointer.
+        
+        * rendering/svg/SVGRenderSupport.cpp:
+        (WebCore::SVGRenderSupport::findTreeRootObject): I do think nothing 
+        guarantees that an SVG renderer has to have an RenderSVGRoot in its
+        ancestors. So change this function to return a pointer. Also Provide
+        the non-const version of this function.
+         
+        (WebCore::SVGRenderSupport::layoutDifferentRootIfNeeded): Runs the layout
+        if needed for all the resources which belong to different RenderSVGRoots.
+        
+        (WebCore::SVGRenderSupport::layoutChildren): Make sure all the renderer's
+        resources which belong to different RenderSVGRoots are laid out before
+        running the layout for this renderer.
+        
+        * rendering/svg/SVGRenderSupport.h: Remove a mysterious comment.
+        
+        * rendering/svg/SVGResources.cpp:
+        (WebCore::SVGResources::layoutDifferentRootIfNeeded): Run the layout for
+        all the resources which belong to different RenderSVGRoots outside the
+        context of their RenderSVGRoots.
+        
+        * rendering/svg/SVGResources.h:
+        (WebCore::SVGResources::clipper):
+        (WebCore::SVGResources::markerStart):
+        (WebCore::SVGResources::markerMid):
+        (WebCore::SVGResources::markerEnd):
+        (WebCore::SVGResources::masker):
+        (WebCore::SVGResources::filter):
+        (WebCore::SVGResources::fill):
+        (WebCore::SVGResources::stroke):
+        Code clean up; use nullptr instead of 0.
+
 2016-01-21  Jer Noble  <jer.noble@apple.com>
 
         [EME] Correctly report errors when generating key requests from AVContentKeySession.
index bd5efbf..5e52008 100644 (file)
@@ -94,8 +94,13 @@ void RenderSVGResourceContainer::markAllClientsForInvalidation(InvalidationMode
     m_isInvalidating = true;
     bool needsLayout = mode == LayoutAndBoundariesInvalidation;
     bool markForInvalidation = mode != ParentOnlyInvalidation;
+    auto* root = SVGRenderSupport::findTreeRootObject(*this);
 
     for (auto* client : m_clients) {
+        // We should not mark any client outside the current root for invalidation
+        if (root != SVGRenderSupport::findTreeRootObject(*client))
+            continue;
+
         if (is<RenderSVGResourceContainer>(*client)) {
             downcast<RenderSVGResourceContainer>(*client).removeAllClientsFromCache(markForInvalidation);
             continue;
index a03706e..6b07839 100644 (file)
@@ -66,7 +66,6 @@ private:
     void addClient(RenderElement&);
     void removeClient(RenderElement&);
 
-private:
     virtual void willBeDestroyed() override final;
     void registerResource();
 
index 96a642d..19fc21b 100644 (file)
@@ -455,12 +455,10 @@ bool RenderSVGRoot::hasRelativeDimensions() const
 
 void RenderSVGRoot::addResourceForClientInvalidation(RenderSVGResourceContainer* resource)
 {
-    RenderElement* svgRoot = resource->parent();
-    while (svgRoot && !is<RenderSVGRoot>(*svgRoot))
-        svgRoot = svgRoot->parent();
+    RenderSVGRoot* svgRoot = SVGRenderSupport::findTreeRootObject(*resource);
     if (!svgRoot)
         return;
-    downcast<RenderSVGRoot>(*svgRoot).m_resourcesNeedingToInvalidateClients.add(resource);
+    svgRoot->m_resourcesNeedingToInvalidateClients.add(resource);
 }
 
 }
index 8a1ff5e..9de1913 100644 (file)
@@ -89,7 +89,11 @@ void RenderSVGShape::updateShapeFromElement()
 
 bool RenderSVGShape::isEmpty() const
 {
-    return path().isEmpty();
+    // This function should never be called before assigning a new Path to m_path.
+    // But this bug can happen if this renderer was created and its layout was not
+    // done before painting. Assert this did not happen but do not crash.
+    ASSERT(hasPath());
+    return !hasPath() || path().isEmpty();
 }
 
 void RenderSVGShape::fillShape(GraphicsContext& context) const
index 24bce95..86063ac 100644 (file)
@@ -369,7 +369,7 @@ void RenderSVGText::layout()
         m_needsReordering = true;
         m_needsPositioningValuesUpdate = false;
         updateCachedBoundariesInParents = true;
-    } else if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(*this).isLayoutSizeChanged()) {
+    } else if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(*this)->isLayoutSizeChanged()) {
         // If the root layout size changed (eg. window size changes) or the transform to the root
         // context has changed then recompute the on-screen font size.
         updateFontInAllDescendants(this, &m_layoutAttributesBuilder);
index 44abb64..7f72216 100644 (file)
@@ -184,9 +184,14 @@ bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepa
     return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect);
 }
 
-const RenderSVGRoot& SVGRenderSupport::findTreeRootObject(const RenderElement& start)
+RenderSVGRoot* SVGRenderSupport::findTreeRootObject(RenderElement& start)
 {
-    return *lineageOfType<RenderSVGRoot>(start).first();
+    return lineageOfType<RenderSVGRoot>(start).first();
+}
+
+const RenderSVGRoot* SVGRenderSupport::findTreeRootObject(const RenderElement& start)
+{
+    return lineageOfType<RenderSVGRoot>(start).first();
 }
 
 static inline void invalidateResourcesOfChildren(RenderElement& renderer)
@@ -225,6 +230,15 @@ bool SVGRenderSupport::transformToRootChanged(RenderElement* ancestor)
     return false;
 }
 
+void SVGRenderSupport::layoutDifferentRootIfNeeded(const RenderElement& renderer)
+{
+    if (auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer)) {
+        auto* svgRoot = SVGRenderSupport::findTreeRootObject(renderer);
+        ASSERT(svgRoot);
+        resources->layoutDifferentRootIfNeeded(svgRoot);
+    }
+}
+
 void SVGRenderSupport::layoutChildren(RenderElement& start, bool selfNeedsLayout)
 {
     bool layoutSizeChanged = layoutSizeOfNearestViewportChanged(start);
@@ -273,6 +287,7 @@ void SVGRenderSupport::layoutChildren(RenderElement& start, bool selfNeedsLayout
             child->setNeedsLayout(MarkOnlyThis);
 
         if (child->needsLayout()) {
+            layoutDifferentRootIfNeeded(downcast<RenderElement>(*child));
             downcast<RenderElement>(*child).layout();
             // Renderers are responsible for repainting themselves when changing, except
             // for the initial paint to avoid potential double-painting caused by non-sensical "old" bounds.
index 1dc1e77..055c459 100644 (file)
@@ -44,6 +44,8 @@ class TransformState;
 // SVGRendererSupport is a helper class sharing code between all SVG renderers.
 class SVGRenderSupport {
 public:
+    static void layoutDifferentRootIfNeeded(const RenderElement&);
+
     // Shares child layouting code between RenderSVGRoot/RenderSVG(Hidden)Container
     static void layoutChildren(RenderElement&, bool selfNeedsLayout);
 
@@ -91,8 +93,8 @@ public:
     static void updateMaskedAncestorShouldIsolateBlending(const RenderElement&);
 #endif
 
-    // FIXME: These methods do not belong here.
-    static const RenderSVGRoot& findTreeRootObject(const RenderElement&);
+    static RenderSVGRoot* findTreeRootObject(RenderElement&);
+    static const RenderSVGRoot* findTreeRootObject(const RenderElement&);
 
 private:
     // This class is not constructable.
index 2e1f2ab..0aaa1ad 100644 (file)
@@ -25,6 +25,7 @@
 #include "RenderSVGResourceFilter.h"
 #include "RenderSVGResourceMarker.h"
 #include "RenderSVGResourceMasker.h"
+#include "RenderSVGRoot.h"
 #include "SVGGradientElement.h"
 #include "SVGNames.h"
 #include "SVGPaint.h"
@@ -283,6 +284,27 @@ bool SVGResources::buildCachedResources(const RenderElement& renderer, const Ren
     return foundResources;
 }
 
+void SVGResources::layoutDifferentRootIfNeeded(const RenderSVGRoot* svgRoot)
+{
+    if (clipper() && svgRoot != SVGRenderSupport::findTreeRootObject(*clipper()))
+        clipper()->layoutIfNeeded();
+
+    if (masker() && svgRoot != SVGRenderSupport::findTreeRootObject(*masker()))
+        masker()->layoutIfNeeded();
+
+    if (filter() && svgRoot != SVGRenderSupport::findTreeRootObject(*filter()))
+        filter()->layoutIfNeeded();
+
+    if (markerStart() && svgRoot != SVGRenderSupport::findTreeRootObject(*markerStart()))
+        markerStart()->layoutIfNeeded();
+
+    if (markerMid() && svgRoot != SVGRenderSupport::findTreeRootObject(*markerMid()))
+        markerMid()->layoutIfNeeded();
+
+    if (markerEnd() && svgRoot != SVGRenderSupport::findTreeRootObject(*markerEnd()))
+        markerEnd()->layoutIfNeeded();
+}
+
 void SVGResources::removeClientFromCache(RenderElement& renderer, bool markForInvalidation) const
 {
     if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
index 27312c7..d41f859 100644 (file)
@@ -35,6 +35,7 @@ class RenderSVGResourceContainer;
 class RenderSVGResourceFilter;
 class RenderSVGResourceMarker;
 class RenderSVGResourceMasker;
+class RenderSVGRoot;
 class SVGRenderStyle;
 
 // Holds a set of resources associated with a RenderObject
@@ -44,24 +45,19 @@ public:
     SVGResources();
 
     bool buildCachedResources(const RenderElement&, const RenderStyle&);
+    void layoutDifferentRootIfNeeded(const RenderSVGRoot*);
 
     // Ordinary resources
-    RenderSVGResourceClipper* clipper() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->clipper : 0; }
-    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; }
-
-    RenderSVGResourceFilter* filter() const
-    {
-        if (m_clipperFilterMaskerData)
-            return m_clipperFilterMaskerData->filter;
-        return 0;
-    }
+    RenderSVGResourceClipper* clipper() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->clipper : nullptr; }
+    RenderSVGResourceMarker* markerStart() const { return m_markerData ? m_markerData->markerStart : nullptr; }
+    RenderSVGResourceMarker* markerMid() const { return m_markerData ? m_markerData->markerMid : nullptr; }
+    RenderSVGResourceMarker* markerEnd() const { return m_markerData ? m_markerData->markerEnd : nullptr; }
+    RenderSVGResourceMasker* masker() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->masker : nullptr; }
+    RenderSVGResourceFilter* filter() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->filter : nullptr; }
 
     // Paint servers
-    RenderSVGResourceContainer* fill() const { return m_fillStrokeData ? m_fillStrokeData->fill : 0; }
-    RenderSVGResourceContainer* stroke() const { return m_fillStrokeData ? m_fillStrokeData->stroke : 0; }
+    RenderSVGResourceContainer* fill() const { return m_fillStrokeData ? m_fillStrokeData->fill : nullptr; }
+    RenderSVGResourceContainer* stroke() const { return m_fillStrokeData ? m_fillStrokeData->stroke : nullptr; }
 
     // Chainable resources - linked through xlink:href
     RenderSVGResourceContainer* linkedResource() const { return m_linkedResource; }