Support Images Module Level 4's double-position gradient color stop syntax
authormegan_gardner@apple.com <megan_gardner@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 18 Sep 2018 21:38:19 +0000 (21:38 +0000)
committermegan_gardner@apple.com <megan_gardner@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 18 Sep 2018 21:38:19 +0000 (21:38 +0000)
https://bugs.webkit.org/show_bug.cgi?id=186154
<rdar://problem/44158152>

Reviewed by Simon Fraser.

Source/WebCore:

The CSS spec for all gradients allows for each color stop to have two angles to be used for hints.
This makes pie chart and checkerboard conic gradients much simpler to write.
Any time you want to have a hard line in a gradient, this syntax simplifies the gradient specification.

Test: fast/gradients/conic-two-hints.html
Test: fast/gradients/linear-two-hints-angle.html
Test: fast/gradients/linear-two-hints.html
Test: fast/gradients/radial-two-hints.html

* css/parser/CSSPropertyParserHelpers.cpp:
(WebCore::CSSPropertyParserHelpers::consumeAngularGradientColorStops): Removed.
(WebCore::CSSPropertyParserHelpers::consumeGradientColorStops):

LayoutTests:

Test that uses two angles or positions per color stop.

* TestExpectations:
* fast/gradients/conic-two-hints-expected.html: Added.
* fast/gradients/conic-two-hints.html: Added.
* fast/gradients/linear-two-hints-angle-expected.html: Added.
* fast/gradients/linear-two-hints-angle.html: Added.
* fast/gradients/linear-two-hints-expected.html: Added.
* fast/gradients/linear-two-hints.html: Added.
* fast/gradients/radial-two-hints-expected.html: Added.
* fast/gradients/radial-two-hints.html: Added.
* platform/ios-12/TestExpectations:
* platform/mac/TestExpectations:

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

14 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/fast/gradients/conic-two-hints-expected.html [new file with mode: 0644]
LayoutTests/fast/gradients/conic-two-hints.html [new file with mode: 0644]
LayoutTests/fast/gradients/linear-two-hints-angle-expected.html [new file with mode: 0644]
LayoutTests/fast/gradients/linear-two-hints-angle.html [new file with mode: 0644]
LayoutTests/fast/gradients/linear-two-hints-expected.html [new file with mode: 0644]
LayoutTests/fast/gradients/linear-two-hints.html [new file with mode: 0644]
LayoutTests/fast/gradients/radial-two-hints-expected.html [new file with mode: 0644]
LayoutTests/fast/gradients/radial-two-hints.html [new file with mode: 0644]
LayoutTests/platform/ios-12/TestExpectations
LayoutTests/platform/mac/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp

index 4b81bc1..1d0e183 100644 (file)
@@ -1,3 +1,25 @@
+2018-09-18  Megan Gardner  <megan_gardner@apple.com>
+
+        Support Images Module Level 4's double-position gradient color stop syntax
+        https://bugs.webkit.org/show_bug.cgi?id=186154
+        <rdar://problem/44158152>
+
+        Reviewed by Simon Fraser.
+
+        Test that uses two angles or positions per color stop.
+
+        * TestExpectations:
+        * fast/gradients/conic-two-hints-expected.html: Added.
+        * fast/gradients/conic-two-hints.html: Added.
+        * fast/gradients/linear-two-hints-angle-expected.html: Added.
+        * fast/gradients/linear-two-hints-angle.html: Added.
+        * fast/gradients/linear-two-hints-expected.html: Added.
+        * fast/gradients/linear-two-hints.html: Added.
+        * fast/gradients/radial-two-hints-expected.html: Added.
+        * fast/gradients/radial-two-hints.html: Added.
+        * platform/ios-12/TestExpectations:
+        * platform/mac/TestExpectations:
+
 2018-09-18  Youenn Fablet  <youenn@apple.com>
 
         Enable Unified Plan by default
index 07acdf0..5786c1b 100644 (file)
@@ -2246,5 +2246,6 @@ fast/gradients/conic-repeating-last-stop.html [ Skip ]
 fast/gradients/conic-gradient-alpha.html [ Skip ]
 fast/gradients/conic-gradient-extended-stops.html [ Skip ]
 fast/gradients/conic-gradient.html [ Skip ]
