[SVG Masking] Enable the use of <mask> elements for -webkit-mask-image
authorstavila@adobe.com <stavila@adobe.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 18 Dec 2014 13:41:59 +0000 (13:41 +0000)
committerstavila@adobe.com <stavila@adobe.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 18 Dec 2014 13:41:59 +0000 (13:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=139294

Reviewed by Simon Fraser.

Source/WebCore:

This patch links together all parts required for the functionality which improves
the -webkit-mask-image property by allowing it to reference a <mask> element defined
in an inline or external SVG document.
Support for this new functionality has been added in a previous patch, under issue
https://bugs.webkit.org/show_bug.cgi?id=139092. A more detailed description of how
the new functionality works can be found in the ChangeLog for that commit.
The containsSVGDocument in ScrollView has been removed because it was added in the
previous patch but is no longer required.

Tests: css3/masking/mask-base64.html
       css3/masking/mask-multiple-values.html
       css3/masking/mask-svg-clipped-fragmentId.html
       css3/masking/mask-svg-fragmentId.html
       css3/masking/mask-svg-inline-fragmentId.html
       css3/masking/mask-svg-inline-invalid-fragmentId.html
       css3/masking/mask-svg-invalid-fragmentId.html
       css3/masking/mask-svg-no-fragmentId-tiled.html
       css3/masking/mask-svg-no-fragmentId.html
       css3/masking/mask-svg-script-entire-svg-to-mask.html
       css3/masking/mask-svg-script-mask-to-entire-svg.html
       css3/masking/mask-svg-script-mask-to-none.html
       css3/masking/mask-svg-script-mask-to-png.html
       css3/masking/mask-svg-script-none-to-mask.html
       css3/masking/mask-svg-script-none-to-png.html
       css3/masking/mask-svg-script-png-to-mask.html
       css3/masking/mask-svg-script-png-to-none.html

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::ComputedStyleExtractor::propertyValue):
* css/CSSParser.cpp:
(WebCore::CSSParser::parseFillShorthand):
(WebCore::CSSParser::parseFillProperty):
(WebCore::CSSParser::parseMaskImage):
* css/CSSParser.h:
* css/CSSValue.h:
* css/DeprecatedStyleBuilder.cpp:
(WebCore::DeprecatedStyleBuilder::DeprecatedStyleBuilder):
* css/StyleResolver.cpp:
(WebCore::StyleResolver::adjustStyleForMaskImages):
(WebCore::StyleResolver::applyMatchedProperties):
(WebCore::StyleResolver::applyProperty):
(WebCore::StyleResolver::loadPendingSVGDocuments):
(WebCore::StyleResolver::createMaskImageOperations):
(WebCore::StyleResolver::loadPendingImages):
* css/StyleResolver.h:
* page/FrameView.cpp:
(WebCore::FrameView::containsSVGDocument): Deleted.
* page/FrameView.h:
* page/animation/CSSPropertyAnimation.cpp:
(WebCore::blendFunc):
(WebCore::MaskImagePropertyWrapper::MaskImagePropertyWrapper):
(WebCore::MaskImagePropertyWrapper::equals):
(WebCore::CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap):
* platform/ScrollView.h:
(WebCore::ScrollView::containsSVGDocument): Deleted.
* platform/graphics/MaskImageOperation.cpp:
(WebCore::MaskImageOperation::~MaskImageOperation):
(WebCore::MaskImageOperation::operator==):
* platform/graphics/MaskImageOperation.h:
* rendering/RenderBox.cpp:
(WebCore::RenderBox::maskClipRect):
* rendering/RenderBox.h:
* rendering/RenderBoxModelObject.cpp:
(WebCore::RenderBoxModelObject::paintFillLayerExtended):
(WebCore::RenderBoxModelObject::calculateFillTileSize):
(WebCore::RenderBoxModelObject::calculateBackgroundImageGeometry):
* rendering/RenderElement.cpp:
(WebCore::RenderElement::~RenderElement):
(WebCore::RenderElement::updateFillImages):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::calculateClipRects):
* rendering/RenderLayer.h:
* rendering/RenderLayerMaskImageInfo.cpp:
(WebCore::RenderLayer::MaskImageInfo::~MaskImageInfo):
(WebCore::RenderLayer::MaskImageInfo::updateMaskImageClients):
(WebCore::RenderLayer::MaskImageInfo::removeMaskImageClients):
* rendering/RenderLayerMaskImageInfo.h:
* rendering/style/FillLayer.cpp:
(WebCore::FillLayer::hasImage):
* rendering/style/FillLayer.h:
(WebCore::FillLayer::image):
(WebCore::FillLayer::imageOrMaskImage): Deleted.
* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::setMaskImage):
* rendering/style/RenderStyle.h:

LayoutTests:

Added tests for different situations using URLs with fragment id
for the -webkit-mask-image property.

* css3/masking/mask-base64-expected.html: Copied from LayoutTests/css3/masking/mask-repeat-space-padding-expected.html.
* css3/masking/mask-base64.html: Added.
* css3/masking/mask-multiple-values-expected.html: Added.
* css3/masking/mask-multiple-values.html: Added.
* css3/masking/mask-repeat-space-padding-expected.html:
* css3/masking/mask-repeat-space-padding.html:
* css3/masking/mask-svg-clipped-fragmentId-expected.html: Added.
* css3/masking/mask-svg-clipped-fragmentId.html: Added.
* css3/masking/mask-svg-fragmentId-expected.html: Added.
* css3/masking/mask-svg-fragmentId.html: Added.
* css3/masking/mask-svg-inline-fragmentId-expected.html: Added.
* css3/masking/mask-svg-inline-fragmentId.html: Added.
* css3/masking/mask-svg-inline-invalid-fragmentId-expected.html: Added.
* css3/masking/mask-svg-inline-invalid-fragmentId.html: Added.
* css3/masking/mask-svg-invalid-fragmentId-expected.html: Added.
* css3/masking/mask-svg-invalid-fragmentId.html: Added.
* css3/masking/mask-svg-no-fragmentId-expected.html: Added.
* css3/masking/mask-svg-no-fragmentId-tiled-expected.html: Added.
* css3/masking/mask-svg-no-fragmentId-tiled.html: Added.
* css3/masking/mask-svg-no-fragmentId.html: Added.
* css3/masking/mask-svg-script-entire-svg-to-mask-expected.html: Added.
* css3/masking/mask-svg-script-entire-svg-to-mask.html: Added.
* css3/masking/mask-svg-script-mask-to-entire-svg-expected.html: Added.
* css3/masking/mask-svg-script-mask-to-entire-svg.html: Added.
* css3/masking/mask-svg-script-mask-to-none-expected.html: Added.
* css3/masking/mask-svg-script-mask-to-none.html: Added.
* css3/masking/mask-svg-script-mask-to-png-expected.html: Added.
* css3/masking/mask-svg-script-mask-to-png.html: Added.
* css3/masking/mask-svg-script-none-to-mask-expected.html: Added.
* css3/masking/mask-svg-script-none-to-mask.html: Added.
* css3/masking/mask-svg-script-none-to-png-expected.html: Added.
* css3/masking/mask-svg-script-none-to-png.html: Added.
* css3/masking/mask-svg-script-png-to-mask-expected.html: Added.
* css3/masking/mask-svg-script-png-to-mask.html: Added.
* css3/masking/mask-svg-script-png-to-none-expected.html: Added.
* css3/masking/mask-svg-script-png-to-none.html: Added.
* css3/masking/resources/masks.svg: Added.

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

