Title: [207111] trunk
Revision
207111
Author
[email protected]
Date
2016-10-11 05:52:28 -0700 (Tue, 11 Oct 2016)

Log Message

[Modern Media Controls] Buttons container
https://bugs.webkit.org/show_bug.cgi?id=163238
<rdar://problem/28701864>

Patch by Antoine Quint <[email protected]> on 2016-10-11
Reviewed by Dean Jackson.

Source/WebCore:

We add a new ButtonsContainer class which contains a group of Button objects
and positions them based on the provided padding and margin between buttons.
Buttons that aren't enabled or marked as dropped are not added to the tree of
LayoutNodes, and thus the DOM.

Additionally, we fix a few issues we found while working on tests for ButtonsContainer
where LayoutNodes would schedule layout callbacks even when they would not do any work
during the layout callback due to not resetting the `needsLayout` flag to false and
removing any scheduled tasks when a layout was completed.

Finally, we fix a few style issues that had not been caught so far and an unused
`size` property on IconButton.

Tests: media/modern-media-controls/buttons-container/buttons-container-buttons-property.html
       media/modern-media-controls/buttons-container/buttons-container-constructor.html
       media/modern-media-controls/buttons-container/buttons-container-layout.html

* Modules/modern-media-controls/controls/airplay-button.js:
(AirplayButton.prototype.set on):
(AirplayButton):
* Modules/modern-media-controls/controls/buttons-container.css:
(.buttons-container):
* Modules/modern-media-controls/controls/buttons-container.js:
(ButtonsContainer.prototype.get buttons):
(ButtonsContainer.prototype.set buttons):
(ButtonsContainer.prototype.layout):
* Modules/modern-media-controls/controls/icon-button.js:
* Modules/modern-media-controls/controls/layout-node.js:
(LayoutNode.prototype.set needsLayout):
(LayoutNode.prototype.markDirtyProperty):
(LayoutNode.prototype._markNodeManipulation):
(LayoutNode.prototype._updateDirtyState):
(performScheduledLayout):
(elementFromString):
* Modules/modern-media-controls/controls/scheduler.js:
(const.scheduler.new.prototype.unscheduleLayout):

LayoutTests:

Adding tests for the new ButtonsContainer class.

* media/modern-media-controls/buttons-container/buttons-container-buttons-property-expected.txt: Added.
* media/modern-media-controls/buttons-container/buttons-container-buttons-property.html: Added.
* media/modern-media-controls/buttons-container/buttons-container-constructor-expected.txt: Added.
* media/modern-media-controls/buttons-container/buttons-container-constructor.html: Added.
* media/modern-media-controls/buttons-container/buttons-container-layout-expected.txt: Added.
* media/modern-media-controls/buttons-container/buttons-container-layout.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (207110 => 207111)


--- trunk/LayoutTests/ChangeLog	2016-10-11 12:47:58 UTC (rev 207110)
+++ trunk/LayoutTests/ChangeLog	2016-10-11 12:52:28 UTC (rev 207111)
@@ -1,3 +1,20 @@
+2016-10-11  Antoine Quint  <[email protected]>
+
+        [Modern Media Controls] Buttons container
+        https://bugs.webkit.org/show_bug.cgi?id=163238
+        <rdar://problem/28701864>
+
+        Reviewed by Dean Jackson.
+
+        Adding tests for the new ButtonsContainer class.
+
+        * media/modern-media-controls/buttons-container/buttons-container-buttons-property-expected.txt: Added.
+        * media/modern-media-controls/buttons-container/buttons-container-buttons-property.html: Added.
+        * media/modern-media-controls/buttons-container/buttons-container-constructor-expected.txt: Added.
+        * media/modern-media-controls/buttons-container/buttons-container-constructor.html: Added.
+        * media/modern-media-controls/buttons-container/buttons-container-layout-expected.txt: Added.
+        * media/modern-media-controls/buttons-container/buttons-container-layout.html: Added.
+
 2016-10-11  Youenn Fablet  <[email protected]>
 
         [Fetch API] Support Request cache mode

Added: trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-buttons-property-expected.txt (0 => 207111)


--- trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-buttons-property-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-buttons-property-expected.txt	2016-10-11 12:52:28 UTC (rev 207111)
@@ -0,0 +1,12 @@
+Testing ButtonsContainer buttons property.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS container.buttons.length is 3
+PASS container.children.length is 3
+PASS container.buttons is container.children
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-buttons-property.html (0 => 207111)


--- trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-buttons-property.html	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-buttons-property.html	2016-10-11 12:52:28 UTC (rev 207111)
@@ -0,0 +1,33 @@
+<link rel="stylesheet" href="" type="text/css" media="screen">
+<link rel="stylesheet" href="" type="text/css" media="screen">
+<script src=""
+<script src="" type="text/_javascript_"></script>
+<script src="" type="text/_javascript_"></script>
+<script src="" type="text/_javascript_"></script>
+<script src="" type="text/_javascript_"></script>
+<script src="" type="text/_javascript_"></script>
+<body>
+<script type="text/_javascript_">
+
+description("Testing <code>ButtonsContainer</code> buttons property.");
+
+window.jsTestIsAsync = true;
+
+const container = new ButtonsContainer({
+    margin: 10,
+    padding: 20
+});
+
+container.buttons = [new Button, new Button, new Button];
+
+scheduler.frameDidFire = function()
+{
+    shouldBe("container.buttons.length", "3");
+    shouldBe("container.children.length", "3");
+    shouldBe("container.buttons", "container.children");
+    finishJSTest();
+};
+
+</script>
+<script src=""
+</body>

Added: trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-constructor-expected.txt (0 => 207111)


--- trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-constructor-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-constructor-expected.txt	2016-10-11 12:52:28 UTC (rev 207111)
@@ -0,0 +1,20 @@
+Testing the ButtonsContainer constructor.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS defaultContainer.element.localName is "div"
+PASS defaultContainer.element.className.trim() is "buttons-container"
+PASS defaultContainer.margin is 0
+PASS defaultContainer.padding is 0
+PASS defaultContainer.buttons is []
+PASS containerWithParameters.element.localName is "div"
+PASS containerWithParameters.element.classList.contains('buttons-container') is true
+PASS containerWithParameters.element.classList.contains('foo') is true
+PASS containerWithParameters.margin is 10
+PASS containerWithParameters.padding is 20
+PASS containerWithParameters.buttons is buttons
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-constructor.html (0 => 207111)


--- trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-constructor.html	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-constructor.html	2016-10-11 12:52:28 UTC (rev 207111)
@@ -0,0 +1,37 @@
+<link rel="stylesheet" href="" type="text/css" media="screen">
+<link rel="stylesheet" href="" type="text/css" media="screen">
+<script src=""
+<script src="" type="text/_javascript_"></script>
+<script src="" type="text/_javascript_"></script>
+<script src="" type="text/_javascript_"></script>
+<script src="" type="text/_javascript_"></script>
+<script src="" type="text/_javascript_"></script>
+<body>
+<script type="text/_javascript_">
+
+description("Testing the <code>ButtonsContainer</code> constructor.");
+
+const defaultContainer = new ButtonsContainer;
+shouldBeEqualToString("defaultContainer.element.localName", "div");
+shouldBeEqualToString("defaultContainer.element.className.trim()", "buttons-container");
+shouldBe("defaultContainer.margin", "0");
+shouldBe("defaultContainer.padding", "0");
+shouldBe("defaultContainer.buttons", "[]");
+
+const buttons = [new Button, new Button];
+const containerWithParameters = new ButtonsContainer({
+    margin: 10,
+    padding: 20,
+    buttons: buttons,
+    cssClassName: "foo"
+});
+shouldBeEqualToString("containerWithParameters.element.localName", "div");
+shouldBeTrue("containerWithParameters.element.classList.contains('buttons-container')");
+shouldBeTrue("containerWithParameters.element.classList.contains('foo')");
+shouldBe("containerWithParameters.margin", "10");
+shouldBe("containerWithParameters.padding", "20");
+shouldBe("containerWithParameters.buttons", "buttons");
+
+</script>
+<script src=""
+</body>

Added: trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-layout-expected.txt (0 => 207111)


--- trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-layout-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-layout-expected.txt	2016-10-11 12:52:28 UTC (rev 207111)
@@ -0,0 +1,17 @@
+Testing ButtonsContainer layout.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS container.children.length is 3
+PASS container.children[0] is tenPtWideButton
+PASS container.children[1] is twentyPtWideButton
+PASS container.children[2] is thirtyPtWideButton
+PASS tenPtWideButton.x is 20
+PASS twentyPtWideButton.x is 40
+PASS thirtyPtWideButton.x is 70
+PASS container.width is 120
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-layout.html (0 => 207111)


--- trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-layout.html	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/buttons-container/buttons-container-layout.html	2016-10-11 12:52:28 UTC (rev 207111)
@@ -0,0 +1,51 @@
+<link rel="stylesheet" href="" type="text/css" media="screen">
+<link rel="stylesheet" href="" type="text/css" media="screen">
+<script src=""
+<script src="" type="text/_javascript_"></script>
+<script src="" type="text/_javascript_"></script>
+<script src="" type="text/_javascript_"></script>
+<script src="" type="text/_javascript_"></script>
+<script src="" type="text/_javascript_"></script>
+<body>
+<script type="text/_javascript_">
+
+description("Testing <code>ButtonsContainer</code> layout.");
+
+const tenPtWideButton = new Button;
+tenPtWideButton.width = 10;
+
+const twentyPtWideButton = new Button;
+twentyPtWideButton.width = 20;
+
+const thirtyPtWideButton = new Button;
+thirtyPtWideButton.width = 30;
+
+// Should be disregarded by the container.
+const disabledButton = new Button;
+disabledButton.width = 15;
+disabledButton.enabled = false;
+
+// Should be disregarded by the container.
+const droppedButton = new Button;
+droppedButton.width = 25;
+droppedButton.dropped = true;
+
+const container = new ButtonsContainer({
+    margin: 10,
+    padding: 20,
+    buttons: [tenPtWideButton, disabledButton, twentyPtWideButton, droppedButton, thirtyPtWideButton]
+});
+
+container.layout();
+shouldBe("container.children.length", "3");
+shouldBe("container.children[0]", "tenPtWideButton");
+shouldBe("container.children[1]", "twentyPtWideButton");
+shouldBe("container.children[2]", "thirtyPtWideButton");
+shouldBe("tenPtWideButton.x", "20");
+shouldBe("twentyPtWideButton.x", "40");
+shouldBe("thirtyPtWideButton.x", "70");
+shouldBe("container.width", "120");
+
+</script>
+<script src=""
+</body>

Modified: trunk/Source/WebCore/ChangeLog (207110 => 207111)


--- trunk/Source/WebCore/ChangeLog	2016-10-11 12:47:58 UTC (rev 207110)
+++ trunk/Source/WebCore/ChangeLog	2016-10-11 12:52:28 UTC (rev 207111)
@@ -1,3 +1,48 @@
+2016-10-11  Antoine Quint  <[email protected]>
+
+        [Modern Media Controls] Buttons container
+        https://bugs.webkit.org/show_bug.cgi?id=163238
+        <rdar://problem/28701864>
+
+        Reviewed by Dean Jackson.
+
+        We add a new ButtonsContainer class which contains a group of Button objects
+        and positions them based on the provided padding and margin between buttons.
+        Buttons that aren't enabled or marked as dropped are not added to the tree of
+        LayoutNodes, and thus the DOM.
+
+        Additionally, we fix a few issues we found while working on tests for ButtonsContainer
+        where LayoutNodes would schedule layout callbacks even when they would not do any work
+        during the layout callback due to not resetting the `needsLayout` flag to false and
+        removing any scheduled tasks when a layout was completed.
+
+        Finally, we fix a few style issues that had not been caught so far and an unused
+        `size` property on IconButton.
+
+        Tests: media/modern-media-controls/buttons-container/buttons-container-buttons-property.html
+               media/modern-media-controls/buttons-container/buttons-container-constructor.html
+               media/modern-media-controls/buttons-container/buttons-container-layout.html
+
+        * Modules/modern-media-controls/controls/airplay-button.js:
+        (AirplayButton.prototype.set on):
+        (AirplayButton):
+        * Modules/modern-media-controls/controls/buttons-container.css:
+        (.buttons-container):
+        * Modules/modern-media-controls/controls/buttons-container.js:
+        (ButtonsContainer.prototype.get buttons):
+        (ButtonsContainer.prototype.set buttons):
+        (ButtonsContainer.prototype.layout):
+        * Modules/modern-media-controls/controls/icon-button.js:
+        * Modules/modern-media-controls/controls/layout-node.js:
+        (LayoutNode.prototype.set needsLayout):
+        (LayoutNode.prototype.markDirtyProperty):
+        (LayoutNode.prototype._markNodeManipulation):
+        (LayoutNode.prototype._updateDirtyState):
+        (performScheduledLayout):
+        (elementFromString):
+        * Modules/modern-media-controls/controls/scheduler.js:
+        (const.scheduler.new.prototype.unscheduleLayout):
+
 2016-10-11  Youenn Fablet  <[email protected]>
 
         [Fetch API] Support Request cache mode

Added: trunk/Source/WebCore/Modules/modern-media-controls/controls/buttons-container.css (0 => 207111)


--- trunk/Source/WebCore/Modules/modern-media-controls/controls/buttons-container.css	                        (rev 0)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/buttons-container.css	2016-10-11 12:52:28 UTC (rev 207111)
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.buttons-container {
+    position: absolute;
+    height: 100%;
+}

Added: trunk/Source/WebCore/Modules/modern-media-controls/controls/buttons-container.js (0 => 207111)


