crash in WebCore::RenderSVGContainer::paint
authorzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 26 Jan 2012 09:50:47 +0000 (09:50 +0000)
committerzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 26 Jan 2012 09:50:47 +0000 (09:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=69714

Reviewed by Dirk Schulze.

Source/WebCore:

When RenderSVGResourceClipper draws its children to a mask, it requires some special constraints:
- fill-opacity/stroke-opacity/opacity forced to 1
- masker/filter resources shouldn't be applied to the children
- fill must be set to the initial fill paint server for all children (solid black)
- stroke must be set to the initial stroke paint server for all children (none)

This was achieved before by mutating the style of the children, which made them need a relayout.
SVGImageBufferTools:renderSubtreeToImageBuffer thus needed to layout the children, if needed, before painting.

This can be completly avoided, when changing RenderSVGResourceClipper to avoid style mutations.
Introduce a new "PaintBehaviorRenderingSVGMask", and set the current FrameViews paintBehaviour to this
state, before painting the subtree. This way we can detect that we're rendering a clip mask, without
having to mutate the style of the children and without having to relayout.

We can now ASSERT(!item->needsLayout()) in renderSubtreeToImageBuffer.

Tests: svg/clip-path/clip-path-tspan-and-stroke.svg
       svg/custom/layout-loop.svg

* rendering/PaintPhase.h:
* rendering/svg/RenderSVGResource.cpp:
(WebCore::requestPaintingResource):
* rendering/svg/RenderSVGResourceClipper.cpp:
(WebCore::RenderSVGResourceClipper::RenderSVGResourceClipper):
(WebCore::RenderSVGResourceClipper::removeAllClientsFromCache):
(WebCore::RenderSVGResourceClipper::removeClientFromCache):
(WebCore::RenderSVGResourceClipper::applyClippingToContext):
(WebCore::RenderSVGResourceClipper::drawContentIntoMaskImage):
* rendering/svg/RenderSVGResourceClipper.h:
* rendering/svg/RenderSVGResourceMasker.cpp:
(WebCore::RenderSVGResourceMasker::applyResource):
(WebCore::RenderSVGResourceMasker::drawContentIntoMaskImage):
* rendering/svg/RenderSVGResourceMasker.h:
* rendering/svg/RenderSVGResourcePattern.cpp:
(WebCore::RenderSVGResourcePattern::createTileImage):
* rendering/svg/RenderSVGResourceSolidColor.cpp:
(WebCore::RenderSVGResourceSolidColor::applyResource):
* rendering/svg/SVGImageBufferTools.cpp:
(WebCore::SVGImageBufferTools::renderSubtreeToImageBuffer):
* rendering/svg/SVGInlineTextBox.cpp:
(WebCore::SVGInlineTextBox::paintSelectionBackground):
(WebCore::SVGInlineTextBox::paint):
* rendering/svg/SVGRenderSupport.cpp:
(WebCore::SVGRenderSupport::prepareToRenderSVGContent):

LayoutTests:

Added a new test covering the clipper specific demands when rendering its children to a mask.
(fill/stroke-opacity=1, opacity=1, don't apply masker/filter to children)

All cases are covered by existing tests, I'm adding a new combination of <tspan> within a <text>,
that tries to apply a stroke paint server, which is supposed to be ignored.

* platform/chromium/test_expectations.txt:
* platform/mac/svg/clip-path/clip-path-tspan-and-stroke-expected.png: Added.
* platform/mac/svg/clip-path/clip-path-tspan-and-stroke-expected.txt: Added.
* svg/clip-path/clip-path-tspan-and-stroke.svg: Added.
* svg/custom/layout-loop-expected.txt: Added.
* svg/custom/layout-loop.svg: Added.

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

19 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/chromium/test_expectations.txt
LayoutTests/platform/mac/svg/clip-path/clip-path-tspan-and-stroke-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/svg/clip-path/clip-path-tspan-and-stroke-expected.txt [new file with mode: 0644]
LayoutTests/svg/clip-path/clip-path-tspan-and-stroke.svg [new file with mode: 0644]
LayoutTests/svg/custom/layout-loop-expected.txt [new file with mode: 0644]
LayoutTests/svg/custom/layout-loop.svg [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/PaintPhase.h
Source/WebCore/rendering/svg/RenderSVGResource.cpp
Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp
Source/WebCore/rendering/svg/RenderSVGResourceClipper.h
Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp
Source/WebCore/rendering/svg/RenderSVGResourceMasker.h
Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp
Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp
Source/WebCore/rendering/svg/SVGImageBufferTools.cpp
Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
Source/WebCore/rendering/svg/SVGRenderSupport.cpp

index 0c46414..c30a3cf 100644 (file)
@@ -1,5 +1,25 @@
 2012-01-26  Nikolas Zimmermann  <nzimmermann@rim.com>
 
+        crash in WebCore::RenderSVGContainer::paint
+        https://bugs.webkit.org/show_bug.cgi?id=69714
+
+        Reviewed by Dirk Schulze.
+
+        Added a new test covering the clipper specific demands when rendering its children to a mask.
+        (fill/stroke-opacity=1, opacity=1, don't apply masker/filter to children)
+
+        All cases are covered by existing tests, I'm adding a new combination of <tspan> within a <text>,
+        that tries to apply a stroke paint server, which is supposed to be ignored.
+
+        * platform/chromium/test_expectations.txt:
+        * platform/mac/svg/clip-path/clip-path-tspan-and-stroke-expected.png: Added.
+        * platform/mac/svg/clip-path/clip-path-tspan-and-stroke-expected.txt: Added.
+        * svg/clip-path/clip-path-tspan-and-stroke.svg: Added.
+        * svg/custom/layout-loop-expected.txt: Added.
+        * svg/custom/layout-loop.svg: Added.
+
+2012-01-26  Nikolas Zimmermann  <nzimmermann@rim.com>
+
         Not reviewed. Regenerated some new SVG results using a Lion machine, to make the baseline pass with --tolerance 0 -p on a vanilla iMac again.
 
         * platform/mac/svg/W3C-SVG-1.1-SE/painting-control-04-f-expected.png:
index 0123de6..ca050af 100644 (file)
@@ -3918,6 +3918,9 @@ BUGWK76800 : svg/W3C-SVG-1.1/filters-composite-02-b.svg = IMAGE
 BUGWK76800 : svg/filters/feImage-reference-invalidation.svg = IMAGE
 BUGWK76800 : svg/filters/feImage-reference-svg-primitive.svg = IMAGE
 
+// Just needs a rebaseline.
+BUGWK69714 : svg/clip-path/clip-path-tspan-and-stroke.svg = IMAGE+TEXT
+
 // Change error (misspelling) underlines from Windows look to Mac look.
 BUG_CARYCLARK MAC : editing/deleting/delete-3928305-fix.html = IMAGE
 BUG_CARYCLARK MAC : editing/deleting/delete-3959464-fix.html = IMAGE
diff --git a/LayoutTests/platform/mac/svg/clip-path/clip-path-tspan-and-stroke-expected.png b/LayoutTests/platform/mac/svg/clip-path/clip-path-tspan-and-stroke-expected.png
new file mode 100644 (file)
index 0000000..a97bdb1
Binary files /dev/null and b/LayoutTests/platform/mac/svg/clip-path/clip-path-tspan-and-stroke-expected.png differ
diff --git a/LayoutTests/platform/mac/svg/clip-path/clip-path-tspan-and-stroke-expected.txt b/LayoutTests/platform/mac/svg/clip-path/clip-path-tspan-and-stroke-expected.txt
new file mode 100644 (file)
index 0000000..d0c3caf
--- /dev/null
@@ -0,0 +1,12 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderSVGRoot {svg} at (40,88) size 191x92
+    RenderSVGHiddenContainer {defs} at (0,0) size 0x0
+      RenderSVGResourceClipper {clipPath} [id="clip"] [clipPathUnits=userSpaceOnUse]
+        RenderSVGText {text} at (40,88) size 191x92 contains 1 chunk(s)
+          RenderSVGTSpan {tspan} at (0,0) size 191x92
+            RenderSVGInlineText {#text} at (0,0) size 191x92
+              chunk 1 text run 1 at (40.00,160.00) startOffset 0 endOffset 4 width 191.00: "CLIP"
+    RenderSVGRect {rect} at (40,88) size 191x92 [fill={[type=SOLID] [color=#008000]}] [x=40.00] [y=40.00] [width=300.00] [height=300.00]
+      [clipPath="clip"] RenderSVGResourceClipper {clipPath} at (40,88) size 191x92
diff --git a/LayoutTests/svg/clip-path/clip-path-tspan-and-stroke.svg b/LayoutTests/svg/clip-path/clip-path-tspan-and-stroke.svg
new file mode 100644 (file)
index 0000000..beb9c02
--- /dev/null
@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<defs>
+    <clipPath id="clip">
+        <!-- fill and stroke properties should be ignored -->
+        <text x="40" y="160" font-size="80" font-weight="bold"><tspan stroke="red" fill="none">CLIP</tspan></text>
+    </clipPath>
+</defs>
+<rect x="40" y="40" height="300" width="300" style="fill:green;clip-path:url(#clip);"/>
+</svg>
diff --git a/LayoutTests/svg/custom/layout-loop-expected.txt b/LayoutTests/svg/custom/layout-loop-expected.txt
new file mode 100644 (file)
index 0000000..8562f41
--- /dev/null
@@ -0,0 +1,2 @@
+CONSOLE MESSAGE: line 15: Error: Problem parsing d="M147.231,26.23c70.188,0,127.086,57.77,127.086,129.032c0"
+PASS, if it doesn't crash.
diff --git a/LayoutTests/svg/custom/layout-loop.svg b/LayoutTests/svg/custom/layout-loop.svg
new file mode 100644 (file)
index 0000000..712c4d2
--- /dev/null
@@ -0,0 +1,53 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+<g>
+    <linearGradient>
+        <stop id="stop"/>
+    </linearGradient>
+</g>
+<g>
+    <defs>
+        <filter id="filter"/>
+    </defs>
+
+    <mask id="mask">
+        <g filter="url(#filter)">
+            <linearGradient id="gradient"/>
+            <path fill="url(#gradient)" d="M147.231,26.23c70.188,0,127.086,57.77,127.086,129.032c0"/>
+        </g>
+    </mask>
+
+    <path mask="url(#mask)" d="M147.231,26.23c70.188,0,127.086,57.77,127.086,129.032"/>
+</g>
+
+<text>PASS, if it doesn't crash.</text>
+<script><![CDATA[
+if (window.layoutTestController)
+    layoutTestController.dumpAsText();
+document.execCommand("SelectAll");
+range = document.createRange();
+range.setStartBefore(document.getElementById("stop"));
+range.insertNode(document.getElementById("mask"));
+
+/* What does this do? It moves the whole <mask> element as child of the <linearGradient>.
+The final DOM looks like:
+
+<g>
+    <linearGradient>
+        <mask id="mask">
+            <g filter="url(#filter)">
+                <linearGradient id="gradient"/>
+                <path fill="url(#gradient)" d="..."/>
+            </g>
+        </mask>
+        <stop id="stop"/>
+    </linearGradient>
+</g>
+<g>
+    <defs>
+        <filter id="filter"/>
+    </defs>
+    <path mask="url(#mask)" d="...."/>
+</g>
+*/
+]]></script>
+</svg>
index 6132fc2..7842646 100644 (file)
@@ -1,5 +1,57 @@
 2012-01-26  Nikolas Zimmermann  <nzimmermann@rim.com>
 
+        crash in WebCore::RenderSVGContainer::paint
+        https://bugs.webkit.org/show_bug.cgi?id=69714
+
+        Reviewed by Dirk Schulze.
+
+        When RenderSVGResourceClipper draws its children to a mask, it requires some special constraints:
+        - fill-opacity/stroke-opacity/opacity forced to 1
+        - masker/filter resources shouldn't be applied to the children
+        - fill must be set to the initial fill paint server for all children (solid black)
+        - stroke must be set to the initial stroke paint server for all children (none)
+
+        This was achieved before by mutating the style of the children, which made them need a relayout.
+        SVGImageBufferTools:renderSubtreeToImageBuffer thus needed to layout the children, if needed, before painting.
+
+        This can be completly avoided, when changing RenderSVGResourceClipper to avoid style mutations.
+        Introduce a new "PaintBehaviorRenderingSVGMask", and set the current FrameViews paintBehaviour to this
+        state, before painting the subtree. This way we can detect that we're rendering a clip mask, without
+        having to mutate the style of the children and without having to relayout.
+
+        We can now ASSERT(!item->needsLayout()) in renderSubtreeToImageBuffer.
+
+        Tests: svg/clip-path/clip-path-tspan-and-stroke.svg
+               svg/custom/layout-loop.svg
+
+        * rendering/PaintPhase.h:
+        * rendering/svg/RenderSVGResource.cpp:
+        (WebCore::requestPaintingResource):
+        * rendering/svg/RenderSVGResourceClipper.cpp:
+        (WebCore::RenderSVGResourceClipper::RenderSVGResourceClipper):
+        (WebCore::RenderSVGResourceClipper::removeAllClientsFromCache):
+        (WebCore::RenderSVGResourceClipper::removeClientFromCache):
+        (WebCore::RenderSVGResourceClipper::applyClippingToContext):
+        (WebCore::RenderSVGResourceClipper::drawContentIntoMaskImage):
+        * rendering/svg/RenderSVGResourceClipper.h:
+        * rendering/svg/RenderSVGResourceMasker.cpp:
+        (WebCore::RenderSVGResourceMasker::applyResource):
+        (WebCore::RenderSVGResourceMasker::drawContentIntoMaskImage):
+        * rendering/svg/RenderSVGResourceMasker.h:
+        * rendering/svg/RenderSVGResourcePattern.cpp:
+        (WebCore::RenderSVGResourcePattern::createTileImage):
+        * rendering/svg/RenderSVGResourceSolidColor.cpp:
+        (WebCore::RenderSVGResourceSolidColor::applyResource):
+        * rendering/svg/SVGImageBufferTools.cpp:
+        (WebCore::SVGImageBufferTools::renderSubtreeToImageBuffer):
+        * rendering/svg/SVGInlineTextBox.cpp:
+        (WebCore::SVGInlineTextBox::paintSelectionBackground):
+        (WebCore::SVGInlineTextBox::paint):
+        * rendering/svg/SVGRenderSupport.cpp:
+        (WebCore::SVGRenderSupport::prepareToRenderSVGContent):
+
+2012-01-26  Nikolas Zimmermann  <nzimmermann@rim.com>
+
         Not reviewed. Try to fix Gtk build - JSShadowRoot.cpp can't be found, fix by looking for it in the derived sources.
 
         * GNUmakefile.list.am:
index 396131f..be4c61b 100644 (file)
@@ -56,7 +56,8 @@ enum PaintBehaviorFlags {
     PaintBehaviorNormal = 0,
     PaintBehaviorSelectionOnly = 1 << 0,
     PaintBehaviorForceBlackText = 1 << 1,
-    PaintBehaviorFlattenCompositingLayers = 1 << 2
+    PaintBehaviorFlattenCompositingLayers = 1 << 2,
+    PaintBehaviorRenderingSVGMask = 1 << 3
 };
 
 typedef unsigned PaintBehavior;
index 5ab349a..965c79c 100644 (file)
@@ -55,12 +55,23 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m
     if (!svgStyle)
         return 0;
 
+    bool isRenderingMask = false;
+    if (object->frame() && object->frame()->view())
+        isRenderingMask = object->frame()->view()->paintBehavior() & PaintBehaviorRenderingSVGMask;
+
     // If we have no fill/stroke, return 0.
     if (mode == ApplyToFillMode) {
+        // When rendering the mask for a RenderSVGResourceClipper, always use the initial fill paint server, and ignore stroke.
+        if (isRenderingMask) {
+            RenderSVGResourceSolidColor* colorResource = RenderSVGResource::sharedSolidPaintingResource();
+            colorResource->setColor(SVGRenderStyle::initialFillPaintColor());
+            return colorResource;
+        }
+
         if (!svgStyle->hasFill())
             return 0;
     } else {
-        if (!svgStyle->hasStroke())
+        if (!svgStyle->hasStroke() || isRenderingMask)
             return 0;
     }
 
index 3b2e6f9..cc6c484 100644 (file)
@@ -54,7 +54,6 @@ RenderSVGResourceType RenderSVGResourceClipper::s_resourceType = ClipperResource
 
 RenderSVGResourceClipper::RenderSVGResourceClipper(SVGClipPathElement* node)
     : RenderSVGResourceContainer(node)
-    , m_invalidationBlocked(false)
 {
 }
 
@@ -69,9 +68,6 @@ RenderSVGResourceClipper::~RenderSVGResourceClipper()
 
 void RenderSVGResourceClipper::removeAllClientsFromCache(bool markForInvalidation)
 {
-    if (m_invalidationBlocked)
-        return;
-
     m_clipBoundaries = FloatRect();
     if (!m_clipper.isEmpty()) {
         deleteAllValues(m_clipper);
@@ -84,9 +80,6 @@ void RenderSVGResourceClipper::removeAllClientsFromCache(bool markForInvalidatio
 void RenderSVGResourceClipper::removeClientFromCache(RenderObject* client, bool markForInvalidation)
 {
     ASSERT(client);
-    if (m_invalidationBlocked)
-        return;
-
     if (m_clipper.contains(client))
         delete m_clipper.take(client);
 
@@ -199,7 +192,10 @@ bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* object, cons
             }
         }
 
-        drawContentIntoMaskImage(clipperData, objectBoundingBox);
+        if (!drawContentIntoMaskImage(clipperData, objectBoundingBox)) {
+            stateSaver.restore();
+            clipperData->clipMaskImage.clear();
+        }
     }
 
     if (!clipperData->clipMaskImage)
@@ -211,6 +207,7 @@ bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* object, cons
 
 bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData, const FloatRect& objectBoundingBox)
 {
+    ASSERT(frame());
     ASSERT(clipperData);
     ASSERT(clipperData->clipMaskImage);
 
@@ -225,11 +222,23 @@ bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData
         maskContext->concatCTM(maskContentTransformation);
     }
 
+    // Switch to a paint behavior where all children of this <clipPath> will be rendered using special constraints:
+    // - fill-opacity/stroke-opacity/opacity set to 1
+    // - masker/filter not applied when rendering the children
+    // - fill is set to the initial fill paint server (solid, black)
+    // - stroke is set to the initial stroke paint server (none)
+    PaintBehavior oldBehavior = frame()->view()->paintBehavior();
+    frame()->view()->setPaintBehavior(oldBehavior | PaintBehaviorRenderingSVGMask);
+
     // 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;
+        if (renderer->needsLayout()) {
+            frame()->view()->setPaintBehavior(oldBehavior);
+            return false;
+        }
         RenderStyle* style = renderer->style();
         if (!style || style->display() == NONE || style->visibility() != VISIBLE)
             continue;
@@ -249,35 +258,15 @@ bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData
         if (!renderer->isSVGShape() && !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(SVGRenderStyle::initialFillPaintType(), SVGRenderStyle::initialFillPaintColor(), SVGRenderStyle::initialFillPaintUri());
-        svgStyle->setStrokePaint(SVGRenderStyle::initialStrokePaintType(), SVGRenderStyle::initialStrokePaintColor(), SVGRenderStyle::initialStrokePaintUri());
-        svgStyle->setFillRule(newClipRule);
-        newRenderStyle.get()->setOpacity(1);
-        svgStyle->setFillOpacity(1);
-        svgStyle->setStrokeOpacity(1);
-        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());
+        maskContext->setFillRule(newClipRule);
 
         // 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;
     }
 
+    frame()->view()->setPaintBehavior(oldBehavior);
     return true;
 }
 
index 2ff8a5d..f2f4b05 100644 (file)
@@ -69,7 +69,6 @@ private:
     bool drawContentIntoMaskImage(ClipperData*, const FloatRect& objectBoundingBox);
     void calculateClipContentRepaintRect();
 
-    bool m_invalidationBlocked;
     FloatRect m_clipBoundaries;
     HashMap<RenderObject*, ClipperData*> m_clipper;
 };
index 82adc6a..7f78059 100644 (file)
@@ -117,7 +117,10 @@ bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*,
         maskImageContext->translate(-clampedAbsoluteTargetRect.x(), -clampedAbsoluteTargetRect.y());
         maskImageContext->concatCTM(absoluteTransform);
 
-        drawContentIntoMaskImage(maskerData, colorSpace, maskElement, object);
+        if (!drawContentIntoMaskImage(maskerData, colorSpace, maskElement, object)) {
+            maskImageContext->restore();
+            maskerData->maskImage.clear();
+        }
     }
 
     if (!maskerData->maskImage)
@@ -127,7 +130,7 @@ bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*,
     return true;
 }
 
-void RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, ColorSpace colorSpace, const SVGMaskElement* maskElement, RenderObject* object)
+bool RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, ColorSpace colorSpace, const SVGMaskElement* maskElement, RenderObject* object)
 {
     GraphicsContext* maskImageContext = maskerData->maskImage->context();
     ASSERT(maskImageContext);
@@ -146,6 +149,8 @@ void RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, C
         RenderObject* renderer = node->renderer();
         if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !renderer)
             continue;
+        if (renderer->needsLayout())
+            return false;
         RenderStyle* style = renderer->style();
         if (!style || style->display() == NONE || style->visibility() != VISIBLE)
             continue;
@@ -162,6 +167,7 @@ void RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, C
 
     // Create the luminance mask.
     maskerData->maskImage->convertToLuminanceMask();
+    return true;
 }
 
 void RenderSVGResourceMasker::calculateMaskContentRepaintRect()