64 files changed:
LayoutTests/ChangeLog
LayoutTests/css3/masking/mask-base64-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-base64.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-multiple-values-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-multiple-values.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-repeat-space-padding-expected.html
LayoutTests/css3/masking/mask-repeat-space-padding.html
LayoutTests/css3/masking/mask-svg-clipped-fragmentId-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-clipped-fragmentId.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-fragmentId-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-fragmentId.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-inline-fragmentId-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-inline-fragmentId.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-inline-invalid-fragmentId-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-inline-invalid-fragmentId.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-invalid-fragmentId-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-invalid-fragmentId.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-no-fragmentId-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-no-fragmentId-tiled-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-no-fragmentId-tiled.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-no-fragmentId.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-entire-svg-to-mask-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-entire-svg-to-mask.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-mask-to-entire-svg-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-mask-to-entire-svg.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-mask-to-none-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-mask-to-none.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-mask-to-png-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-mask-to-png.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-none-to-mask-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-none-to-mask.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-none-to-png-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-none-to-png.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-png-to-mask-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-png-to-mask.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-png-to-none-expected.html [new file with mode: 0644]
LayoutTests/css3/masking/mask-svg-script-png-to-none.html [new file with mode: 0644]
LayoutTests/css3/masking/resources/masks.svg [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSParser.cpp
Source/WebCore/css/CSSParser.h
Source/WebCore/css/CSSValue.h
Source/WebCore/css/DeprecatedStyleBuilder.cpp
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/css/StyleResolver.h
Source/WebCore/page/FrameView.cpp
Source/WebCore/page/FrameView.h
Source/WebCore/page/animation/CSSPropertyAnimation.cpp
Source/WebCore/platform/ScrollView.h
Source/WebCore/platform/graphics/MaskImageOperation.cpp
Source/WebCore/platform/graphics/MaskImageOperation.h
Source/WebCore/rendering/RenderBox.cpp
Source/WebCore/rendering/RenderBox.h
Source/WebCore/rendering/RenderBoxModelObject.cpp
Source/WebCore/rendering/RenderElement.cpp
Source/WebCore/rendering/RenderLayer.cpp
Source/WebCore/rendering/RenderLayer.h
Source/WebCore/rendering/RenderLayerMaskImageInfo.cpp
Source/WebCore/rendering/RenderLayerMaskImageInfo.h
Source/WebCore/rendering/style/FillLayer.cpp
Source/WebCore/rendering/style/FillLayer.h
Source/WebCore/rendering/style/RenderStyle.cpp
Source/WebCore/rendering/style/RenderStyle.h

index e522c7e..6dccaa5 100644 (file)
@@ -1,3 +1,51 @@
+2014-12-18  Radu Stavila  <stavila@adobe.com>
+
+        [SVG Masking] Enable the use of <mask> elements for -webkit-mask-image
+        https://bugs.webkit.org/show_bug.cgi?id=139294
+
+        Reviewed by Simon Fraser.
+
+        Added tests for different situations using URLs with fragment id
+        for the -webkit-mask-image property.
+
+        * css3/masking/mask-base64-expected.html: Copied from LayoutTests/css3/masking/mask-repeat-space-padding-expected.html.
+        * css3/masking/mask-base64.html: Added.
+        * css3/masking/mask-multiple-values-expected.html: Added.
+        * css3/masking/mask-multiple-values.html: Added.
+        * css3/masking/mask-repeat-space-padding-expected.html:
+        * css3/masking/mask-repeat-space-padding.html:
+        * css3/masking/mask-svg-clipped-fragmentId-expected.html: Added.
+        * css3/masking/mask-svg-clipped-fragmentId.html: Added.
+        * css3/masking/mask-svg-fragmentId-expected.html: Added.
+        * css3/masking/mask-svg-fragmentId.html: Added.
+        * css3/masking/mask-svg-inline-fragmentId-expected.html: Added.
+        * css3/masking/mask-svg-inline-fragmentId.html: Added.
+        * css3/masking/mask-svg-inline-invalid-fragmentId-expected.html: Added.
+        * css3/masking/mask-svg-inline-invalid-fragmentId.html: Added.
+        * css3/masking/mask-svg-invalid-fragmentId-expected.html: Added.
+        * css3/masking/mask-svg-invalid-fragmentId.html: Added.
+        * css3/masking/mask-svg-no-fragmentId-expected.html: Added.
+        * css3/masking/mask-svg-no-fragmentId-tiled-expected.html: Added.
+        * css3/masking/mask-svg-no-fragmentId-tiled.html: Added.
+        * css3/masking/mask-svg-no-fragmentId.html: Added.
+        * css3/masking/mask-svg-script-entire-svg-to-mask-expected.html: Added.
+        * css3/masking/mask-svg-script-entire-svg-to-mask.html: Added.
+        * css3/masking/mask-svg-script-mask-to-entire-svg-expected.html: Added.
+        * css3/masking/mask-svg-script-mask-to-entire-svg.html: Added.
+        * css3/masking/mask-svg-script-mask-to-none-expected.html: Added.
+        * css3/masking/mask-svg-script-mask-to-none.html: Added.
+        * css3/masking/mask-svg-script-mask-to-png-expected.html: Added.
+        * css3/masking/mask-svg-script-mask-to-png.html: Added.
+        * css3/masking/mask-svg-script-none-to-mask-expected.html: Added.
+        * css3/masking/mask-svg-script-none-to-mask.html: Added.
+        * css3/masking/mask-svg-script-none-to-png-expected.html: Added.
+        * css3/masking/mask-svg-script-none-to-png.html: Added.
+        * css3/masking/mask-svg-script-png-to-mask-expected.html: Added.
+        * css3/masking/mask-svg-script-png-to-mask.html: Added.
+        * css3/masking/mask-svg-script-png-to-none-expected.html: Added.
+        * css3/masking/mask-svg-script-png-to-none.html: Added.
+        * css3/masking/resources/masks.svg: Added.
+
 2014-12-18  Csaba Osztrogon√°c  <ossy@webkit.org>
 
         [EFL] Fix test expectations after r177363
diff --git a/LayoutTests/css3/masking/mask-base64-expected.html b/LayoutTests/css3/masking/mask-base64-expected.html
new file mode 100644 (file)
index 0000000..b48a41d
--- /dev/null
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #front {
+                width: 200px;
+                height: 160px;
+                background-color: green;
+                -webkit-mask-repeat: no-repeat;
+                -webkit-mask-origin: content-box;
+                -webkit-mask-clip: content-box;
+            }
+        </style>
+        <script>
+            var sizeX = 50, sizeY = 40, spaceX = 0, spaceY = 0, width = 200, height = 160;
+
+            var urls = Array(), size = Array(), position = Array();
+
+            function addMasks() {
+                for (var x = 0; x < width; x += sizeX + spaceX) {
+                    for (var y = 0; y < height; y += sizeY + spaceY) {
+                        urls.push("url(resources/circle.svg)");
+                        size.push(sizeX + "px " + sizeY + "px");
+                        position.push(x + "px " + y + "px");
+                    }
+                }
+
+                div = document.getElementById("front");
+
+                div.style.cssText += "-webkit-mask-image: " + urls.join(", ") + ";" +
+                                     "-webkit-mask-size: " + size.join(", ")  + ";" +
+                                     "-webkit-mask-position: " + position.join(", ") + ";";
+           }
+       </script>
+    </head>
+
+    <body onload="addMasks()">
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a 4x4 grid of green circles.</p>
+        <p>This test sets the mask-image value using base64.</p>
+        <div id="front"></div>
+    </body>
+</html>
+
diff --git a/LayoutTests/css3/masking/mask-base64.html b/LayoutTests/css3/masking/mask-base64.html
new file mode 100644 (file)
index 0000000..19fb286
--- /dev/null
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 200px;
+                height: 160px;
+                background-color: green;
+                -webkit-mask-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjM2MCIgaGVpZ2h0PSIyODgiPgogICAgPGNpcmNsZSBjeD0iMTgwIiBjeT0iMTQ0IiByPSI4MCIgLz4KPC9zdmc+Cgo=);
+                -webkit-mask-size: 50px 40px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a 4x4 grid of green circles.</p>
+        <p>This test sets the mask-image value using base64.</p>
+        <div id="maskedElement"></div>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-multiple-values-expected.html b/LayoutTests/css3/masking/mask-multiple-values-expected.html
new file mode 100644 (file)
index 0000000..7a1b62b
--- /dev/null
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #back {
+                width: 500px;
+                height: 500px;
+                background-color: green;
+            }
+            .front {
+                position: absolute;
+                width: 300px;
+                height: 300px;
+                background-color: black;
+                border: 50px solid blue;
+                padding: 50px;
+                -webkit-mask-repeat: no-repeat;
+                -webkit-mask-origin: content-box;
+                -webkit-mask-clip: border-box;
+            }
+            #front1 {
+                -webkit-mask-image: url('resources/circle.png');
+                -webkit-mask-size: 150px 120px;
+                -webkit-mask-position: -120px -110px;
+            }
+            #front2 {
+                -webkit-mask-image: url('resources/masks.svg#lowerHalf');
+                -webkit-mask-size: 300px 240px;
+                -webkit-mask-position: 50px 0px;
+            }
+            #front3 {
+                -webkit-mask-image: url('resources/masks.svg#upperHalf');
+                -webkit-mask-size: 300px 240px;
+                -webkit-mask-position: 50px 0px;
+            }
+            #front4 {
+                -webkit-mask-image: url('resources/masks.svg#invalidId');
+                -webkit-mask-size: 225px 180px;
+                -webkit-mask-position: 160px 220px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - This test uses multiple masks from multiple resources.</p>
+        <div id="back">
+            <div class="front" id="front1"></div>
+            <div class="front" id="front2"></div>
+            <div class="front" id="front3"></div>
+            <div class="front" id="front4"></div>
+        </div>
+    </body>
+</html>
+
diff --git a/LayoutTests/css3/masking/mask-multiple-values.html b/LayoutTests/css3/masking/mask-multiple-values.html
new file mode 100644 (file)
index 0000000..ed2d675
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #back {
+                width: 500px;
+                height: 500px;
+                background-color: green;
+            }
+            #front {
+                width: 300px;
+                height: 300px;
+                background-color: black;
+                border: 50px solid blue;
+                padding: 50px;
+                -webkit-mask-image: url('resources/circle.png'), url('resources/masks.svg#lowerHalf'), url('resources/masks.svg#upperHalf'), url('resources/masks.svg#invalidId');
+                -webkit-mask-size: 150px 120px, 300px 240px, 300px 240px, 225px 180px;
+                -webkit-mask-position: -120px -110px, 50px 0px, 50px 0px, 160px 220px;
+                -webkit-mask-repeat: no-repeat;
+                -webkit-mask-origin: content-box;
+                -webkit-mask-clip: border-box;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - This test uses multiple masks from multiple resources.</p>
+        <div id="back">
+            <div id="front"></div>
+        </div>
+    </body>
+</html>
+
index 2be9836..3cce138 100644 (file)
@@ -26,7 +26,7 @@
             function addMasks() {
                 for (var x = 0; x < width; x += sizeX + spaceX) {
                     for (var y = 0; y < height; y += sizeY + spaceY) {
-                        urls.push("url(resources/circle.png)");
+                        urls.push("url(resources/circle.svg)");
                         size.push(sizeX + "px " + sizeY + "px");
                         position.push(x + "px " + y + "px");
                     }
index e1c6d3b..e1c480a 100644 (file)
@@ -13,7 +13,7 @@
                 background-color: red;
                 border: 50px solid blue;
                 padding: 50px;
-                -webkit-mask-image: url("resources/circle.png");
+                -webkit-mask-image: url("resources/circle.svg");
                 -webkit-mask-size: 100px;
                 -webkit-mask-repeat: space;
                 -webkit-mask-origin: padding-box;
diff --git a/LayoutTests/css3/masking/mask-svg-clipped-fragmentId-expected.html b/LayoutTests/css3/masking/mask-svg-clipped-fragmentId-expected.html
new file mode 100644 (file)
index 0000000..c7d9b83
--- /dev/null
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #back {
+                width: 320px;
+                height: 420px;
+                background-color: green;
+                overflow: hidden;
+            }
+            #blackSVG {
+                position: relative;
+                left: 60px;
+                top: -35px;
+            }
+            #blueSVG {
+                position: relative;
+                left: 70px;
+                top: -474px;
+            }
+        </style>
+    </head>
+
+    <body>
+        
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - This test used a &lt;mask&gt; element and paints it at the side of the masked element, causing it to be clipped.</p>
+        <div id="back">
+            <svg id="blackSVG" width="320px" height="420px">
+                <path fill="black" d="M80,20 L280,20 L280,380 L240,380 L240,60 L80,60 L80,20"/>
+            </svg>
+            <svg id="blueSVG" width="320px" height="420px">
+                <path fill="blue" d="M70,20 L280,20 L280,395 L240,395 L240,60 L70,60 L70,20"/>
+            </svg>
+        </div>
+    </body>
+</html>
+
diff --git a/LayoutTests/css3/masking/mask-svg-clipped-fragmentId.html b/LayoutTests/css3/masking/mask-svg-clipped-fragmentId.html
new file mode 100644 (file)
index 0000000..2ab0941
--- /dev/null
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #back {
+                width: 320px;
+                height: 420px;
+                background-color: green;
+            }
+            #front {
+                width: 300px;
+                height: 400px;
+                background-color: black;
+                border: 10px solid blue;
+                -webkit-mask-image: url('resources/masks.svg#upperHalf');
+                -webkit-mask-size: 320px 420px;
+                -webkit-mask-position: 50px -45px;
+                -webkit-mask-repeat: no-repeat;
+                -webkit-mask-origin: content-box;
+                -webkit-mask-clip: border-box;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - This test used a &lt;mask&gt; element and paints it at the side of the masked element, causing it to be clipped.</p>
+        <div id="back">
+            <div id="front"></div>
+        </div>
+    </body>
+</html>
+
diff --git a/LayoutTests/css3/masking/mask-svg-fragmentId-expected.html b/LayoutTests/css3/masking/mask-svg-fragmentId-expected.html
new file mode 100644 (file)
index 0000000..5a170cd
--- /dev/null
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+        </style>
+    </head>
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a green inverted-L shape and no red.</p>
+        <p>This test references a &lt;mask&gt; element from an external SVG</p>
+        <svg width="300px" height="400px">
+            <path fill="green" d="M80,20 L280,20 L280,380 L240,380 L240,60 L80,60 L80,20"/>
+        </svg>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-fragmentId.html b/LayoutTests/css3/masking/mask-svg-fragmentId.html
new file mode 100644 (file)
index 0000000..00fd70e
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 300px;
+                height: 400px;
+                background-color: green;
+                -webkit-mask-image:url('resources/masks.svg#upperHalf');
+            }
+            #redSvg {
+                position: absolute;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a green inverted-L shape and no red.</p>
+        <p>This test references a &lt;mask&gt; element from an external SVG</p>
+        <svg id="redSvg" width="300px" height="400px">
+            <path fill="red" d="M80,20 L280,20 L280,380 L240,380 L240,60 L80,60 L80,20"/>
+        </svg>
+        <div id="maskedElement"></div>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-inline-fragmentId-expected.html b/LayoutTests/css3/masking/mask-svg-inline-fragmentId-expected.html
new file mode 100644 (file)
index 0000000..82785a7
--- /dev/null
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+        </style>
+    </head>
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a green L shape and no red.</p>
+        <p>This test references a &lt;mask&gt; element defined in the main HTML document</p>
+        <svg width="300px" height="400px">
+            <path fill="green" d="M20,20 L60,20 L60,340 L220,340 L220,380 L20,380 L20,20"/>
+        </svg>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-inline-fragmentId.html b/LayoutTests/css3/masking/mask-svg-inline-fragmentId.html
new file mode 100644 (file)
index 0000000..225417b
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 300px;
+                height: 400px;
+                background-color: green;
+                -webkit-mask-image:url('#lowerHalf');
+            }
+            #redSvg {
+                position: absolute;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a green L shape and no red.</p>
+        <p>This test references a &lt;mask&gt; element defined in the main HTML document</p>
+        <svg id="redSvg" width="300px" height="400px">
+            <path fill="red" d="M20,20 L60,20 L60,340 L220,340 L220,380 L20,380 L20,20"/>
+            <mask id="lowerHalf" maskUnits="objectBoundingBox">
+                <path fill="#FFFFFF" d="M20,20 L60,20 L60,340 L220,340 L220,380 L20,380 L20,20"/>
+            </mask>
+        </svg>
+        <div id="maskedElement"></div>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-inline-invalid-fragmentId-expected.html b/LayoutTests/css3/masking/mask-svg-inline-invalid-fragmentId-expected.html
new file mode 100644 (file)
index 0000000..43378ee
--- /dev/null
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #elementToNotBeCovered {
+                width: 300px;
+                height: 400px;
+                background-color: #2222FF;
+                position: absolute;
+                left: 10px;
+                top: 50px;
+            }
+        </style>
+    </head>
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a blue rectangle and no red.</p>
+        <p>This test references an invalid fragment identifier.</p>
+        <div id="elementToNotBeCovered"></div>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-inline-invalid-fragmentId.html b/LayoutTests/css3/masking/mask-svg-inline-invalid-fragmentId.html
new file mode 100644 (file)
index 0000000..6be3c06
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 300px;
+                height: 400px;
+                background-color: red;
+                -webkit-mask-image:url('#invalidId');
+                position: absolute;
+                left: 10px;
+                top: 50px;
+            }
+            #elementToNotBeCovered {
+                width: 300px;
+                height: 400px;
+                background-color: #2222FF;
+                position: absolute;
+                left: 10px;
+                top: 50px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a blue rectangle and no red.</p>
+        <p>This test references an invalid fragment identifier.</p>
+        <div id="elementToNotBeCovered"></div>
+        <div id="maskedElement"></div>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-invalid-fragmentId-expected.html b/LayoutTests/css3/masking/mask-svg-invalid-fragmentId-expected.html
new file mode 100644 (file)
index 0000000..c73ab7e
--- /dev/null
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see 4 green rectangles and no red.</p>
+        <p>This test references an invalid fragment identifier from an external SVG</p>
+        <svg width="300px" height="400px">
+            <rect x="5px" y="45px" width="140px" height="140px" fill="green"/>
+            <rect x="155px" y="45px" width="140px" height="140px" fill="green"/>
+            <rect x="155px" y="215px" width="140px" height="140px" fill="green"/>
+            <rect x="5px" y="215px" width="140px" height="140px" fill="green"/>
+        </svg>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-invalid-fragmentId.html b/LayoutTests/css3/masking/mask-svg-invalid-fragmentId.html
new file mode 100644 (file)
index 0000000..0b354ea
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 300px;
+                height: 400px;
+                background-color: green;
+                -webkit-mask-image:url('resources/masks.svg#invalidId');
+            }
+            #redSvg {
+                position: absolute;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see 4 green rectangles and no red.</p>
+        <p>This test references an invalid fragment identifier from an external SVG</p>
+        <svg id="redSvg" width="300px" height="400px">
+            <rect x="5px" y="45px" width="140px" height="140px" fill="red"/>
+            <rect x="155px" y="45px" width="140px" height="140px" fill="red"/>
+            <rect x="155px" y="215px" width="140px" height="140px" fill="red"/>
+            <rect x="5px" y="215px" width="140px" height="140px" fill="red"/>
+        </svg>
+        <div id="maskedElement"></div>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-no-fragmentId-expected.html b/LayoutTests/css3/masking/mask-svg-no-fragmentId-expected.html
new file mode 100644 (file)
index 0000000..d52a0f1
--- /dev/null
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see 4 green rectangles and no red.</p>
+        <p>This test references an external SVG without specifying a fragment id.</p>
+        <svg width="300px" height="400px">
+            <rect x="5px" y="45px" width="140px" height="140px" fill="green"/>
+            <rect x="155px" y="45px" width="140px" height="140px" fill="green"/>
+            <rect x="155px" y="215px" width="140px" height="140px" fill="green"/>
+            <rect x="5px" y="215px" width="140px" height="140px" fill="green"/>
+        </svg>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-no-fragmentId-tiled-expected.html b/LayoutTests/css3/masking/mask-svg-no-fragmentId-tiled-expected.html
new file mode 100644 (file)
index 0000000..debfd33
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #background {
+                width: 400px;
+                height: 500px;
+                background-color: lightblue;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a 4-rectangle green image painted tiled and no red.</p>
+        <p>This test references an external SVG without specifying a fragment id and paints using multiple tiles.</p>
+
+        <div id="background">
+            <svg id="redSvg" width="400px" height="500px">
+                <rect x="5px" y="45px" width="140px" height="140px" fill="green"/>
+                <rect x="155px" y="45px" width="140px" height="140px" fill="green"/>
+                <rect x="305px" y="45px" width="95px" height="140px" fill="green"/>
+                <rect x="155px" y="215px" width="140px" height="140px" fill="green"/>
+                <rect x="305px" y="215px" width="95px" height="140px" fill="green"/>
+                <rect x="5px" y="215px" width="140px" height="140px" fill="green"/>
+                <rect x="5px" y="445px" width="140px" height="55px" fill="green"/>
+                <rect x="155px" y="445px" width="140px" height="55px" fill="green"/>
+                <rect x="305px" y="445px" width="95px" height="55px" fill="green"/>
+            </svg>
+        </div>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-no-fragmentId-tiled.html b/LayoutTests/css3/masking/mask-svg-no-fragmentId-tiled.html
new file mode 100644 (file)
index 0000000..88ae563
--- /dev/null
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #background {
+                width: 400px;
+                height: 500px;
+                background-color: lightblue;
+            }
+            #maskedElement {
+                width: 400px;
+                height: 500px;
+                background-color: green;
+                -webkit-mask-image:url('resources/masks.svg');
+            }
+            #redSvg {
+                position: absolute;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a 4-rectangle green image painted tiled and no red.</p>
+        <p>This test references an external SVG without specifying a fragment id and paints using multiple tiles.</p>
+        <svg id="redSvg" width="400px" height="500px">
+            <rect x="5px" y="45px" width="140px" height="140px" fill="red"/>
+            <rect x="155px" y="45px" width="140px" height="140px" fill="red"/>
+            <rect x="305px" y="45px" width="95px" height="140px" fill="red"/>
+            <rect x="155px" y="215px" width="140px" height="140px" fill="red"/>
+            <rect x="305px" y="215px" width="95px" height="140px" fill="red"/>
+            <rect x="5px" y="215px" width="140px" height="140px" fill="red"/>
+            <rect x="5px" y="445px" width="140px" height="55px" fill="red"/>
+            <rect x="155px" y="445px" width="140px" height="55px" fill="red"/>
+            <rect x="305px" y="445px" width="95px" height="55px" fill="red"/>
+        </svg>
+        <div id="background">
+            <div id="maskedElement"></div>
+        </div>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-no-fragmentId.html b/LayoutTests/css3/masking/mask-svg-no-fragmentId.html
new file mode 100644 (file)
index 0000000..8e0d8fc
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 300px;
+                height: 400px;
+                background-color: green;
+                -webkit-mask-image:url('resources/masks.svg');
+            }
+            #redSvg {
+                position: absolute;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see 4 green rectangles and no red.</p>
+        <p>This test references an external SVG without specifying a fragment id.</p>
+        <svg id="redSvg" width="300px" height="400px">
+            <rect x="5px" y="45px" width="140px" height="140px" fill="red"/>
+            <rect x="155px" y="45px" width="140px" height="140px" fill="red"/>
+            <rect x="155px" y="215px" width="140px" height="140px" fill="red"/>
+            <rect x="5px" y="215px" width="140px" height="140px" fill="red"/>
+        </svg>
+        <div id="maskedElement"></div>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-entire-svg-to-mask-expected.html b/LayoutTests/css3/masking/mask-svg-script-entire-svg-to-mask-expected.html
new file mode 100644 (file)
index 0000000..4f24ee9
--- /dev/null
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+        </style>
+    </head>
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a blue inverted-L shape and no red.</p>
+        <p>This test sets the mask-image via CSS to the entire SVG and then changes it to a &lt;mask&gt; element from the SVG via a script.</p>
+        <svg width="300px" height="400px">
+            <path fill="blue" d="M80,20 L280,20 L280,380 L240,380 L240,60 L80,60 L80,20"/>
+        </svg>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-entire-svg-to-mask.html b/LayoutTests/css3/masking/mask-svg-script-entire-svg-to-mask.html
new file mode 100644 (file)
index 0000000..e21fd60
--- /dev/null
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 300px;
+                height: 400px;
+                background-color: green;
+                -webkit-mask-image:url('resources/masks.svg');
+            }
+            #redSvg {
+                position: absolute;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a blue inverted-L shape and no red.</p>
+        <p>This test sets the mask-image via CSS to the entire SVG and then changes it to a &lt;mask&gt; element from the SVG via a script.</p>
+        <svg id="redSvg" width="300px" height="400px">
+            <path fill="red" d="M80,20 L280,20 L280,380 L240,380 L240,60 L80,60 L80,20"/>
+        </svg>
+        <div id="maskedElement"></div>
+
+        <script>
+            var maskedElement = document.getElementById("maskedElement");
+            maskedElement.style.cssText += "-webkit-mask-image:url('resources/masks.svg#upperHalf');background-color: blue";
+        </script>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-mask-to-entire-svg-expected.html b/LayoutTests/css3/masking/mask-svg-script-mask-to-entire-svg-expected.html
new file mode 100644 (file)
index 0000000..5bbdbd0
--- /dev/null
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 300px;
+                height: 400px;
+                background-color: blue;
+                -webkit-mask-image:url('resources/masks.svg');
+            }
+        </style>
+    </head>
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see four blue squares and no red.</p>
+        <p>This test sets the mask-image via CSS to a &lt;mask&gt; element from an SVG file and then changes it to the entire SVG file via a script.</p>
+        <div id="maskedElement"></div>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-mask-to-entire-svg.html b/LayoutTests/css3/masking/mask-svg-script-mask-to-entire-svg.html
new file mode 100644 (file)
index 0000000..a0872e6
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 300px;
+                height: 400px;
+                background-color: green;
+                -webkit-mask-image:url('resources/masks.svg#lowerHalf');
+            }
+            #redSvg {
+                position: absolute;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see four blue squares and no red.</p>
+        <p>This test sets the mask-image via CSS to a &lt;mask&gt; element from an SVG file and then changes it to the entire SVG file via a script.</p>
+        <svg id="redSvg" width="300px" height="400px">
+            <rect x="5px" y="45px" width="140px" height="140px" fill="red"/>
+            <rect x="155px" y="45px" width="140px" height="140px" fill="red"/>
+            <rect x="155px" y="215px" width="140px" height="140px" fill="red"/>
+            <rect x="5px" y="215px" width="140px" height="140px" fill="red"/>
+        </svg>
+        <div id="maskedElement"></div>
+
+        <script>
+            var maskedElement = document.getElementById("maskedElement");
+            maskedElement.style.cssText += "-webkit-mask-image:url('resources/masks.svg');background-color:blue";
+        </script>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-mask-to-none-expected.html b/LayoutTests/css3/masking/mask-svg-script-mask-to-none-expected.html
new file mode 100644 (file)
index 0000000..afc49d8
--- /dev/null
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 400px;
+                height: 400px;
+                background-color: blue;
+            }
+        </style>
+    </head>
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a blue rectangle and no red.</p>
+        <p>This test sets the mask-image via CSS to a &lt;mask&gt; element from an external SVG file and then changes it to 'none' via a script.</p>
+        <div id="maskedElement"></div>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-mask-to-none.html b/LayoutTests/css3/masking/mask-svg-script-mask-to-none.html
new file mode 100644 (file)
index 0000000..cd1c1bc
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 400px;
+                height: 400px;
+                background-color: green;
+                -webkit-mask-image:url('resources/masks.svg#lowerHalf');
+            }
+            #redElement {
+                width: 400px;
+                height: 400px;
+                background-color: red;
+                position: absolute;
+                z-index: -1;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a blue rectangle and no red.</p>
+        <p>This test sets the mask-image via CSS to a &lt;mask&gt; element from an external SVG file and then changes it to 'none' via a script.</p>
+        <div id="redElement"></div>
+        <div id="maskedElement"></div>
+        <script>
+            var maskedElement = document.getElementById("maskedElement");
+            maskedElement.style.cssText += "-webkit-mask-image:none;background-color: blue";
+        </script>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-mask-to-png-expected.html b/LayoutTests/css3/masking/mask-svg-script-mask-to-png-expected.html
new file mode 100644 (file)
index 0000000..82f526a
--- /dev/null
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 360px;
+                height: 288px;
+                background-color: blue;
+                -webkit-mask-image:url('resources/circle.png');
+            }
+        </style>
+    </head>
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a blue circle and no red.</p>
+        <p>This test sets the mask-image via CSS to a &lt;mask&gt; element from an SVG file and then changes it to a PNG via a script.</p>
+        <div id="maskedElement"></div>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-mask-to-png.html b/LayoutTests/css3/masking/mask-svg-script-mask-to-png.html
new file mode 100644 (file)
index 0000000..d86b943
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 360px;
+                height: 288px;
+                background-color: red;
+                -webkit-mask-image:url('resources/masks.svg#lowerHalf');
+            }
+            #redElement {
+                position: absolute;
+                width: 360px;
+                height: 288px;
+                background-color: red;
+                -webkit-transform: scale(0.95, 0.95);
+                -webkit-mask-image: url('resources/circle.png');
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a blue circle and no red.</p>
+        <p>This test sets the mask-image via CSS to a &lt;mask&gt; element from an SVG file and then changes it to a PNG via a script.</p>
+        <div id="redElement"></div>
+        <div id="maskedElement"></div>
+
+        <script>
+            var maskedElement = document.getElementById("maskedElement");
+            maskedElement.style.cssText += "-webkit-mask-image:url('resources/circle.png');background-color: blue";
+        </script>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-none-to-mask-expected.html b/LayoutTests/css3/masking/mask-svg-script-none-to-mask-expected.html
new file mode 100644 (file)
index 0000000..5293ada
--- /dev/null
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 400px;
+                height: 400px;
+                background-color: blue;
+                -webkit-mask-image:url('resources/masks.svg#upperHalf');
+            }
+        </style>
+    </head>
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a blue inverted-L shape and no red.</p>
+        <p>This test sets the mask-image value to a &lt;mask&gt; element from an external SVG via a script.</p>
+        <div id="maskedElement"></div>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-none-to-mask.html b/LayoutTests/css3/masking/mask-svg-script-none-to-mask.html
new file mode 100644 (file)
index 0000000..c971c91
--- /dev/null
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 400px;
+                height: 400px;
+                background-color: red;
+            }
+            #redSvg {
+                position: absolute;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a blue inverted-L shape and no red.</p>
+        <p>This test sets the mask-image value to a &lt;mask&gt; element from an external SVG via a script.</p>
+        <svg id="redSvg" width="300px" height="400px">
+            <path fill="red" d="M80,20 L280,20 L280,380 L240,380 L240,60 L80,60 L80,20"/>
+        </svg>
+        <div id="maskedElement"></div>
+
+        <script>
+            var maskedElement = document.getElementById("maskedElement");
+            maskedElement.style.cssText += "-webkit-mask-image:url('resources/masks.svg#upperHalf');background-color: blue";
+        </script>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-none-to-png-expected.html b/LayoutTests/css3/masking/mask-svg-script-none-to-png-expected.html
new file mode 100644 (file)
index 0000000..b70da4f
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 280px;
+                height: 210px;
+                background-color: blue;
+                -webkit-mask-image:url('resources/dice.png');
+                -webkit-mask-source-type:luminance;
+            }
+        </style>
+    </head>
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a blue-tinted image of 3 dice.</p>
+        <p>This test sets the mask-image to a PNG image via a script.</p>
+        <div id="maskedElement"></div>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-none-to-png.html b/LayoutTests/css3/masking/mask-svg-script-none-to-png.html
new file mode 100644 (file)
index 0000000..896cd80
--- /dev/null
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 280px;
+                height: 210px;
+                background-color: green;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a blue-tinted image of 3 dice.</p>
+        <p>This test sets the mask-image to a PNG image via a script.</p>
+        <div id="maskedElement"></div>
+        <script>
+            var maskedElement = document.getElementById("maskedElement");
+            maskedElement.style.cssText += "-webkit-mask-image:url('resources/dice.png');-webkit-mask-source-type:luminance;background-color:blue";
+        </script>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-png-to-mask-expected.html b/LayoutTests/css3/masking/mask-svg-script-png-to-mask-expected.html
new file mode 100644 (file)
index 0000000..16f4ce8
--- /dev/null
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+        </style>
+    </head>
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a blue inverted-L shape and no red.</p>
+        <p>This test sets the mask-image via CSS to a PNG and then changes it to a &lt;mask&gt; element from an SVG file via a script.</p>
+        <svg width="300px" height="400px">
+            <path fill="blue" d="M80,20 L280,20 L280,380 L240,380 L240,60 L80,60 L80,20"/>
+        </svg>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-png-to-mask.html b/LayoutTests/css3/masking/mask-svg-script-png-to-mask.html
new file mode 100644 (file)
index 0000000..43dd32f
--- /dev/null
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 300px;
+                height: 400px;
+                background-color: green;
+                -webkit-mask-image:url('resources/circle.png');
+            }
+            #redSvg {
+                position: absolute;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a blue inverted-L shape and no red.</p>
+        <p>This test sets the mask-image via CSS to a PNG and then changes it to a &lt;mask&gt; element from an SVG file via a script.</p>
+        <svg id="redSvg" width="300px" height="400px">
+            <path fill="red" d="M80,20 L280,20 L280,380 L240,380 L240,60 L80,60 L80,20"/>
+        </svg>
+        <div id="maskedElement"></div>
+
+        <script>
+            var maskedElement = document.getElementById("maskedElement");
+            maskedElement.style.cssText += "-webkit-mask-image:url('resources/masks.svg#upperHalf');background-color: blue";
+        </script>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-png-to-none-expected.html b/LayoutTests/css3/masking/mask-svg-script-png-to-none-expected.html
new file mode 100644 (file)
index 0000000..b4f558c
--- /dev/null
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 280px;
+                height: 210px;
+                background-color: blue;
+            }
+        </style>
+    </head>
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a simple blue rectangle.</p>
+        <p>This test sets the mask-image via CSS to a PNG image and then changes it to 'none' via a script.</p>
+        <div id="maskedElement"></div>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/mask-svg-script-png-to-none.html b/LayoutTests/css3/masking/mask-svg-script-png-to-none.html
new file mode 100644 (file)
index 0000000..9bf07f3
--- /dev/null
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            p {
+                margin: 0px;
+            }
+            #maskedElement {
+                width: 280px;
+                height: 210px;
+                background-color: green;
+                -webkit-mask-image:url('resources/dice.png');
+                -webkit-mask-source-type: luminance;
+            }
+        </style>
+    </head>
+
+    <body>
+        <p><a href="https://bugs.webkit.org/show_bug.cgi?id=129682">Bug 129682</a> - On success, you should see a simple blue rectangle.</p>
+        <p>This test sets the mask-image via CSS to a PNG image and then changes it to 'none' via a script.</p>
+        <div id="maskedElement"></div>
+        <script>
+            var maskedElement = document.getElementById("maskedElement");
+            maskedElement.style.cssText += "-webkit-mask-image:none;background-color: blue";
+        </script>
+    </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/masking/resources/masks.svg b/LayoutTests/css3/masking/resources/masks.svg
new file mode 100644 (file)
index 0000000..5d43705
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363)  -->\r
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+   width="300px" height="400px" viewBox="0 0 300 400" enable-background="new 0 0 300 400" xml:space="preserve">\r
+<defs>\r
+       <mask id="upperHalf" maskUnits="objectBoundingBox">\r
+               <path fill="#FFFFFF" d="M80,20 L280,20 L280,380 L240,380 L240,60 L80,60 L80,20"/>\r
+       </mask>\r
+       <mask id="lowerHalf" maskUnits="objectBoundingBox">\r
+               <path fill="#FFFFFF" d="M20,20 L60,20 L60,340 L220,340 L220,380 L20,380 L20,20"/>\r
+       </mask>\r
+       <mask id="animatedCircle" maskUnits="objectBoundingBox">\r
+               <circle cx="150" cy="150" r="40" fill="white">\r
+                       <animate attributeName="r" from="40" to="120" dur="10s" repeatCount="indefinite"/>\r
+               </circle>\r
+       </mask>\r
+</defs>\r
+\r
+<g>\r
+       <rect x="5px" y="45px" width="140px" height="140px" fill="#C1553B"/>\r
+       <rect x="155px" y="45px" width="140px" height="140px" fill="#71E5FF"/>\r
+       <rect x="155px" y="215px" width="140px" height="140px" fill="#404041"/>\r
+       <rect x="5px" y="215px" width="140px" height="140px" fill="#77D091"/>\r
+</g>\r
+\r
+</svg>
\ No newline at end of file
index 6d264ec..0c7a89d 100644 (file)
@@ -1,3 +1,96 @@
+2014-12-18  Radu Stavila  <stavila@adobe.com>
+
+        [SVG Masking] Enable the use of <mask> elements for -webkit-mask-image
+        https://bugs.webkit.org/show_bug.cgi?id=139294
+
+        Reviewed by Simon Fraser.
+
+        This patch links together all parts required for the functionality which improves 
+        the -webkit-mask-image property by allowing it to reference a <mask> element defined 
+        in an inline or external SVG document.
+        Support for this new functionality has been added in a previous patch, under issue
+        https://bugs.webkit.org/show_bug.cgi?id=139092. A more detailed description of how
+        the new functionality works can be found in the ChangeLog for that commit.
+        The containsSVGDocument in ScrollView has been removed because it was added in the
+        previous patch but is no longer required.
+
+        Tests: css3/masking/mask-base64.html
+               css3/masking/mask-multiple-values.html
+               css3/masking/mask-svg-clipped-fragmentId.html
+               css3/masking/mask-svg-fragmentId.html
+               css3/masking/mask-svg-inline-fragmentId.html
+               css3/masking/mask-svg-inline-invalid-fragmentId.html
+               css3/masking/mask-svg-invalid-fragmentId.html
+               css3/masking/mask-svg-no-fragmentId-tiled.html
+               css3/masking/mask-svg-no-fragmentId.html
+               css3/masking/mask-svg-script-entire-svg-to-mask.html
+               css3/masking/mask-svg-script-mask-to-entire-svg.html
+               css3/masking/mask-svg-script-mask-to-none.html
+               css3/masking/mask-svg-script-mask-to-png.html
+               css3/masking/mask-svg-script-none-to-mask.html
+               css3/masking/mask-svg-script-none-to-png.html
+               css3/masking/mask-svg-script-png-to-mask.html
+               css3/masking/mask-svg-script-png-to-none.html
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::ComputedStyleExtractor::propertyValue):
+        * css/CSSParser.cpp:
+        (WebCore::CSSParser::parseFillShorthand):
+        (WebCore::CSSParser::parseFillProperty):
+        (WebCore::CSSParser::parseMaskImage):
+        * css/CSSParser.h:
+        * css/CSSValue.h:
+        * css/DeprecatedStyleBuilder.cpp:
+        (WebCore::DeprecatedStyleBuilder::DeprecatedStyleBuilder):
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::adjustStyleForMaskImages):
+        (WebCore::StyleResolver::applyMatchedProperties):
+        (WebCore::StyleResolver::applyProperty):
+        (WebCore::StyleResolver::loadPendingSVGDocuments):
+        (WebCore::StyleResolver::createMaskImageOperations):
+        (WebCore::StyleResolver::loadPendingImages):
+        * css/StyleResolver.h:
+        * page/FrameView.cpp:
+        (WebCore::FrameView::containsSVGDocument): Deleted.
+        * page/FrameView.h:
+        * page/animation/CSSPropertyAnimation.cpp:
+        (WebCore::blendFunc):
+        (WebCore::MaskImagePropertyWrapper::MaskImagePropertyWrapper):
+        (WebCore::MaskImagePropertyWrapper::equals):
+        (WebCore::CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap):
+        * platform/ScrollView.h:
+        (WebCore::ScrollView::containsSVGDocument): Deleted.
+        * platform/graphics/MaskImageOperation.cpp:
+        (WebCore::MaskImageOperation::~MaskImageOperation):
+        (WebCore::MaskImageOperation::operator==):
+        * platform/graphics/MaskImageOperation.h:
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::maskClipRect):
+        * rendering/RenderBox.h:
+        * rendering/RenderBoxModelObject.cpp:
+        (WebCore::RenderBoxModelObject::paintFillLayerExtended):
+        (WebCore::RenderBoxModelObject::calculateFillTileSize):
+        (WebCore::RenderBoxModelObject::calculateBackgroundImageGeometry):
+        * rendering/RenderElement.cpp:
+        (WebCore::RenderElement::~RenderElement):
+        (WebCore::RenderElement::updateFillImages):
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::calculateClipRects):
+        * rendering/RenderLayer.h:
+        * rendering/RenderLayerMaskImageInfo.cpp:
+        (WebCore::RenderLayer::MaskImageInfo::~MaskImageInfo):
+        (WebCore::RenderLayer::MaskImageInfo::updateMaskImageClients):
+        (WebCore::RenderLayer::MaskImageInfo::removeMaskImageClients):
+        * rendering/RenderLayerMaskImageInfo.h:
+        * rendering/style/FillLayer.cpp:
+        (WebCore::FillLayer::hasImage):
+        * rendering/style/FillLayer.h:
+        (WebCore::FillLayer::image):
+        (WebCore::FillLayer::imageOrMaskImage): Deleted.
+        * rendering/style/RenderStyle.cpp:
+        (WebCore::RenderStyle::setMaskImage):
+        * rendering/style/RenderStyle.h:
+
 2014-12-18  Antti Koivisto  <antti@apple.com>
 
         Stop returning GlyphPage from various Font functions