--- trunk/Source/WebCore/Modules/modern-media-controls/controls/buttons-container.js	                        (rev 0)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/buttons-container.js	2016-10-11 12:52:28 UTC (rev 207111)
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+class ButtonsContainer extends LayoutNode
+{
+
+    constructor({ buttons = [], padding = 0, margin = 0, cssClassName = "" } = {})
+    {
+        super(`<div class="buttons-container ${cssClassName}">`);
+
+        this.margin = margin;
+        this.padding = padding;
+        this.buttons = buttons;
+    }
+
+    // Public
+
+    get buttons()
+    {
+        return this._buttons;
+    }
+
+    set buttons(buttons)
+    {
+        if (!Array.isArray(buttons))
+            return;
+
+        this._buttons = buttons;
+        this.needsLayout = true;
+    }
+
+    layout()
+    {
+        super.layout();
+
+        const children = [];
+        let x = this.padding;
+
+        this._buttons.forEach(button => {
+            if (!button.enabled || button.dropped)
+                return;
+            button.x = x;
+            x += button.width + this.margin;
+            children.push(button);
+        });
+
+        if (children.length)
+            this.width = x - this.margin + this.padding;
+        else
+            this.width = this.padding * 2;
+
+        this.children = children;
+    }
+
+}

Modified: trunk/Source/WebCore/Modules/modern-media-controls/controls/icon-button.js (207110 => 207111)


--- trunk/Source/WebCore/Modules/modern-media-controls/controls/icon-button.js	2016-10-11 12:47:58 UTC (rev 207110)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/icon-button.js	2016-10-11 12:52:28 UTC (rev 207111)
@@ -39,8 +39,6 @@
 
         if (!!iconName)
             this.iconName = iconName;
-
-        this.size = { width: 0, height: 0 };
     }
 
     // Public

Modified: trunk/Source/WebCore/Modules/modern-media-controls/controls/layout-node.js (207110 => 207111)


--- trunk/Source/WebCore/Modules/modern-media-controls/controls/layout-node.js	2016-10-11 12:47:58 UTC (rev 207110)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/layout-node.js	2016-10-11 12:52:28 UTC (rev 207111)
@@ -95,7 +95,7 @@
         if (this.needsLayout === flag)
             return;
 
-        this._needsLayout = true;
+        this._needsLayout = flag;
         this._updateDirtyState();
     }
 
@@ -167,7 +167,8 @@
             return this._parent.removeChild(this);
     }
 
-    markDirtyProperty(propertyName) {
+    markDirtyProperty(propertyName)
+    {
         const hadProperty = this._dirtyProperties.has(propertyName);
         this._dirtyProperties.add(propertyName);
 
@@ -217,17 +218,22 @@
 
     // Private
 
-    _markNodeManipulation(manipulation) {
+    _markNodeManipulation(manipulation)
+    {
         this._pendingDOMManipulation = manipulation;
         this._updateDirtyState();
     }
 
-    _updateDirtyState() {
+    _updateDirtyState()
+    {
         if (this.needsLayout) {
             dirtyNodes.add(this);
             scheduler.scheduleLayout(performScheduledLayout);
-        } else
-            dirtyNodes.delete(node);
+        } else {
+            dirtyNodes.delete(this);
+            if (dirtyNodes.size === 0)
+                scheduler.unscheduleLayout(performScheduledLayout);
+        }
     }
 
     _updateChildren()
@@ -255,15 +261,21 @@
     Addition: 2
 };
 
-function performScheduledLayout() {
-    dirtyNodes.forEach(node => node.layout());
+function performScheduledLayout()
+{
+    dirtyNodes.forEach(node => {
+        node.needsLayout = false;
+        node.layout()
+    });
     dirtyNodes.clear();
+    scheduler.unscheduleLayout(performScheduledLayout);
 
     nodesRequiringChildrenUpdate.forEach(node => node._updateChildren());
     nodesRequiringChildrenUpdate.clear();
 }
 
-function elementFromString(elementString) {
+function elementFromString(elementString)
+{
     const element = document.createElement("div");
     element.innerHTML = elementString;
     return element.firstElementChild;

Modified: trunk/Source/WebCore/Modules/modern-media-controls/controls/scheduler.js (207110 => 207111)


--- trunk/Source/WebCore/Modules/modern-media-controls/controls/scheduler.js	2016-10-11 12:47:58 UTC (rev 207110)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/scheduler.js	2016-10-11 12:52:28 UTC (rev 207111)
@@ -19,6 +19,14 @@
         this._requestFrameIfNeeded();
     }
 
+    unscheduleLayout(callback)
+    {
+        if (typeof callback !== "function")
+            return;
+
+        this._layoutCallbacks.delete(callback);
+    }
+
     // Private
 
     _requestFrameIfNeeded()
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to