index 8336e0d..9c57923 100644 (file)
@@ -57,7 +57,7 @@ public:
     static RenderSVGResourceType s_resourceType;
 
 private:
-    void drawContentIntoMaskImage(MaskerData*, ColorSpace, const SVGMaskElement*, RenderObject*);
+    bool drawContentIntoMaskImage(MaskerData*, ColorSpace, const SVGMaskElement*, RenderObject*);
     void calculateMaskContentRepaintRect();
 
     FloatRect m_maskContentBoundaries;
index 652623a..a17ed5a 100644 (file)
@@ -258,6 +258,8 @@ PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternA
     for (Node* node = attributes.patternContentElement()->firstChild(); node; node = node->nextSibling()) {
         if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !node->renderer())
             continue;
+        if (node->renderer()->needsLayout())
+            return nullptr;
         SVGImageBufferTools::renderSubtreeToImageBuffer(tileImage.get(), node->renderer(), contentTransformation);
     }
 
index 63df751..b06cd80 100644 (file)
@@ -54,15 +54,25 @@ bool RenderSVGResourceSolidColor::applyResource(RenderObject* object, RenderStyl
     const SVGRenderStyle* svgStyle = style ? style->svgStyle() : 0;
     ColorSpace colorSpace = style ? style->colorSpace() : ColorSpaceDeviceRGB;
 
+    bool isRenderingMask = false;
+    if (object->frame() && object->frame()->view())
+        isRenderingMask = object->frame()->view()->paintBehavior() & PaintBehaviorRenderingSVGMask;
+
     if (resourceMode & ApplyToFillMode) {
-        context->setAlpha(svgStyle ? svgStyle->fillOpacity() : 1.0f);
+        if (!isRenderingMask && svgStyle)
+            context->setAlpha(svgStyle->fillOpacity());
+        else
+            context->setAlpha(1);
         context->setFillColor(m_color, colorSpace);
-        context->setFillRule(svgStyle ? svgStyle->fillRule() : RULE_NONZERO);
+        if (!isRenderingMask)
+            context->setFillRule(svgStyle ? svgStyle->fillRule() : RULE_NONZERO);
 
         if (resourceMode & ApplyToTextMode)
             context->setTextDrawingMode(TextModeFill);
     } else if (resourceMode & ApplyToStrokeMode) {
-        context->setAlpha(svgStyle ? svgStyle->strokeOpacity() : 1.0f);
+        // When rendering the mask for a RenderSVGResourceClipper, the stroke code path is never hit.
+        ASSERT(!isRenderingMask);
+        context->setAlpha(svgStyle ? svgStyle->strokeOpacity() : 1);
         context->setStrokeColor(m_color, colorSpace);
 
         if (style)
index fe31f2f..e38d3ab 100644 (file)
@@ -87,7 +87,7 @@ void SVGImageBufferTools::renderSubtreeToImageBuffer(ImageBuffer* image, RenderO
     AffineTransform savedContentTransformation = contentTransformation;
     contentTransformation = subtreeContentTransformation * contentTransformation;
 
-    item->layoutIfNeeded();
+    ASSERT(!item->needsLayout());
     item->paint(info, IntPoint());
 
     contentTransformation = savedContentTransformation;
index 23f26b5..c025291 100644 (file)
@@ -198,21 +198,10 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo)
     const SVGRenderStyle* svgStyle = style->svgStyle();
     ASSERT(svgStyle);
 
-    bool hasFill = svgStyle->hasFill();
-    bool hasStroke = svgStyle->hasStroke();
-
     RenderStyle* selectionStyle = style;
     if (hasSelection) {
         selectionStyle = parentRenderer->getCachedPseudoStyle(SELECTION);
-        if (selectionStyle) {
-            const SVGRenderStyle* svgSelectionStyle = selectionStyle->svgStyle();
-            ASSERT(svgSelectionStyle);
-
-            if (!hasFill)
-                hasFill = svgSelectionStyle->hasFill();
-            if (!hasStroke)
-                hasStroke = svgSelectionStyle->hasStroke();
-        } else
+        if (!selectionStyle)
             selectionStyle = style;
     }
 
@@ -295,6 +284,11 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni
             selectionStyle = style;
     }
 
+    if (textRenderer->frame() && textRenderer->frame()->view() && textRenderer->frame()->view()->paintBehavior() & PaintBehaviorRenderingSVGMask) {
+        hasFill = true;
+        hasStroke = false;
+    }
+
     AffineTransform fragmentTransform;
     unsigned textFragmentsSize = m_textFragments.size();
     for (unsigned i = 0; i < textFragmentsSize; ++i) {
index 5819d45..b25815f 100644 (file)
@@ -87,8 +87,12 @@ bool SVGRenderSupport::prepareToRenderSVGContent(RenderObject* object, PaintInfo
     const SVGRenderStyle* svgStyle = style->svgStyle();
     ASSERT(svgStyle);
 
+    bool isRenderingMask = false;
+    if (object->frame() && object->frame()->view())
+        isRenderingMask = object->frame()->view()->paintBehavior() & PaintBehaviorRenderingSVGMask;
+
     // Setup transparency layers before setting up SVG resources!
-    float opacity = style->opacity();
+    float opacity = isRenderingMask ? 1 : style->opacity();
     const ShadowData* shadow = svgStyle->shadow();
     if (opacity < 1 || shadow) {
         FloatRect repaintRect = object->repaintRectInLocalCoordinates();
@@ -114,9 +118,11 @@ bool SVGRenderSupport::prepareToRenderSVGContent(RenderObject* object, PaintInfo
         return true;
     }
 
-    if (RenderSVGResourceMasker* masker = resources->masker()) {
-        if (!masker->applyResource(object, style, paintInfo.context, ApplyToDefaultMode))
-            return false;
+    if (!isRenderingMask) {
+        if (RenderSVGResourceMasker* masker = resources->masker()) {
+            if (!masker->applyResource(object, style, paintInfo.context, ApplyToDefaultMode))
+                return false;
+        }
     }
 
     if (RenderSVGResourceClipper* clipper = resources->clipper()) {
@@ -125,9 +131,11 @@ bool SVGRenderSupport::prepareToRenderSVGContent(RenderObject* object, PaintInfo
     }
 
 #if ENABLE(FILTERS)
-    if (RenderSVGResourceFilter* filter = resources->filter()) {
-        if (!filter->applyResource(object, style, paintInfo.context, ApplyToDefaultMode))
-            return false;
+    if (!isRenderingMask) {
+        if (RenderSVGResourceFilter* filter = resources->filter()) {
+            if (!filter->applyResource(object, style, paintInfo.context, ApplyToDefaultMode))
+                return false;
+        }
     }
 #endif