index a6872ff..3bc4f2f 100644 (file)
@@ -1793,9 +1793,8 @@ PassRefPtr<CSSValue> ComputedStyleExtractor::propertyValue(CSSPropertyID propert
 
         case CSSPropertyBackgroundColor:
             return cssValuePool().createColorValue(m_allowVisitedStyle? style->visitedDependentColor(CSSPropertyBackgroundColor).rgb() : style->backgroundColor().rgb());
-        case CSSPropertyBackgroundImage:
-        case CSSPropertyWebkitMaskImage: {
-            const FillLayer* layers = propertyID == CSSPropertyWebkitMaskImage ? style->maskLayers() : style->backgroundLayers();
+        case CSSPropertyBackgroundImage: {
+            const FillLayer* layers = style->backgroundLayers();
             if (!layers)
                 return cssValuePool().createIdentifierValue(CSSValueNone);
 
@@ -1815,6 +1814,27 @@ PassRefPtr<CSSValue> ComputedStyleExtractor::propertyValue(CSSPropertyID propert
             }
             return list.release();
         }
+        case CSSPropertyWebkitMaskImage: {
+            const FillLayer* layers = style->maskLayers();
+            if (!layers)
+                return cssValuePool().createIdentifierValue(CSSValueNone);
+
+            if (!layers->next()) {
+                if (layers->maskImage().get())
+                    return layers->maskImage()->cssValue();
+
+                return cssValuePool().createIdentifierValue(CSSValueNone);
+            }
+
+            RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
+            for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) {
+                if (currLayer->maskImage().get())
+                    list->append(*currLayer->maskImage()->cssValue());
+                else
+                    list->append(cssValuePool().createIdentifierValue(CSSValueNone));
+            }
+            return list.release();
+        }
         case CSSPropertyBackgroundSize:
         case CSSPropertyWebkitBackgroundSize:
         case CSSPropertyWebkitMaskSize: {
index 7552a71..52fb722 100644 (file)
@@ -83,6 +83,7 @@
 #include "TextEncoding.h"
 #include "WebKitCSSFilterValue.h"
 #include "WebKitCSSRegionRule.h"
+#include "WebKitCSSResourceValue.h"
 #include "WebKitCSSTransformValue.h"
 #include <bitset>
 #include <limits.h>
@@ -3358,6 +3359,7 @@ bool CSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* pr
                 RefPtr<CSSValue> val2;
                 CSSPropertyID propId1, propId2;
                 CSSParserValue& parserValue = *m_valueList->current();
+
                 if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
                     parsedProperty[i] = found = true;
                     addFillValue(values[i], val1.releaseNonNull());
@@ -4446,10 +4448,13 @@ bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1,
                     }
                     break;
                 case CSSPropertyBackgroundImage:
-                case CSSPropertyWebkitMaskImage:
                     if (parseFillImage(*m_valueList, currValue))
                         m_valueList->next();
                     break;
+                case CSSPropertyWebkitMaskImage:
+                    if (parseMaskImage(*m_valueList, currValue))
+                        m_valueList->next();
+                    break;
                 case CSSPropertyWebkitBackgroundClip:
                 case CSSPropertyWebkitBackgroundOrigin:
                 case CSSPropertyWebkitMaskClip:
@@ -9427,6 +9432,23 @@ bool CSSParser::parseFilter(CSSParserValueList& valueList, RefPtr<CSSValue>& res
     return true;
 }
 
+bool CSSParser::parseMaskImage(CSSParserValueList& valueList, RefPtr<CSSValue>& outValue)
+{
+    outValue = nullptr;
+    CSSParserValue* value = valueList.current();
+    if (value->id == CSSValueNone)
+        outValue = WebKitCSSResourceValue::create(cssValuePool().createIdentifierValue(CSSValueNone));
+    else if (value->unit == CSSPrimitiveValue::CSS_URI)
+        outValue = WebKitCSSResourceValue::create(CSSPrimitiveValue::create(completeURL(value->string), CSSPrimitiveValue::CSS_URI));
+    else {
+        RefPtr<CSSValue> fillImageValue;
+        if (parseFillImage(valueList, fillImageValue))
+            outValue = WebKitCSSResourceValue::create(fillImageValue);
+    }
+
+    return outValue.get();
+}
+
 #if ENABLE(CSS_REGIONS)
 static bool validFlowName(const String& flowName)
 {
index 9ec7a96..2988a6a 100644 (file)
@@ -117,6 +117,8 @@ public:
 
     PassRefPtr<CSSValue> parseBackgroundColor();
 
+    // FIXME: Maybe these two methods could be combined into one.
+    bool parseMaskImage(CSSParserValueList&, RefPtr<CSSValue>&);
     bool parseFillImage(CSSParserValueList&, RefPtr<CSSValue>&);
 
     enum FillPositionFlag { InvalidFillPosition = 0, AmbiguousFillPosition = 1, XFillPosition = 2, YFillPosition = 4 };
index 36c2994..632ef9a 100644 (file)
@@ -163,6 +163,7 @@ protected:
 #endif
         SVGColorClass,
         SVGPaintClass,
+        WebKitCSSResourceClass,
 
         // List class types must appear after ValueListClass.
         ValueListClass,
@@ -174,7 +175,6 @@ protected:
 #if ENABLE(CSS_GRID_LAYOUT)
         GridLineNamesClass,
 #endif
-        WebKitCSSResourceClass
 
         // Do not append non-list class types here.
     };
index c27ba8a..66cfea9 100644 (file)
@@ -758,7 +758,6 @@ DeprecatedStyleBuilder::DeprecatedStyleBuilder()
     setPropertyHandler(CSSPropertyWebkitFontVariantLigatures, ApplyPropertyFontVariantLigatures::createHandler());
     setPropertyHandler(CSSPropertyWebkitMaskClip, ApplyPropertyFillLayer<EFillBox, CSSPropertyWebkitMaskClip, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, &FillLayer::isClipSet, &FillLayer::clip, &FillLayer::setClip, &FillLayer::clearClip, &FillLayer::initialFillClip, &CSSToStyleMap::mapFillClip>::createHandler());
     setPropertyHandler(CSSPropertyWebkitMaskComposite, ApplyPropertyFillLayer<CompositeOperator, CSSPropertyWebkitMaskComposite, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, &FillLayer::isCompositeSet, &FillLayer::composite, &FillLayer::setComposite, &FillLayer::clearComposite, &FillLayer::initialFillComposite, &CSSToStyleMap::mapFillComposite>::createHandler());
-    setPropertyHandler(CSSPropertyWebkitMaskImage, ApplyPropertyFillLayer<StyleImage*, CSSPropertyWebkitMaskImage, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, &FillLayer::isImageSet, &FillLayer::image, &FillLayer::setImage, &FillLayer::clearImage, &FillLayer::initialFillImage, &CSSToStyleMap::mapFillImage>::createHandler());
     setPropertyHandler(CSSPropertyWebkitMaskOrigin, ApplyPropertyFillLayer<EFillBox, CSSPropertyWebkitMaskOrigin, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, &FillLayer::isOriginSet, &FillLayer::origin, &FillLayer::setOrigin, &FillLayer::clearOrigin, &FillLayer::initialFillOrigin, &CSSToStyleMap::mapFillOrigin>::createHandler());
     setPropertyHandler(CSSPropertyWebkitMaskPositionX, ApplyPropertyFillLayer<Length, CSSPropertyWebkitMaskPositionX, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, &FillLayer::isXPositionSet, &FillLayer::xPosition, &FillLayer::setXPosition, &FillLayer::clearXPosition, &FillLayer::initialFillXPosition, &CSSToStyleMap::mapFillXPosition>::createHandler());
     setPropertyHandler(CSSPropertyWebkitMaskPositionY, ApplyPropertyFillLayer<Length, CSSPropertyWebkitMaskPositionY, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, &FillLayer::isYPositionSet, &FillLayer::yPosition, &FillLayer::setYPosition, &FillLayer::clearYPosition, &FillLayer::initialFillYPosition, &CSSToStyleMap::mapFillYPosition>::createHandler());
index fb7551f..c0913bc 100644 (file)
@@ -1157,6 +1157,61 @@ void StyleResolver::adjustStyleForInterCharacterRuby()
         style->setWritingMode(LeftToRightWritingMode);
 }
 