+fast/gradients/conic-two-hints.html [ Skip ]
 
 webkit.org/b/187773 http/tests/webAPIStatistics [ Skip ]
diff --git a/LayoutTests/fast/gradients/conic-two-hints-expected.html b/LayoutTests/fast/gradients/conic-two-hints-expected.html
new file mode 100644 (file)
index 0000000..7b71df1
--- /dev/null
@@ -0,0 +1,33 @@
+<html>
+<head>
+    <style>
+        div {
+            float: left;
+        }
+
+        #box1 {
+            height: 50px;
+            width: 25px;
+            background-color: orange;
+        }
+        #box2 {
+            height: 25px;
+            width: 25px;
+            background-color: blue;
+        }
+        #box3 {
+            height: 25px;
+            width: 25px;
+            clear: left;
+            background-color: green;
+        }
+    </style>
+</head>
+<body>
+    <div id="box1"></div>
+    <div id="container">
+        <div id="box2"></div>
+        <div id="box3"></div>
+    </div>
+</body>
+</html>
diff --git a/LayoutTests/fast/gradients/conic-two-hints.html b/LayoutTests/fast/gradients/conic-two-hints.html
new file mode 100644 (file)
index 0000000..4392812
--- /dev/null
@@ -0,0 +1,14 @@
+<html>
+<head>
+    <style>
+        #grad {
+            height: 50px;
+            width: 50px;
+            background: conic-gradient(blue 0deg 90deg, green 90deg 180deg, orange 180deg 360deg);
+        }
+    </style>
+</head>
+<body>
+    <div id="grad"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/gradients/linear-two-hints-angle-expected.html b/LayoutTests/fast/gradients/linear-two-hints-angle-expected.html
new file mode 100644 (file)
index 0000000..c9ad2ec
--- /dev/null
@@ -0,0 +1,115 @@
+<html>
+<head>
+    <style>
+        div {
+            width: 200px;
+            height: 200px;
+            float: left;
+        }
+
+        #topleft {
+            width: 0; 
+            height: 0; 
+            border-left: 50px solid green;
+            border-right: 50px solid orange;
+            border-top: 50px solid orange;
+        }
+        #topright {
+            width: 0; 
+            height: 0; 
+            border-left: 50px solid orange;
+            border-right: 50px solid lime;
+            border-top: 50px solid lime;
+        }
+        #topmiddleleft {
+            width: 0; 
+            height: 0; 
+            clear: left;
+            border-left: 50px solid green;
+            border-right: 50px solid orange;
+            border-bottom: 50px solid green;
+        }
+        #topmiddleright {
+            width: 0; 
+            height: 0; 
+            border-left: 50px solid orange;
+            border-right: 50px solid lime;
+            border-bottom: 50px solid orange;
+        }
+
+        #bottommiddleleft {
+            width: 0; 
+            height: 0; 
+            clear: left;
+            border-left: 50px solid blue;
+            border-right: 50px solid green;
+            border-top: 50px solid green;
+        }
+        #bottommiddleright {
+            width: 0; 
+            height: 0; 
+            border-left: 50px solid green;
+            border-right: 50px solid orange;
+            border-top: 50px solid orange;
+        }
+        #bottomleft {
+            width: 0; 
+            height: 0; 
+            clear: left;
+            border-left: 50px solid blue;
+            border-right: 50px solid green;
+            border-bottom: 50px solid blue;
+        }
+        #bottomright {
+            width: 0; 
+            height: 0; 
+            border-left: 50px solid green;
+            border-right: 50px solid orange;
+            border-bottom: 50px solid green;
+        }
+
+        .box {
+            position: absolute;
+        }
+        .x1 {
+            position: absolute;
+            -webkit-clip-path: polygon(0% 45%,55% 100%,45% 100%,0% 55%);
+        }
+        #x1 {
+            background-color:black;
+        }
+        .x2 {
+            position: absolute;
+            -webkit-clip-path: polygon(0% 0%, 5% 0%, 100% 95%, 100% 100%, 95% 100%,0% 5%);
+        }
+        #x2 {
+            background-color:black;
+        }
+        .x3 {
+            position: absolute;
+            -webkit-clip-path: polygon(55% 0%, 100% 45%, 100% 55%,45% 0%);
+        }
+        #x3 {
+            background-color:black;
+        }
+
+    </style>
+</head>
+<body>
+    <div>
+        <div class="box">
+            <div id="topleft"></div>
+            <div id="topright"></div>
+            <div id="topmiddleleft"></div>
+            <div id="topmiddleright"></div>
+            <div id="bottommiddleleft"></div>
+            <div id="bottommiddleright"></div>
+            <div id="bottomleft"></div>
+            <div id="bottomright"></div>
+        </div>
+        <div id="x1" class="x1"></div>
+        <div id="x2" class="x2"></div>
+        <div id="x3" class="x3"></div>
+    </div>
+</body>
+</html>
diff --git a/LayoutTests/fast/gradients/linear-two-hints-angle.html b/LayoutTests/fast/gradients/linear-two-hints-angle.html
new file mode 100644 (file)
index 0000000..5b946ef
--- /dev/null
@@ -0,0 +1,42 @@
+<html>
+<head>
+    <style>
+       div {
+            width: 200px;
+            height: 200px;
+        }
+        #grad {
+               position: absolute;
+            background: -webkit-linear-gradient(45deg, blue 0% 25%, green 25% 50%, orange 100px 75%, lime 150px);
+        }
+
+        .x1 {
+            position: absolute;
+            -webkit-clip-path: polygon(0% 45%,55% 100%,45% 100%,0% 55%);
+        }
+        #x1 {
+            background-color:black;
+        }
+        .x2 {
+            position: absolute;
+            -webkit-clip-path: polygon(0% 0%, 5% 0%, 100% 95%, 100% 100%, 95% 100%,0% 5%);
+        }
+        #x2 {
+            background-color:black;
+        }
+        .x3 {
+            position: absolute;
+            -webkit-clip-path: polygon(55% 0%, 100% 45%, 100% 55%,45% 0%);
+        }
+        #x3 {
+            background-color:black;
+        }
+    </style>
+</head>
+<body>
+       <div id="grad"></div>
+    <div id="x1" class="x1"></div>
+    <div id="x2" class="x2"></div>
+    <div id="x3" class="x3"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/gradients/linear-two-hints-expected.html b/LayoutTests/fast/gradients/linear-two-hints-expected.html
new file mode 100644 (file)
index 0000000..17237e0
--- /dev/null
@@ -0,0 +1,29 @@
+<html>
+<head>
+    <style>
+        div {
+            width: 200px;
+            height: 50px;
+        }
+
+        #box1 {
+            background-color: blue;
+        }
+        #box2 {
+            background-color: green;
+        }
+        #box3 {
+            background-color: orange;
+        }
+        #box4 {
+            background-color: lime;
+        }
+    </style>
+</head>
+<body>
+    <div id="box1"></div>
+    <div id="box2"></div>
+    <div id="box3"></div>
+    <div id="box4"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/gradients/linear-two-hints.html b/LayoutTests/fast/gradients/linear-two-hints.html
new file mode 100644 (file)
index 0000000..856f4a6
--- /dev/null
@@ -0,0 +1,14 @@
+<html>
+<head>
+    <style>
+        #grad {
+               width: 200px;
+            height: 200px;
+            background: -webkit-linear-gradient(blue 0% 25%, green 25% 50%, orange 100px 75%, lime 150px);
+        }
+    </style>
+</head>
+<body>
+    <div id="grad"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/gradients/radial-two-hints-expected.html b/LayoutTests/fast/gradients/radial-two-hints-expected.html
new file mode 100644 (file)
index 0000000..23c2688
--- /dev/null
@@ -0,0 +1,66 @@
+<html>
+<head>
+    <style>
+        div {
+            width: 200px;
+            height: 200px;
+        }
+        #grad1 {
+            background-color: orange;
+            height: 33px;
+            -webkit-clip-path: inset( 0% 40% 0% 40%);
+        }
+        #grad2 {
+            background-color: green;
+            height: 33px;
+            -webkit-clip-path: inset( 0% 40% 0% 40%);
+        }
+        #grad3 {
+            background-color: blue;
+            height: 68px;
+            -webkit-clip-path: inset( 0% 40% 0% 40%);
+        }
+        #grad4 {
+            background-color: green;
+            height: 33px;
+            -webkit-clip-path: inset( 0% 40% 0% 40%);
+        }
+        #grad5 {
+            background-color: orange;
+            height: 33px;
+            -webkit-clip-path: inset( 0% 40% 0% 40%);
+        }
+        .box {
+            position: absolute;
+            background-color:black;
+        }
+        #box1 {
+            -webkit-clip-path: inset( 30% 40% 60% 40%);
+        }
+        #box2 {
+            -webkit-clip-path: inset( 60% 40% 30% 40%);
+        }
+        #box3 {
+            -webkit-clip-path: inset( 10% 40% 80% 40%);
+        }
+        #box4 {
+            -webkit-clip-path: inset( 80% 40% 10% 40%);
+        }
+    </style>
+</head>
+<body>
+    <div style="position: absolute">
+        <div id="grad1"></div>
+        <div id="grad2"></div>
+        <div id="grad3"></div>
+        <div id="grad4"></div>
+        <div id="grad5"></div>
+    </div>
+    <div style="position: absolute">
+        <div id="box1" class="box"></div>
+        <div id="box2" class="box"></div>
+        <div id="box3" class="box"></div>
+        <div id="box4" class="box"></div>
+    </div>
+</body>
+</html>
diff --git a/LayoutTests/fast/gradients/radial-two-hints.html b/LayoutTests/fast/gradients/radial-two-hints.html
new file mode 100644 (file)
index 0000000..5903c0e
--- /dev/null
@@ -0,0 +1,40 @@
+<html>
+<head>
+    <style>
+       div {
+               position: absolute;
+               width: 200px;
+            height: 200px;
+       }
+        #grad {
+            background: -webkit-radial-gradient(blue 0%, blue 25%, green 25% ,green 50%, orange 50%, orange 75%, lime 75%);
+            -webkit-clip-path: inset(0% 40% 0% 40%);
+        }
+               .box {
+               position: absolute;
+               background-color:black;
+        }
+        #box1 {
+               -webkit-clip-path: inset(30% 40% 60% 40%);
+        }
+        #box2 {
+               -webkit-clip-path: inset(60% 40% 30% 40%);
+        }
+        #box3 {
+               -webkit-clip-path: inset(10% 40% 80% 40%);
+        }
+        #box4 {
+               -webkit-clip-path: inset(80% 40% 10% 40%);
+        }
+    </style>
+</head>
+<body>
+       <div>
+           <div id="grad"></div>
+           <div id="box1" class="box"></div>
+           <div id="box2" class="box"></div>
+           <div id="box3" class="box"></div>
+           <div id="box4" class="box"></div>
+       </div>
+</body>
+</html>
index 05511e5..05f74a8 100644 (file)
@@ -37,4 +37,4 @@ fast/gradients/conic-repeating-last-stop.html [ Pass ]
 fast/gradients/conic-gradient-alpha.html [ Pass ]
 fast/gradients/conic-gradient-extended-stops.html [ Pass ]
 fast/gradients/conic-gradient.html [ Pass ]