+void StyleResolver::adjustStyleForMaskImages()
+{
+    // If we already have the same mask image objects loaded on the old style,
+    // use the old ones instead of loading new ones.
+    RenderStyle* newStyle = m_state.style();
+    RenderStyle* oldStyle = (m_state.element() ? m_state.element()->renderStyle() : nullptr);
+
+    if (newStyle && oldStyle) {
+        Vector<RefPtr<MaskImageOperation>> removedExternalResources;
+        
+        // Get all mask objects from the old style in a vector
+        // so we can remove them as we match them, making the following steps faster.
+        Vector<RefPtr<MaskImageOperation>> oldStyleMaskImages;
+        const FillLayer* oldMaskLayer = oldStyle->maskLayers();
+        while (oldMaskLayer) {
+            RefPtr<MaskImageOperation> oldMaskImage = oldMaskLayer->maskImage();
+            if (oldMaskImage.get())
+                oldStyleMaskImages.append(oldMaskImage);
+
+            oldMaskLayer = oldMaskLayer->next();
+        }
+        
+        // Try to match the new mask objects through the list from the old style.
+        // This should work perfectly and optimal when the list of masks remained
+        // the same and also work correctly (but slower) when they were reordered.
+        FillLayer* newMaskLayer = newStyle->accessMaskLayers();
+        int countOldStyleMaskImages = oldStyleMaskImages.size();
+        while (newMaskLayer && countOldStyleMaskImages) {
+            RefPtr<MaskImageOperation> newMaskImage = newMaskLayer->maskImage();
+            if (newMaskImage.get()) {
+                for (int i = 0; i < countOldStyleMaskImages; i++) {
+                    RefPtr<MaskImageOperation> oldMaskImage = oldStyleMaskImages[i];
+                    if (*oldMaskImage == *newMaskImage) {
+                        newMaskLayer->setMaskImage(oldMaskImage);
+                        if (newMaskImage->isExternalDocument())
+                            removedExternalResources.append(newMaskImage);
+
+                        oldStyleMaskImages.remove(i);
+                        countOldStyleMaskImages--;
+                        break;
+                    }
+                }
+            }
+
+            newMaskLayer = newMaskLayer->next();
+        }
+
+        Vector<RefPtr<MaskImageOperation>>& pendingResources = m_state.maskImagesWithPendingSVGDocuments();
+        for (int i = pendingResources.size() - 1; i >= 0; i--) {
+            if (removedExternalResources.contains(pendingResources[i]))
+                pendingResources.remove(i);
+        }
+    }
+}
+
 void StyleResolver::adjustRenderStyle(RenderStyle& style, const RenderStyle& parentStyle, Element *e)
 {
     // Cache our original display.
@@ -1763,6 +1818,8 @@ void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const
     // There are some CSS properties that affect the same RenderStyle values,
     // so to preserve behavior, we queue them up during cascade and flush here.
     cascade.applyDeferredProperties(*this);
+    
+    adjustStyleForMaskImages();
 
     // Start loading resources referenced by this style.
     loadPendingResources();
@@ -2540,6 +2597,14 @@ void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value)
     }
 #endif
 
+    case CSSPropertyWebkitMaskImage: {
+        Vector<RefPtr<MaskImageOperation>> operations;
+        if (createMaskImageOperations(value, operations))
+            state.style()->setMaskImage(operations);
+
+        return;
+    }
+
 #if ENABLE(CSS_GRID_LAYOUT)
     case CSSPropertyWebkitGridAutoColumns: {
         HANDLE_INHERIT_AND_INITIAL(gridAutoColumns, GridAutoColumns);
@@ -2966,7 +3031,6 @@ void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value)
     case CSSPropertyWebkitMaskBoxImageWidth:
     case CSSPropertyWebkitMaskClip:
     case CSSPropertyWebkitMaskComposite:
-    case CSSPropertyWebkitMaskImage:
     case CSSPropertyWebkitMaskOrigin:
     case CSSPropertyWebkitMaskPositionX:
     case CSSPropertyWebkitMaskPositionY:
@@ -3317,14 +3381,30 @@ void StyleResolver::loadPendingSVGDocuments()
     // style is NULL. We don't know exactly why this happens. Our guess is
     // reentering styleForElement().
     ASSERT(state.style());
-    if (!state.style() || !state.style()->hasFilter() || state.filtersWithPendingSVGDocuments().isEmpty())
+    if (!state.style())
+        return;
+    
+    bool hasFilters = (state.style()->hasFilter() && !state.filtersWithPendingSVGDocuments().isEmpty());
+    bool hasMasks = (state.style()->hasMask() && !state.maskImagesWithPendingSVGDocuments().isEmpty());
+    
+    if (!hasFilters && !hasMasks)
         return;
 
     CachedResourceLoader* cachedResourceLoader = state.document().cachedResourceLoader();