-
+fast/gradients/conic-two-hints.html [ Pass ]
index 8f83e43..da026d7 100644 (file)
@@ -1767,5 +1767,6 @@ webkit.org/b/187393 imported/w3c/web-platform-tests/2dcontext/imagebitmap/create
 [ Mojave+ ] fast/gradients/conic-gradient-alpha.html [ Pass ]
 [ Mojave+ ] fast/gradients/conic-gradient-extended-stops.html [ Pass ]
 [ Mojave+ ] fast/gradients/conic-gradient.html [ Pass ]
+[ Mojave+ ] fast/gradients/conic-two-hints.html [ Pass ]
 
 webkit.org/b/185651 legacy-animation-engine/animations/play-state-in-shorthand.html [ Pass Failure ]
index bd769ff..172770d 100644 (file)
@@ -1,3 +1,24 @@
+2018-09-18  Megan Gardner  <megan_gardner@apple.com>
+
+        Support Images Module Level 4's double-position gradient color stop syntax
+        https://bugs.webkit.org/show_bug.cgi?id=186154
+        <rdar://problem/44158152>
+
+        Reviewed by Simon Fraser.
+
+        The CSS spec for all gradients allows for each color stop to have two angles to be used for hints.
+        This makes pie chart and checkerboard conic gradients much simpler to write.
+        Any time you want to have a hard line in a gradient, this syntax simplifies the gradient specification.
+
+        Test: fast/gradients/conic-two-hints.html
+        Test: fast/gradients/linear-two-hints-angle.html
+        Test: fast/gradients/linear-two-hints.html
+        Test: fast/gradients/radial-two-hints.html
+
+        * css/parser/CSSPropertyParserHelpers.cpp:
+        (WebCore::CSSPropertyParserHelpers::consumeAngularGradientColorStops): Removed.
+        (WebCore::CSSPropertyParserHelpers::consumeGradientColorStops):
+
 2018-09-18  Simon Fraser  <simon.fraser@apple.com>
 
         Remove the unused RenderLayerCompositor::enclosingCompositorFlushingLayers()