-    for (auto& filterOperation : state.filtersWithPendingSVGDocuments())
-        filterOperation->getOrCreateCachedSVGDocumentReference()->load(cachedResourceLoader);
+    
+    if (hasFilters) {
+        for (auto& filterOperation : state.filtersWithPendingSVGDocuments())
+            filterOperation->getOrCreateCachedSVGDocumentReference()->load(cachedResourceLoader);
 
-    state.filtersWithPendingSVGDocuments().clear();
+        state.filtersWithPendingSVGDocuments().clear();
+    }
+    
+    if (hasMasks) {
+        for (auto& maskImageOperation : state.maskImagesWithPendingSVGDocuments())
+            maskImageOperation->ensureCachedSVGDocumentReference()->load(cachedResourceLoader);
+
+        state.maskImagesWithPendingSVGDocuments().clear();
+    }
 }
 
 bool StyleResolver::createFilterOperations(CSSValue* inValue, FilterOperations& outOperations)
@@ -3472,16 +3552,22 @@ bool StyleResolver::createMaskImageOperations(CSSValue* inValue, Vector<RefPtr<M
     if (!inValue)
         return false;
 
-    ASSERT(is<CSSValueList>(*inValue));
+    RefPtr<WebKitCSSResourceValue> maskImageValue;
+    RefPtr<CSSValueList> maskImagesList;
+    CSSValueList::iterator listIterator;
+    if (is<WebKitCSSResourceValue>(*inValue))
+        maskImageValue = downcast<WebKitCSSResourceValue>(inValue);
+    else if (is<CSSValueList>(*inValue)) {
+        maskImagesList = downcast<CSSValueList>(inValue);
+        listIterator = maskImagesList->begin();
+        if (listIterator != maskImagesList->end())
+            maskImageValue = &downcast<WebKitCSSResourceValue>(listIterator->get());
+    }
 
-    for (auto& currValue : downcast<CSSValueList>(*inValue)) {
-        if (!is<WebKitCSSResourceValue>(currValue.get()))
-            continue;
-        
-        WebKitCSSResourceValue& maskImageValue = downcast<WebKitCSSResourceValue>(currValue.get());
-        RefPtr<CSSValue> maskInnerValue = maskImageValue.innerValue();
+    while (maskImageValue.get()) {
+        RefPtr<CSSValue> maskInnerValue = maskImageValue->innerValue();
         RefPtr<MaskImageOperation> newMaskImage;
-        
+
         if (is<CSSPrimitiveValue>(maskInnerValue.get())) {
             RefPtr<CSSPrimitiveValue> primitiveValue = downcast<CSSPrimitiveValue>(maskInnerValue.get());
             if (primitiveValue->isValueID() && primitiveValue->getValueID() == CSSValueNone)
@@ -3491,7 +3577,7 @@ bool StyleResolver::createMaskImageOperations(CSSValue* inValue, Vector<RefPtr<M
                 URL url = m_state.document().completeURL(cssUrl);
                 
                 bool isExternalDocument = (SVGURIReference::isExternalURIReference(cssUrl, m_state.document()));
-                newMaskImage = MaskImageOperation::create(&maskImageValue, cssUrl, url.fragmentIdentifier(), isExternalDocument, m_state.document().cachedResourceLoader());
+                newMaskImage = MaskImageOperation::create(maskImageValue, cssUrl, url.fragmentIdentifier(), isExternalDocument, m_state.document().cachedResourceLoader());
                 if (isExternalDocument)
                     m_state.maskImagesWithPendingSVGDocuments().append(newMaskImage);
             }
@@ -3506,6 +3592,12 @@ bool StyleResolver::createMaskImageOperations(CSSValue* inValue, Vector<RefPtr<M
             newMaskImage = MaskImageOperation::create();
 
         outOperations.append(newMaskImage);
+
+        if (maskImagesList.get()) {
+            listIterator++;
+            maskImageValue = (listIterator != maskImagesList->end() ? &downcast<WebKitCSSResourceValue>(listIterator->get()) : nullptr);
+        } else
+            maskImageValue = nullptr;
     }
 
     return true;
@@ -3629,9 +3721,10 @@ void StyleResolver::loadPendingImages()
         }
         case CSSPropertyWebkitMaskImage: {
             for (FillLayer* maskLayer = m_state.style()->accessMaskLayers(); maskLayer; maskLayer = maskLayer->next()) {
-                auto* styleImage = maskLayer->image();
+                RefPtr<MaskImageOperation> maskImage = maskLayer->maskImage();
+                auto* styleImage = maskImage.get() ? maskImage->image() : nullptr;
                 if (is<StylePendingImage>(styleImage))
-                    maskLayer->setImage(loadPendingImage(downcast<StylePendingImage>(*styleImage)));
+                    maskImage->setImage(loadPendingImage(downcast<StylePendingImage>(*styleImage)));
             }
             break;
         }
index d6083d5..d88678e 100644 (file)
@@ -301,6 +301,7 @@ private:
 #endif
     
     void adjustStyleForInterCharacterRuby();
+    void adjustStyleForMaskImages();
     
     bool fastRejectSelector(const RuleData&) const;
 
index 1106540..09cab8d 100644 (file)
@@ -4393,14 +4393,6 @@ bool FrameView::isFlippedDocument() const
     return renderView->style().isFlippedBlocksWritingMode();
 }
 
-bool FrameView::containsSVGDocument() const
-{
-    if (frame().document())
-        return frame().document()->isSVGDocument();
-    
-    return false;
-}
-
 void FrameView::notifyWidgetsInAllFrames(WidgetNotification notification)
 {
     for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
index 97f5c37..3661e70 100644 (file)
@@ -527,7 +527,6 @@ protected:
 
     virtual bool isVerticalDocument() const override;
     virtual bool isFlippedDocument() const override;
-    virtual bool containsSVGDocument() const override;
 
 private:
     explicit FrameView(Frame&);
index a977adb..354354f 100644 (file)
@@ -42,6 +42,7 @@
 #include "ClipPathOperation.h"
 #include "FloatConversion.h"
 #include "IdentityTransformOperation.h"
+#include "MaskImageOperation.h"
 #include "Matrix3DTransformOperation.h"
 #include "MatrixTransformOperation.h"
 #include "RenderBox.h"
@@ -341,6 +342,19 @@ static inline PassRefPtr<StyleImage> blendFunc(const AnimationBase* anim, StyleI
     return to;
 }
 
+static inline PassRefPtr<MaskImageOperation> blendFunc(const AnimationBase* anim, const RefPtr<MaskImageOperation> from, const RefPtr<MaskImageOperation> to, double progress)
+{
+    if (!from.get() || !to.get())
+        return to;
+
+    // Only animates between masks using images (PNG, entire SVG, generated image).
+    // It does not animate between <mask> elements (file.svg#identifier).
+    if (from->image() && to->image())
+        return MaskImageOperation::create(blendFunc(anim, from->image(), to->image(), progress));
+
+    return to;
+}
+
 static inline NinePieceImage blendFunc(const AnimationBase* anim, const NinePieceImage& from, const NinePieceImage& to, double progress)
 {
     if (!from.hasImage() || !to.hasImage())
@@ -500,6 +514,30 @@ public:
     }
 };
 
+class MaskImagePropertyWrapper : public PropertyWrapper<const RefPtr<MaskImageOperation>> {
+public:
+    MaskImagePropertyWrapper()
+        : PropertyWrapper<const RefPtr<MaskImageOperation>>(CSSPropertyWebkitMaskImage, &RenderStyle::maskImage, &RenderStyle::setMaskImage)
+    {
+    }
+    
+    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+    {
+        // If the style pointers are the same, don't bother doing the test.
+        // If either is null, return false. If both are null, return true.
+        if (a == b)
+            return true;
+        if (!a || !b)
+            return false;
+        
+        const RefPtr<MaskImageOperation> maskImageA = (a->*m_getter)();
+        const RefPtr<MaskImageOperation> maskImageB = (b->*m_getter)();
+        StyleImage* styleImageA = (maskImageA ? maskImageA->image() : nullptr);
+        StyleImage* styleImageB = (maskImageB ? maskImageB->image() : nullptr);
+        return StyleImage::imagesEquivalent(styleImageA, styleImageB);
+    }
+};
+
 class PropertyWrapperColor : public PropertyWrapperGetter<Color> {
 public:
     PropertyWrapperColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
@@ -1152,7 +1190,7 @@ CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap()
 
         new FillLayersPropertyWrapper(CSSPropertyBackgroundImage, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers),
         new StyleImagePropertyWrapper(CSSPropertyListStyleImage, &RenderStyle::listStyleImage, &RenderStyle::setListStyleImage),
-        new StyleImagePropertyWrapper(CSSPropertyWebkitMaskImage, &RenderStyle::maskImage, &RenderStyle::setMaskImage),
+        new MaskImagePropertyWrapper(),
 
         new StyleImagePropertyWrapper(CSSPropertyBorderImageSource, &RenderStyle::borderImageSource, &RenderStyle::setBorderImageSource),
         new LengthPropertyWrapper<LengthBox>(CSSPropertyBorderImageSlice, &RenderStyle::borderImageSlices, &RenderStyle::setBorderImageSlices),
index 55116fe..c250924 100644 (file)
@@ -410,7 +410,6 @@ protected:
     // Subclassed by FrameView to check the writing-mode of the document.
     virtual bool isVerticalDocument() const { return true; }
     virtual bool isFlippedDocument() const { return false; }
-    virtual bool containsSVGDocument() const { return false; }
 
     // Called to update the scrollbars to accurately reflect the state of the view.
     void updateScrollbars(const IntSize& desiredOffset);
index 67af85c..4a7acd8 100644 (file)
@@ -82,6 +82,15 @@ MaskImageOperation::MaskImageOperation()
 
 MaskImageOperation::~MaskImageOperation()
 {
+    setRenderLayerImageClient(nullptr);
+}
+
+bool MaskImageOperation::operator==(const MaskImageOperation& other) const
+{
+    if (m_url.length())
+        return (m_url == other.m_url && m_fragment == other.m_fragment && m_isExternalDocument == other.m_isExternalDocument);
+
+    return m_styleImage.get() == other.m_styleImage.get();
 }
 
 bool MaskImageOperation::isCSSValueNone() const
index 48753bd..6ea6079 100644 (file)
@@ -57,9 +57,13 @@ public:
     PassRefPtr<CSSValue> cssValue();
 
     virtual ~MaskImageOperation();
+    
+    bool operator==(const MaskImageOperation&) const;
+    inline bool operator!=(const MaskImageOperation& other) const { return !operator==(other); }
 
     const String& url() const { return m_url; }
     const String& fragment() const { return m_fragment; }
+    bool isExternalDocument() const { return m_isExternalDocument; }
     StyleImage* image() const { return m_styleImage.get(); }
     void setImage(PassRefPtr<StyleImage> image) { m_styleImage = image; }
     void setRenderLayerImageClient(CachedImageClient*);
index 29c2b92..f464310 100644 (file)
@@ -1530,7 +1530,7 @@ LayoutRect RenderBox::maskClipRect()
     LayoutRect result;
     LayoutRect borderBox = borderBoxRect();
     for (const FillLayer* maskLayer = style().maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
-        if (maskLayer->image()) {
+        if (maskLayer->maskImage()) {
             BackgroundImageGeometry geometry;
             // Masks should never have fixed attachment, so it's OK for paintContainer to be null.
             calculateBackgroundImageGeometry(0, maskLayer, borderBox, geometry);
index f06c803..b548de9 100644 (file)
@@ -175,6 +175,9 @@ public:
     // Bounds of the outline box in absolute coords. Respects transforms
     virtual LayoutRect outlineBoundsForRepaint(const RenderLayerModelObject* /*repaintContainer*/, const RenderGeometryMap*) const override final;
     virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) override;
+    
+    virtual FloatRect repaintRectInLocalCoordinates() const override { return borderBoxRect(); }
+    virtual FloatRect objectBoundingBox() const override { return borderBoxRect(); }
 
     // Use this with caution! No type checking is done!
     RenderBox* previousSiblingBox() const;
index d38ec1f..ddde6e5 100644 (file)
@@ -27,6 +27,8 @@
 #include "RenderBoxModelObject.h"
 
 #include "BorderEdge.h"
+#include "CachedImage.h"
+#include "CachedSVGDocument.h"
 #include "FloatRoundedRect.h"
 #include "Frame.h"
 #include "FrameView.h"
 #include "RenderNamedFlowFragment.h"
 #include "RenderNamedFlowThread.h"
 #include "RenderRegion.h"
+#include "RenderSVGResourceMasker.h"
 #include "RenderTable.h"
 #include "RenderTableRow.h"
 #include "RenderText.h"
 #include "RenderTextFragment.h"
 #include "RenderView.h"
+#include "SVGImageForContainer.h"
+#include "SVGSVGElement.h"
 #include "ScrollingConstraints.h"
 #include "Settings.h"
+#include "StyleCachedImage.h"
 #include "TransformState.h"
 #include <wtf/NeverDestroyed.h>
 
@@ -676,7 +682,7 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co
     FloatRect pixelSnappedRect = snapRectToDevicePixels(rect, deviceScaleFactor);
 
     // Fast path for drawing simple color backgrounds.
-    if (!isRoot && !clippedWithLocalScrolling && !shouldPaintBackgroundImage && isBorderFill && !bgLayer->next()) {
+    if (!isRoot && !clippedWithLocalScrolling && !shouldPaintBackgroundImage && isBorderFill && !bgLayer->hasMaskImage() && !bgLayer->next()) {
         if (!colorVisible)
             return;
 
@@ -837,19 +843,26 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co
     }
 
     // no progressive loading of the background image
-    if (!baseBgColorOnly && shouldPaintBackgroundImage) {
+    if (!baseBgColorOnly && (shouldPaintBackgroundImage || bgLayer->hasMaskImage())) {
         BackgroundImageGeometry geometry;
         calculateBackgroundImageGeometry(paintInfo.paintContainer, bgLayer, scrolledPaintRect, geometry, backgroundObject);
         geometry.clip(LayoutRect(pixelSnappedRect));
+
         if (!geometry.destRect().isEmpty()) {
+            bool didPaintCustomMask = false;
             CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op;
             auto clientForBackgroundImage = backgroundObject ? backgroundObject : this;
-            RefPtr<Image> image = bgImage->image(clientForBackgroundImage, geometry.tileSize());
-            context->setDrawLuminanceMask(bgLayer->maskSourceType() == MaskLuminance);
-            bool useLowQualityScaling = shouldPaintAtLowQuality(context, image.get(), bgLayer, geometry.tileSize());
-            if (image.get())
-                image->setSpaceSize(geometry.spaceSize());
-            context->drawTiledImage(image.get(), style().colorSpace(), geometry.destRect(), geometry.relativePhase(), geometry.tileSize(), ImagePaintingOptions(compositeOp, bgLayer->blendMode(), ImageOrientationDescription(), useLowQualityScaling));
+            RefPtr<Image> image = (bgImage ? bgImage->image(clientForBackgroundImage, geometry.tileSize()) : nullptr);
+            if (!image.get() && bgLayer->hasMaskImage())
+                didPaintCustomMask = bgLayer->maskImage()->drawMask(*this, geometry, context, compositeOp);
+
+            if (!didPaintCustomMask && shouldPaintBackgroundImage) {
+                context->setDrawLuminanceMask(bgLayer->maskSourceType() == MaskLuminance);
+                bool useLowQualityScaling = shouldPaintAtLowQuality(context, image.get(), bgLayer, geometry.tileSize());
+                if (image.get())
+                    image->setSpaceSize(geometry.spaceSize());
+                context->drawTiledImage(image.get(), style().colorSpace(), geometry.destRect(), geometry.relativePhase(), geometry.tileSize(), ImagePaintingOptions(compositeOp, bgLayer->blendMode(), ImageOrientationDescription(), useLowQualityScaling));
+            }
         }
     }
 
@@ -954,8 +967,13 @@ LayoutSize RenderBoxModelObject::calculateFillTileSize(const FillLayer* fillLaye
     StyleImage* image = fillLayer->image();
     EFillSizeType type = fillLayer->size().type;
 
-    LayoutSize imageIntrinsicSize = calculateImageIntrinsicDimensions(image, positioningAreaSize, ScaleByEffectiveZoom);
-    imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScaleFactor());
+    LayoutSize imageIntrinsicSize;
+    if (image) {
+        imageIntrinsicSize = calculateImageIntrinsicDimensions(image, positioningAreaSize, ScaleByEffectiveZoom);
+        imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScaleFactor());
+    } else
+        imageIntrinsicSize = positioningAreaSize;
+
     switch (type) {
         case SizeLength: {
             LayoutSize tileSize = positioningAreaSize;
@@ -1151,7 +1169,9 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const RenderLayerMod
 
     auto clientForBackgroundImage = backgroundObject ? backgroundObject : this;
     LayoutSize fillTileSize = calculateFillTileSize(fillLayer, positioningAreaSize);
-    fillLayer->image()->setContainerSizeForRenderer(clientForBackgroundImage, fillTileSize, style().effectiveZoom());
+    if (StyleImage* layerImage = fillLayer->image())
+        layerImage->setContainerSizeForRenderer(clientForBackgroundImage, fillTileSize, style().effectiveZoom());
+    
     geometry.setTileSize(fillTileSize);
 
     EFillRepeat backgroundRepeatX = fillLayer->repeatX();
index 693fd64..225a109 100644 (file)
@@ -118,6 +118,8 @@ RenderElement::~RenderElement()
         for (const FillLayer* maskLayer = m_style->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
             if (StyleImage* maskImage = maskLayer->image())
                 maskImage->removeClient(this);
+            else if (maskLayer->maskImage().get())
+                maskLayer->maskImage()->removeRendererImageClient(this);
         }
 
         if (StyleImage* borderImage = m_style->borderImage().image())
@@ -323,18 +325,22 @@ inline bool RenderElement::shouldRepaintForStyleDifference(StyleDifference diff)
 void RenderElement::updateFillImages(const FillLayer* oldLayers, const FillLayer* newLayers)
 {
     // Optimize the common case
-    if (oldLayers && !oldLayers->next() && newLayers && !newLayers->next() && (oldLayers->image() == newLayers->image()))
+    if (oldLayers && !oldLayers->next() && newLayers && !newLayers->next() && oldLayers->image() == newLayers->image() && oldLayers->maskImage() == newLayers->maskImage())
         return;
     
     // Go through the new layers and addClients first, to avoid removing all clients of an image.
     for (const FillLayer* currNew = newLayers; currNew; currNew = currNew->next()) {
-        if (currNew->image())
-            currNew->image()->addClient(this);
+        if (StyleImage* image = currNew->image())
+            image->addClient(this);
+        else if (currNew->maskImage().get())
+            currNew->maskImage()->addRendererImageClient(this);
     }
 
     for (const FillLayer* currOld = oldLayers; currOld; currOld = currOld->next()) {
-        if (currOld->image())
-            currOld->image()->removeClient(this);
+        if (StyleImage* image = currOld->image())
+            image->removeClient(this);
+        else if (currOld->maskImage().get())
+            currOld->maskImage()->removeRendererImageClient(this);
     }
 }
 
index ff509e6..9025574 100644 (file)
@@ -6502,6 +6502,7 @@ void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle
     updateBlendMode();
 #endif
     updateOrRemoveFilterClients();
+    updateOrRemoveMaskImageClients(oldStyle);
 
     updateNeedsCompositedScrolling();
 
@@ -6656,6 +6657,19 @@ void RenderLayer::updateOrRemoveFilterClients()
         filterInfo->removeReferenceFilterClients();
 }
 
+void RenderLayer::updateOrRemoveMaskImageClients(const RenderStyle* oldStyle)
+{
+    if (oldStyle && oldStyle->maskImage().get()) {
+        if (MaskImageInfo* maskImageInfo = MaskImageInfo::getIfExists(*this))
+            maskImageInfo->removeMaskImageClients(*oldStyle);
+    }
+
+    if (renderer().style().maskImage().get())
+        MaskImageInfo::get(*this).updateMaskImageClients();
+    else if (MaskImageInfo* maskImageInfo = MaskImageInfo::getIfExists(*this))
+        maskImageInfo->removeMaskImageClients(renderer().style());
+}
+
 void RenderLayer::updateOrRemoveFilterEffectRenderer()
 {
     // FilterEffectRenderer is only used to render the filters in software mode,
index 3f11909..22630a2 100644 (file)
@@ -1127,6 +1127,8 @@ private:
     void updateOrRemoveFilterClients();
     void updateOrRemoveFilterEffectRenderer();
 
+    void updateOrRemoveMaskImageClients(const RenderStyle* oldStyle);
+
 #if ENABLE(CSS_COMPOSITING)
     void updateAncestorChainHasBlendingDescendants();
     void dirtyAncestorChainHasBlendingDescendants();
index a77fe08..51126e8 100644 (file)
@@ -77,7 +77,7 @@ RenderLayer::MaskImageInfo::MaskImageInfo(RenderLayer& layer)
 
 RenderLayer::MaskImageInfo::~MaskImageInfo()
 {
-    removeMaskImageClients();
+    removeMaskImageClients(m_layer.renderer().style());
 }
 
 void RenderLayer::MaskImageInfo::notifyFinished(CachedResource*)
@@ -92,7 +92,7 @@ void RenderLayer::MaskImageInfo::imageChanged(CachedImage*, const IntRect*)
 
 void RenderLayer::MaskImageInfo::updateMaskImageClients()
 {
-    removeMaskImageClients();
+    removeMaskImageClients(m_layer.renderer().style());
     
     const FillLayer* maskLayer = m_layer.renderer().style().maskLayers();
     while (maskLayer) {
@@ -119,9 +119,9 @@ void RenderLayer::MaskImageInfo::updateMaskImageClients()
     }
 }
 
-void RenderLayer::MaskImageInfo::removeMaskImageClients()
+void RenderLayer::MaskImageInfo::removeMaskImageClients(const RenderStyle& oldStyle)
 {
-    const FillLayer* maskLayer = m_layer.renderer().style().maskLayers();
+    const FillLayer* maskLayer = oldStyle.maskLayers();
     while (maskLayer) {
         if (maskLayer->maskImage())
             maskLayer->maskImage()->setRenderLayerImageClient(nullptr);
index 1d5079f..e70279d 100644 (file)
@@ -80,7 +80,7 @@ public:
     ~MaskImageInfo();
 
     void updateMaskImageClients();
-    void removeMaskImageClients();
+    void removeMaskImageClients(const RenderStyle& oldStyle);
 
 private:
     friend void WTF::deleteOwnedPtr<MaskImageInfo>(MaskImageInfo*);
index 82d9365..555e028 100644 (file)
@@ -378,7 +378,7 @@ bool FillLayer::hasRepeatXY() const
 bool FillLayer::hasImage() const
 {
     for (auto* layer = this; layer; layer = layer->m_next.get()) {
-        if (layer->m_image)
+        if (layer->image())
             return true;
     }
     return false;
index df4487a..a6385a2 100644 (file)
@@ -68,9 +68,8 @@ public:
     explicit FillLayer(EFillLayerType);
     ~FillLayer();
 
+    StyleImage* image() const { return hasMaskImage() ? maskImage()->image() : m_image.get(); }
     const RefPtr<MaskImageOperation>& maskImage() const { return m_maskImageOperation; }
-    StyleImage* image() const { return m_image.get(); }
-    StyleImage* imageOrMaskImage() const { return hasMaskImage() ? maskImage()->image() : image(); }
     const Length& xPosition() const { return m_xPosition; }
     const Length& yPosition() const { return m_yPosition; }
     BackgroundEdgeOrigin backgroundXOrigin() const { return static_cast<BackgroundEdgeOrigin>(m_backgroundXOrigin); }
@@ -182,6 +181,8 @@ private:
 
     std::unique_ptr<FillLayer> m_next;
 
+    // FIXME: A FillLayer will always have at least one of these pointers null.
+    // Maybe we could group them together somehow and decrease the size of FillLayer.
     RefPtr<MaskImageOperation> m_maskImageOperation;
     RefPtr<StyleImage> m_image;
 
index 8e58109..56ecdb7 100644 (file)
@@ -830,6 +830,28 @@ bool RenderStyle::diffRequiresLayerRepaint(const RenderStyle& style, bool isComp
 
     return false;
 }
+    
+void RenderStyle::setMaskImage(const Vector<RefPtr<MaskImageOperation>>& ops)
+{
+    FillLayer* curLayer = &rareNonInheritedData.access()->m_mask;
+    while (curLayer) {
+        curLayer->setMaskImage(nullptr);
+        curLayer = curLayer->next();
+    }
+
+    curLayer = &rareNonInheritedData.access()->m_mask;
+    FillLayer* prevLayer = nullptr;
+    for (auto& maskImage : ops) {
+        if (!curLayer) {
+            prevLayer->setNext(std::make_unique<FillLayer>(MaskFillLayer));
+            curLayer = prevLayer->next();
+        }
+
+        curLayer->setMaskImage(maskImage);
+        prevLayer = curLayer;
+        curLayer = curLayer->next();
+    }
+}
 
 void RenderStyle::setClip(Length top, Length right, Length bottom, Length left)
 {
index a95ef17..7c0cea0 100644 (file)
@@ -108,6 +108,7 @@ class FilterOperations;
 class Font;
 class FontMetrics;
 class IntRect;
+class MaskImageOperation;
 class Pair;
 class ShadowData;
 class StyleImage;
@@ -798,7 +799,6 @@ public:
     FillLayer* accessBackgroundLayers() { return &(m_background.access()->m_background); }
     const FillLayer* backgroundLayers() const { return &(m_background->background()); }
 
-    StyleImage* maskImage() const { return rareNonInheritedData->m_mask.image(); }
     EFillRepeat maskRepeatX() const { return static_cast<EFillRepeat>(rareNonInheritedData->m_mask.repeatX()); }
     EFillRepeat maskRepeatY() const { return static_cast<EFillRepeat>(rareNonInheritedData->m_mask.repeatY()); }
     CompositeOperator maskComposite() const { return static_cast<CompositeOperator>(rareNonInheritedData->m_mask.composite()); }
@@ -1025,7 +1025,7 @@ public:
     void applyTransform(TransformationMatrix&, const FloatRect& boundingBox, ApplyTransformOrigin = IncludeTransformOrigin) const;
     void setPageScaleTransform(float);
 
-    bool hasMask() const { return rareNonInheritedData->m_mask.hasImage() || rareNonInheritedData->m_maskBoxImage.hasImage(); }
+    bool hasMask() const { return rareNonInheritedData->m_mask.hasNonEmptyMaskImage() || rareNonInheritedData->m_mask.hasImage() || rareNonInheritedData->m_maskBoxImage.hasImage(); }
 
     TextCombine textCombine() const { return static_cast<TextCombine>(rareNonInheritedData->m_textCombine); }
     bool hasTextCombine() const { return textCombine() != TextCombineNone; }
@@ -1126,6 +1126,9 @@ public:
     FilterOperations& mutableFilter() { return rareNonInheritedData.access()->m_filter.access()->m_operations; }
     const FilterOperations& filter() const { return rareNonInheritedData->m_filter->m_operations; }
     bool hasFilter() const { return !rareNonInheritedData->m_filter->m_operations.operations().isEmpty(); }
+    
+    RefPtr<MaskImageOperation>& mutableMaskImage() { return rareNonInheritedData.access()->m_mask.m_maskImageOperation; }
+    const RefPtr<MaskImageOperation> maskImage() const { return rareNonInheritedData->m_mask.maskImage(); }
 
 #if ENABLE(FILTERS_LEVEL_2)
     FilterOperations& mutableBackdropFilter() { return rareNonInheritedData.access()->m_backdropFilter.access()->m_operations; }
@@ -1377,8 +1380,6 @@ public:
         }
     }
 
-    void setMaskImage(PassRefPtr<StyleImage> v) { rareNonInheritedData.access()->m_mask.setImage(v); }
-
     void setMaskBoxImage(const NinePieceImage& b) { SET_VAR(rareNonInheritedData, m_maskBoxImage, b); }
     void setMaskBoxImageSource(PassRefPtr<StyleImage> v) { rareNonInheritedData.access()->m_maskBoxImage.setImage(v); }
     void setMaskXPosition(Length length) { SET_VAR(rareNonInheritedData, m_mask.m_xPosition, WTF::move(length)); }
@@ -1569,6 +1570,9 @@ public:
     void setBackdropFilter(const FilterOperations& ops) { SET_VAR(rareNonInheritedData.access()->m_backdropFilter, m_operations, ops); }
 #endif
 
+    void setMaskImage(const Vector<RefPtr<MaskImageOperation>>&);
+    void setMaskImage(const RefPtr<MaskImageOperation> maskImage) { Vector<RefPtr<MaskImageOperation>> vectMask; vectMask.append(maskImage); setMaskImage(vectMask); }
+
     void setTabSize(unsigned size) { SET_VAR(rareInheritedData, m_tabSize, size); }
 
     // End CSS3 Setters