index 98ffc21..29d52b8 100644 (file)
@@ -963,7 +963,9 @@ static RefPtr<CSSValue> consumeDeprecatedGradient(CSSParserTokenRange& args, CSS
 
 static bool consumeGradientColorStops(CSSParserTokenRange& range, CSSParserMode cssParserMode, CSSGradientValue& gradient)
 {
-    bool supportsColorHints = gradient.gradientType() == CSSLinearGradient || gradient.gradientType() == CSSRadialGradient;
+    bool supportsColorHints = gradient.gradientType() == CSSLinearGradient || gradient.gradientType() == CSSRadialGradient || gradient.gradientType() == CSSConicGradient;
+    
+    bool isAngularGradient = gradient.gradientType() == CSSConicGradient;
 
     // The first color stop cannot be a color hint.
     bool previousStopWasColorHint = true;
@@ -979,45 +981,27 @@ static bool consumeGradientColorStops(CSSParserTokenRange& range, CSSParserMode
         // FIXME-NEWPARSER: This boolean could be removed. Null checking color would be sufficient.
         stop.isMidpoint = !stop.m_color;
 
-        stop.m_position = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
+        if (isAngularGradient)
+            stop.m_position = consumeAngleOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Forbid);
+        else
+            stop.m_position = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
+        
         if (!stop.m_color && !stop.m_position)
             return false;
         gradient.addStop(stop);
-    } while (consumeCommaIncludingWhitespace(range));
-
-    gradient.doneAddingStops();
-
-    // The last color stop cannot be a color hint.
-    if (previousStopWasColorHint)
-        return false;
-
-    // Must have 2 or more stops to be valid.
-    return gradient.stopCount() >= 2;
-}
-
-// https://www.w3.org/TR/css-images-4/#typedef-angular-color-stop-list
-// FIXME: This should support up to two position hints per color stop.
-static bool consumeAngularGradientColorStops(CSSParserTokenRange& range, CSSParserMode cssParserMode, CSSGradientValue& gradient)
-{
-    // The first color stop cannot be a color hint.
-    bool previousStopWasColorHint = true;
-    do {
-        CSSGradientColorStop stop;
-        stop.m_color = consumeColor(range, cssParserMode);
-
-        // Two hints in a row are not allowed.
-        if (!stop.m_color && previousStopWasColorHint)
-            return false;
         
-        previousStopWasColorHint = !stop.m_color;
+        // See if there is a second color hint, which is optional.
+        CSSGradientColorStop secondStop;
+        if (isAngularGradient)
+            secondStop.m_position = consumeAngleOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Forbid);
+        else
+            secondStop.m_position = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
+        
+        if (secondStop.m_position) {
+            secondStop.m_color = stop.m_color;
+            gradient.addStop(secondStop);
+        }
         
-        // FIXME-NEWPARSER: This boolean could be removed. Null checking color would be sufficient.
-        stop.isMidpoint = !stop.m_color;
-
-        stop.m_position = consumeAngleOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Forbid);
-        if (!stop.m_color && !stop.m_position)
-            return false;
-        gradient.addStop(stop);
     } while (consumeCommaIncludingWhitespace(range));
 
     gradient.doneAddingStops();
@@ -1228,7 +1212,7 @@ static RefPtr<CSSValue> consumeConicGradient(CSSParserTokenRange& args, CSSParse
 
     if (expectComma && !consumeCommaIncludingWhitespace(args))
         return nullptr;
-    if (!consumeAngularGradientColorStops(args, context.mode, *result))
+    if (!consumeGradientColorStops(args, context.mode, *result))
         return nullptr;
     return result;
 }