<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[206686] trunk</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/206686">206686</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-09-30 15:45:17 -0700 (Fri, 30 Sep 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>[Modern Media Controls] layout nodes
https://bugs.webkit.org/show_bug.cgi?id=162799
<rdar://problem/28569301>
Patch by Antoine Quint <graouts@apple.com> on 2016-09-30
Reviewed by Dean Jackson.
Source/WebCore:
Modern media controls will be using a tree of LayoutNode objects that commit to the DOM
in coordinated `requestAnimationFrame()` calls to ensure all layouts are done in an efficient
and coordinated manner. As a preamble, we introduced the `scheduler` singleton in
https://webkit.org/b/162726 which is in charge of scheduling callbacks.
A LayoutNode is created by providing an Element to its constructor, or an HTML string. Not
providing a parameter creates a simple <div>.
When we set a property on a LayoutNode, we call `markDirtyProperty(propertyName)` which keeps
track of dirty properties in the `_dirtyProperties` set. When this set is non-empty, the node
is marked as dirty and registered in the global `dirtyNodes` map, asking the shared scheduler
that a layout is needed. When the layout is performed, all nodes in the `dirtyNodes` map are
processed such that `commitProperty(propertyName)` is called to commit dirty properties for
a given node to the DOM, and `layout()` is called to allow subclasses of LayoutNode to conduct
custom layout logic that goes beyond committing a given property.
Another reason why a node may be marked as dirty is when a DOM hierarchy change is needed. A
host of DOM-like methods are exposed to allow flexible manipulations of nodes, with an extra
`children` property which allows wholesale change of a node's subtree with a single array
property assignment. Changes to the DOM hierarchy are performed in the same scheduler callback
as style properties.
Nodes can be marked for layout explicitly with by setting the `needsLayout` property.
Tests: media/modern-media-controls/layout-node/addChild.html
media/modern-media-controls/layout-node/children.html
media/modern-media-controls/layout-node/constructor.html
media/modern-media-controls/layout-node/height.html
media/modern-media-controls/layout-node/insertAfter.html
media/modern-media-controls/layout-node/insertBefore.html
media/modern-media-controls/layout-node/parent.html
media/modern-media-controls/layout-node/remove.html
media/modern-media-controls/layout-node/removeChild.html
media/modern-media-controls/layout-node/subclassing.html
media/modern-media-controls/layout-node/visible.html
media/modern-media-controls/layout-node/width.html
media/modern-media-controls/layout-node/x.html
media/modern-media-controls/layout-node/y.html
* Modules/modern-media-controls/controls/layout-node.js: Added.
(LayoutNode):
(LayoutNode.prototype.get x):
(LayoutNode.prototype.set x):
(LayoutNode.prototype.get y):
(LayoutNode.prototype.set y):
(LayoutNode.prototype.get width):
(LayoutNode.prototype.set width):
(LayoutNode.prototype.get height):
(LayoutNode.prototype.set height):
(LayoutNode.prototype.get visible):
(LayoutNode.prototype.set visible):
(LayoutNode.prototype.get needsLayout):
(LayoutNode.prototype.set needsLayout):
(LayoutNode.prototype.get parent):
(LayoutNode.prototype.get children):
(LayoutNode.prototype.set children):
(LayoutNode.prototype.addChild):
(LayoutNode.prototype.insertBefore):
(LayoutNode.prototype.insertAfter):
(LayoutNode.prototype.removeChild):
(LayoutNode.prototype.remove):
(LayoutNode.prototype.markDirtyProperty):
(LayoutNode.prototype.commitProperty):
(LayoutNode.prototype.layout):
(LayoutNode.prototype._markNodeManipulation):
(LayoutNode.prototype._updateDirtyState):
(LayoutNode.prototype._updateChildren):
(performScheduledLayout):
(elementFromString):
LayoutTests:
Testing all public properties and methods of the LayoutNode class.
* media/modern-media-controls/layout-node/addChild-expected.txt: Added.
* media/modern-media-controls/layout-node/addChild.html: Added.
* media/modern-media-controls/layout-node/children-expected.txt: Added.
* media/modern-media-controls/layout-node/children.html: Added.
* media/modern-media-controls/layout-node/constructor-expected.txt: Added.
* media/modern-media-controls/layout-node/constructor.html: Added.
* media/modern-media-controls/layout-node/height-expected.txt: Added.
* media/modern-media-controls/layout-node/height.html: Added.
* media/modern-media-controls/layout-node/insertAfter-expected.txt: Added.
* media/modern-media-controls/layout-node/insertAfter.html: Added.
* media/modern-media-controls/layout-node/insertBefore-expected.txt: Added.
* media/modern-media-controls/layout-node/insertBefore.html: Added.
* media/modern-media-controls/layout-node/parent-expected.txt: Added.
* media/modern-media-controls/layout-node/parent.html: Added.
* media/modern-media-controls/layout-node/remove-expected.txt: Added.
* media/modern-media-controls/layout-node/remove.html: Added.
* media/modern-media-controls/layout-node/removeChild-expected.txt: Added.
* media/modern-media-controls/layout-node/removeChild.html: Added.
* media/modern-media-controls/layout-node/subclassing-expected.txt: Added.
* media/modern-media-controls/layout-node/subclassing.html: Added.
* media/modern-media-controls/layout-node/visible-expected.txt: Added.
* media/modern-media-controls/layout-node/visible.html: Added.
* media/modern-media-controls/layout-node/width-expected.txt: Added.
* media/modern-media-controls/layout-node/width.html: Added.
* media/modern-media-controls/layout-node/x-expected.txt: Added.
* media/modern-media-controls/layout-node/x.html: Added.
* media/modern-media-controls/layout-node/y-expected.txt: Added.
* media/modern-media-controls/layout-node/y.html: Added.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li>trunk/LayoutTests/media/modern-media-controls/layout-node/</li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodeaddChildexpectedtxt">trunk/LayoutTests/media/modern-media-controls/layout-node/addChild-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodeaddChildhtml">trunk/LayoutTests/media/modern-media-controls/layout-node/addChild.html</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodechildrenexpectedtxt">trunk/LayoutTests/media/modern-media-controls/layout-node/children-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodechildrenhtml">trunk/LayoutTests/media/modern-media-controls/layout-node/children.html</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodeconstructorexpectedtxt">trunk/LayoutTests/media/modern-media-controls/layout-node/constructor-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodeconstructorhtml">trunk/LayoutTests/media/modern-media-controls/layout-node/constructor.html</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodeheightexpectedtxt">trunk/LayoutTests/media/modern-media-controls/layout-node/height-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodeheighthtml">trunk/LayoutTests/media/modern-media-controls/layout-node/height.html</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodeinsertAfterexpectedtxt">trunk/LayoutTests/media/modern-media-controls/layout-node/insertAfter-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodeinsertAfterhtml">trunk/LayoutTests/media/modern-media-controls/layout-node/insertAfter.html</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodeinsertBeforeexpectedtxt">trunk/LayoutTests/media/modern-media-controls/layout-node/insertBefore-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodeinsertBeforehtml">trunk/LayoutTests/media/modern-media-controls/layout-node/insertBefore.html</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodeparentexpectedtxt">trunk/LayoutTests/media/modern-media-controls/layout-node/parent-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodeparenthtml">trunk/LayoutTests/media/modern-media-controls/layout-node/parent.html</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnoderemoveexpectedtxt">trunk/LayoutTests/media/modern-media-controls/layout-node/remove-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnoderemovehtml">trunk/LayoutTests/media/modern-media-controls/layout-node/remove.html</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnoderemoveChildexpectedtxt">trunk/LayoutTests/media/modern-media-controls/layout-node/removeChild-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnoderemoveChildhtml">trunk/LayoutTests/media/modern-media-controls/layout-node/removeChild.html</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodesubclassingexpectedtxt">trunk/LayoutTests/media/modern-media-controls/layout-node/subclassing-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodesubclassinghtml">trunk/LayoutTests/media/modern-media-controls/layout-node/subclassing.html</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodevisibleexpectedtxt">trunk/LayoutTests/media/modern-media-controls/layout-node/visible-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodevisiblehtml">trunk/LayoutTests/media/modern-media-controls/layout-node/visible.html</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodewidthexpectedtxt">trunk/LayoutTests/media/modern-media-controls/layout-node/width-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodewidthhtml">trunk/LayoutTests/media/modern-media-controls/layout-node/width.html</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodexexpectedtxt">trunk/LayoutTests/media/modern-media-controls/layout-node/x-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodexhtml">trunk/LayoutTests/media/modern-media-controls/layout-node/x.html</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodeyexpectedtxt">trunk/LayoutTests/media/modern-media-controls/layout-node/y-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolslayoutnodeyhtml">trunk/LayoutTests/media/modern-media-controls/layout-node/y.html</a></li>
<li><a href="#trunkSourceWebCoreModulesmodernmediacontrolscontrolslayoutnodejs">trunk/Source/WebCore/Modules/modern-media-controls/controls/layout-node.js</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (206685 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-09-30 22:43:40 UTC (rev 206685)
+++ trunk/LayoutTests/ChangeLog        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -1,3 +1,42 @@
</span><ins>+2016-09-30 Antoine Quint <graouts@apple.com>
+
+ [Modern Media Controls] layout nodes
+ https://bugs.webkit.org/show_bug.cgi?id=162799
+ <rdar://problem/28569301>
+
+ Reviewed by Dean Jackson.
+
+ Testing all public properties and methods of the LayoutNode class.
+
+ * media/modern-media-controls/layout-node/addChild-expected.txt: Added.
+ * media/modern-media-controls/layout-node/addChild.html: Added.
+ * media/modern-media-controls/layout-node/children-expected.txt: Added.
+ * media/modern-media-controls/layout-node/children.html: Added.
+ * media/modern-media-controls/layout-node/constructor-expected.txt: Added.
+ * media/modern-media-controls/layout-node/constructor.html: Added.
+ * media/modern-media-controls/layout-node/height-expected.txt: Added.
+ * media/modern-media-controls/layout-node/height.html: Added.
+ * media/modern-media-controls/layout-node/insertAfter-expected.txt: Added.
+ * media/modern-media-controls/layout-node/insertAfter.html: Added.
+ * media/modern-media-controls/layout-node/insertBefore-expected.txt: Added.
+ * media/modern-media-controls/layout-node/insertBefore.html: Added.
+ * media/modern-media-controls/layout-node/parent-expected.txt: Added.
+ * media/modern-media-controls/layout-node/parent.html: Added.
+ * media/modern-media-controls/layout-node/remove-expected.txt: Added.
+ * media/modern-media-controls/layout-node/remove.html: Added.
+ * media/modern-media-controls/layout-node/removeChild-expected.txt: Added.
+ * media/modern-media-controls/layout-node/removeChild.html: Added.
+ * media/modern-media-controls/layout-node/subclassing-expected.txt: Added.
+ * media/modern-media-controls/layout-node/subclassing.html: Added.
+ * media/modern-media-controls/layout-node/visible-expected.txt: Added.
+ * media/modern-media-controls/layout-node/visible.html: Added.
+ * media/modern-media-controls/layout-node/width-expected.txt: Added.
+ * media/modern-media-controls/layout-node/width.html: Added.
+ * media/modern-media-controls/layout-node/x-expected.txt: Added.
+ * media/modern-media-controls/layout-node/x.html: Added.
+ * media/modern-media-controls/layout-node/y-expected.txt: Added.
+ * media/modern-media-controls/layout-node/y.html: Added.
+
</ins><span class="cx"> 2016-09-30 Ryan Haddad <ryanhaddad@apple.com>
</span><span class="cx">
</span><span class="cx"> Marking http/tests/media/hls/hls-video-resize.html as flaky on mac-wk1.
</span></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodeaddChildexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/addChild-expected.txt (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/addChild-expected.txt         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/addChild-expected.txt        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+Testing the LayoutNode.addChild(child[, index]) method.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+node.addChild(a)
+PASS node.children.length === 1 is true
+PASS node.children[0] === a is true
+PASS retVal === a is true
+
+node.addChild(b, 0)
+PASS node.children.length === 2 is true
+PASS node.children[0] === b is true
+PASS node.children[1] === a is true
+
+Layout was performed
+PASS node.element.childElementCount === 2 is true
+PASS node.element.firstElementChild === b.element is true
+PASS node.element.lastElementChild === a.element is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodeaddChildhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/addChild.html (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/addChild.html         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/addChild.html        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,41 @@
</span><ins>+<script src="../../../resources/js-test-pre.js"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/scheduler.js" type="text/javascript"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/layout-node.js" type="text/javascript"></script>
+<script type="text/javascript">
+
+description("Testing the <code>LayoutNode.addChild(child[, index])</code> method.");
+
+window.jsTestIsAsync = true;
+
+const node = new LayoutNode;
+
+const a = new LayoutNode;
+const b = new LayoutNode;
+
+debug("node.addChild(a)");
+const retVal = node.addChild(a);
+shouldBeTrue("node.children.length === 1");
+shouldBeTrue("node.children[0] === a");
+shouldBeTrue("retVal === a");
+
+debug("");
+debug("node.addChild(b, 0)");
+node.addChild(b, 0);
+shouldBeTrue("node.children.length === 2");
+shouldBeTrue("node.children[0] === b");
+shouldBeTrue("node.children[1] === a");
+
+scheduler.frameDidFire = function()
+{
+ debug("");
+ debug("Layout was performed");
+
+ shouldBeTrue("node.element.childElementCount === 2");
+ shouldBeTrue("node.element.firstElementChild === b.element");
+ shouldBeTrue("node.element.lastElementChild === a.element");
+
+ finishJSTest();
+};
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodechildrenexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/children-expected.txt (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/children-expected.txt         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/children-expected.txt        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,41 @@
</span><ins>+Testing the LayoutNode.children property.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Check default state
+PASS Array.isArray(node.children) is true
+PASS node.children.length === 0 is true
+
+Set children to [a, b, c]
+PASS node.children.length === 3 is true
+PASS node.children[0] === a is true
+PASS node.children[1] === b is true
+PASS node.children[2] === c is true
+PASS node.children !== children is true
+
+Layout was performed
+PASS node.element.childElementCount === 3 is true
+PASS node.element.firstElementChild === a.element is true
+PASS node.element.firstElementChild.nextElementSibling === b.element is true
+PASS node.element.lastElementChild === c.element is true
+
+Set children to [b, a]
+PASS node.children.length === 2 is true
+PASS node.children[0] === b is true
+PASS node.children[1] === a is true
+
+Layout was performed
+PASS node.element.childElementCount === 2 is true
+PASS node.element.firstElementChild === b.element is true
+PASS node.element.lastElementChild === a.element is true
+
+Set children to []
+PASS node.children.length === 0 is true
+
+Layout was performed
+PASS node.element.childElementCount === 0 is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodechildrenhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/children.html (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/children.html         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/children.html        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,67 @@
</span><ins>+<script src="../../../resources/js-test-pre.js"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/scheduler.js" type="text/javascript"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/layout-node.js" type="text/javascript"></script>
+<script type="text/javascript">
+
+description("Testing the <code>LayoutNode.children</code> property.");
+
+window.jsTestIsAsync = true;
+
+const node = new LayoutNode;
+
+debug("Check default state");
+shouldBeTrue("Array.isArray(node.children)");
+shouldBeTrue("node.children.length === 0");
+
+const a = new LayoutNode;
+const b = new LayoutNode;
+const c = new LayoutNode;
+
+const children = [a, b, c];
+node.children = children;
+
+debug("");
+debug("Set children to [a, b, c]");
+shouldBeTrue("node.children.length === 3");
+shouldBeTrue("node.children[0] === a");
+shouldBeTrue("node.children[1] === b");
+shouldBeTrue("node.children[2] === c");
+shouldBeTrue("node.children !== children");
+
+let numberOfFrames = 0;
+scheduler.frameDidFire = function()
+{
+ debug("");
+ debug("Layout was performed");
+
+ switch (++numberOfFrames) {
+ case 1:
+ shouldBeTrue("node.element.childElementCount === 3");
+ shouldBeTrue("node.element.firstElementChild === a.element");
+ shouldBeTrue("node.element.firstElementChild.nextElementSibling === b.element");
+ shouldBeTrue("node.element.lastElementChild === c.element");
+ debug("");
+ debug("Set children to [b, a]");
+ node.children = [b, a];
+ shouldBeTrue("node.children.length === 2");
+ shouldBeTrue("node.children[0] === b");
+ shouldBeTrue("node.children[1] === a");
+ break;
+ case 2:
+ shouldBeTrue("node.element.childElementCount === 2");
+ shouldBeTrue("node.element.firstElementChild === b.element");
+ shouldBeTrue("node.element.lastElementChild === a.element");
+ debug("");
+ debug("Set children to []");
+ node.children = [];
+ shouldBeTrue("node.children.length === 0");
+ break;
+ case 3:
+ shouldBeTrue("node.element.childElementCount === 0");
+ finishJSTest();
+ break;
+ }
+};
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodeconstructorexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/constructor-expected.txt (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/constructor-expected.txt         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/constructor-expected.txt        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+Testing the LayoutNode various constructor parameters.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+No parameter
+PASS nodeWithNoParameter.element.localName is "div"
+
+Element parameter
+PASS nodeWithElementParameter.element === element is true
+
+HTML string parameter
+PASS nodeWithStringParameter.element.localName is "span"
+PASS nodeWithStringParameter.element.textContent is "hello world"
+PASS nodeWithStringParameter.element.firstElementChild.localName is "strong"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodeconstructorhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/constructor.html (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/constructor.html         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/constructor.html        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,26 @@
</span><ins>+<script src="../../../resources/js-test-pre.js"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/scheduler.js" type="text/javascript"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/layout-node.js" type="text/javascript"></script>
+<script type="text/javascript">
+
+description("Testing the <code>LayoutNode</code> various constructor parameters.");
+
+debug("No parameter");
+const nodeWithNoParameter = new LayoutNode;
+shouldBeEqualToString("nodeWithNoParameter.element.localName", "div");
+
+debug("");
+debug("Element parameter");
+const element = document.createElement("h1");
+const nodeWithElementParameter = new LayoutNode(element);
+shouldBeTrue("nodeWithElementParameter.element === element");
+
+debug("");
+debug("HTML string parameter");
+const nodeWithStringParameter = new LayoutNode(`<span>hello <strong>world</strong></span>`);
+shouldBeEqualToString("nodeWithStringParameter.element.localName", "span");
+shouldBeEqualToString("nodeWithStringParameter.element.textContent", "hello world");
+shouldBeEqualToString("nodeWithStringParameter.element.firstElementChild.localName", "strong");
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodeheightexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/height-expected.txt (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/height-expected.txt         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/height-expected.txt        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,22 @@
</span><ins>+Testing the LayoutNode.height property.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Checking default value
+PASS node.height is 0
+PASS node.element.style.height is ""
+
+node.height = 10
+PASS node.height is 10
+PASS node.element.style.height is ""
+
+node.height = 20
+
+Layout was performed
+PASS node.height is 20
+PASS node.element.style.height is "20px"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodeheighthtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/height.html (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/height.html         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/height.html        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,37 @@
</span><ins>+<script src="../../../resources/js-test-pre.js"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/scheduler.js" type="text/javascript"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/layout-node.js" type="text/javascript"></script>
+<script type="text/javascript">
+
+description("Testing the <code>LayoutNode.height</code> property.");
+
+window.jsTestIsAsync = true;
+
+const node = new LayoutNode;
+
+debug("Checking default value");
+shouldBe("node.height", "0");
+shouldBeEqualToString("node.element.style.height", "");
+
+debug("");
+debug("node.height = 10");
+node.height = 10;
+shouldBe("node.height", "10");
+shouldBeEqualToString("node.element.style.height", "");
+
+// Set the value to another one so we can check it's the one committed to the DOM.
+debug("");
+debug("node.height = 20");
+node.height = 20;
+
+scheduler.frameDidFire = function()
+{
+ debug("");
+ debug("Layout was performed");
+ shouldBe("node.height", "20");
+ shouldBeEqualToString("node.element.style.height", "20px");
+ finishJSTest();
+};
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodeinsertAfterexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/insertAfter-expected.txt (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/insertAfter-expected.txt         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/insertAfter-expected.txt        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,36 @@
</span><ins>+Testing the LayoutNode.insertAfter(newSibling, referenceSibling) method.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+node.insertAfter(a)
+PASS node.children.length === 1 is true
+PASS node.children[0] === a is true
+PASS retVal === a is true
+
+node.insertAfter(c, a)
+PASS node.children.length === 2 is true
+PASS node.children[0] === a is true
+PASS node.children[1] === c is true
+
+node.insertAfter(b, a)
+PASS node.children.length === 3 is true
+PASS node.children[0] === a is true
+PASS node.children[1] === b is true
+PASS node.children[2] === c is true
+
+node.insertAfter(a, c)
+PASS node.children.length === 3 is true
+PASS node.children[0] === b is true
+PASS node.children[1] === c is true
+PASS node.children[2] === a is true
+
+Layout was performed
+PASS node.element.childElementCount === 3 is true
+PASS node.element.firstElementChild === b.element is true
+PASS node.element.firstElementChild.nextElementSibling === c.element is true
+PASS node.element.lastElementChild === a.element is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodeinsertAfterhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/insertAfter.html (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/insertAfter.html         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/insertAfter.html        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,59 @@
</span><ins>+<script src="../../../resources/js-test-pre.js"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/scheduler.js" type="text/javascript"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/layout-node.js" type="text/javascript"></script>
+<script type="text/javascript">
+
+description("Testing the <code>LayoutNode.insertAfter(newSibling, referenceSibling)</code> method.");
+
+window.jsTestIsAsync = true;
+
+const node = new LayoutNode;
+
+const a = new LayoutNode;
+const b = new LayoutNode;
+const c = new LayoutNode;
+
+debug("node.insertAfter(a)");
+const retVal = node.insertAfter(a);
+shouldBeTrue("node.children.length === 1");
+shouldBeTrue("node.children[0] === a");
+shouldBeTrue("retVal === a");
+
+debug("");
+debug("node.insertAfter(c, a)");
+node.insertAfter(c, a);
+shouldBeTrue("node.children.length === 2");
+shouldBeTrue("node.children[0] === a");
+shouldBeTrue("node.children[1] === c");
+
+debug("");
+debug("node.insertAfter(b, a)");
+node.insertAfter(b, a);
+shouldBeTrue("node.children.length === 3");
+shouldBeTrue("node.children[0] === a");
+shouldBeTrue("node.children[1] === b");
+shouldBeTrue("node.children[2] === c");
+
+debug("");
+debug("node.insertAfter(a, c)");
+node.insertAfter(a, c);
+shouldBeTrue("node.children.length === 3");
+shouldBeTrue("node.children[0] === b");
+shouldBeTrue("node.children[1] === c");
+shouldBeTrue("node.children[2] === a");
+
+scheduler.frameDidFire = function()
+{
+ debug("");
+ debug("Layout was performed");
+
+ shouldBeTrue("node.element.childElementCount === 3");
+ shouldBeTrue("node.element.firstElementChild === b.element");
+ shouldBeTrue("node.element.firstElementChild.nextElementSibling === c.element");
+ shouldBeTrue("node.element.lastElementChild === a.element");
+
+ finishJSTest();
+};
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodeinsertBeforeexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/insertBefore-expected.txt (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/insertBefore-expected.txt         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/insertBefore-expected.txt        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,36 @@
</span><ins>+Testing the LayoutNode.insertBefore(newSibling, referenceSibling) method.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+node.insertBefore(c)
+PASS node.children.length === 1 is true
+PASS node.children[0] === c is true
+PASS retVal === c is true
+
+node.insertBefore(a, c)
+PASS node.children.length === 2 is true
+PASS node.children[0] === a is true
+PASS node.children[1] === c is true
+
+node.insertBefore(b, c)
+PASS node.children.length === 3 is true
+PASS node.children[0] === a is true
+PASS node.children[1] === b is true
+PASS node.children[2] === c is true
+
+node.insertBefore(a, c)
+PASS node.children.length === 3 is true
+PASS node.children[0] === b is true
+PASS node.children[1] === c is true
+PASS node.children[2] === a is true
+
+Layout was performed
+PASS node.element.childElementCount === 3 is true
+PASS node.element.firstElementChild === b.element is true
+PASS node.element.firstElementChild.nextElementSibling === c.element is true
+PASS node.element.lastElementChild === a.element is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodeinsertBeforehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/insertBefore.html (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/insertBefore.html         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/insertBefore.html        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,59 @@
</span><ins>+<script src="../../../resources/js-test-pre.js"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/scheduler.js" type="text/javascript"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/layout-node.js" type="text/javascript"></script>
+<script type="text/javascript">
+
+description("Testing the <code>LayoutNode.insertBefore(newSibling, referenceSibling)</code> method.");
+
+window.jsTestIsAsync = true;
+
+const node = new LayoutNode;
+
+const a = new LayoutNode;
+const b = new LayoutNode;
+const c = new LayoutNode;
+
+debug("node.insertBefore(c)");
+const retVal = node.insertBefore(c);
+shouldBeTrue("node.children.length === 1");
+shouldBeTrue("node.children[0] === c");
+shouldBeTrue("retVal === c");
+
+debug("");
+debug("node.insertBefore(a, c)");
+node.insertBefore(a, c);
+shouldBeTrue("node.children.length === 2");
+shouldBeTrue("node.children[0] === a");
+shouldBeTrue("node.children[1] === c");
+
+debug("");
+debug("node.insertBefore(b, c)");
+node.insertBefore(b, c);
+shouldBeTrue("node.children.length === 3");
+shouldBeTrue("node.children[0] === a");
+shouldBeTrue("node.children[1] === b");
+shouldBeTrue("node.children[2] === c");
+
+debug("");
+debug("node.insertBefore(a, c)");
+node.insertBefore(a, c);
+shouldBeTrue("node.children.length === 3");
+shouldBeTrue("node.children[0] === b");
+shouldBeTrue("node.children[1] === c");
+shouldBeTrue("node.children[2] === a");
+
+scheduler.frameDidFire = function()
+{
+ debug("");
+ debug("Layout was performed");
+
+ shouldBeTrue("node.element.childElementCount === 3");
+ shouldBeTrue("node.element.firstElementChild === b.element");
+ shouldBeTrue("node.element.firstElementChild.nextElementSibling === c.element");
+ shouldBeTrue("node.element.lastElementChild === a.element");
+
+ finishJSTest();
+};
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodeparentexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/parent-expected.txt (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/parent-expected.txt         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/parent-expected.txt        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,40 @@
</span><ins>+Testing the LayoutNode.parent property.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Checking nodes have a null parent by default
+PASS a.parent === null is true
+PASS b.parent === null is true
+PASS c.parent === null is true
+PASS d.parent === null is true
+
+node.children = [a, b, c]
+PASS a.parent === node is true
+PASS b.parent === node is true
+PASS c.parent === node is true
+
+a.remove()
+PASS a.parent === null is true
+
+node.removeChild(b)
+PASS b.parent === null is true
+
+node.addChild(a)
+PASS a.parent === node is true
+
+node.insertBefore(b, c)
+PASS b.parent === node is true
+
+node.insertAfter(d, c)
+PASS d.parent === node is true
+
+node.children = []
+PASS a.parent === null is true
+PASS b.parent === null is true
+PASS c.parent === null is true
+PASS d.parent === null is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodeparenthtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/parent.html (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/parent.html         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/parent.html        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,62 @@
</span><ins>+<script src="../../../resources/js-test-pre.js"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/scheduler.js" type="text/javascript"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/layout-node.js" type="text/javascript"></script>
+<script type="text/javascript">
+
+description("Testing the <code>LayoutNode.parent</code> property.");
+
+const node = new LayoutNode;
+
+const a = new LayoutNode;
+const b = new LayoutNode;
+const c = new LayoutNode;
+const d = new LayoutNode;
+
+debug("Checking nodes have a null parent by default");
+shouldBeTrue("a.parent === null");
+shouldBeTrue("b.parent === null");
+shouldBeTrue("c.parent === null");
+shouldBeTrue("d.parent === null");
+
+debug("");
+debug("node.children = [a, b, c]");
+node.children = [a, b, c];
+shouldBeTrue("a.parent === node");
+shouldBeTrue("b.parent === node");
+shouldBeTrue("c.parent === node");
+
+debug("");
+debug("a.remove()");
+a.remove();
+shouldBeTrue("a.parent === null");
+
+debug("");
+debug("node.removeChild(b)");
+node.removeChild(b);
+shouldBeTrue("b.parent === null");
+
+debug("");
+debug("node.addChild(a)");
+node.addChild(a);
+shouldBeTrue("a.parent === node");
+
+debug("");
+debug("node.insertBefore(b, c)");
+node.insertBefore(b, c);
+shouldBeTrue("b.parent === node");
+
+debug("");
+debug("node.insertAfter(d, c)");
+node.insertAfter(d, c);
+shouldBeTrue("d.parent === node");
+
+debug("");
+debug("node.children = []");
+node.children = [];
+shouldBeTrue("a.parent === null");
+shouldBeTrue("b.parent === null");
+shouldBeTrue("c.parent === null");
+shouldBeTrue("d.parent === null");
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnoderemoveexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/remove-expected.txt (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/remove-expected.txt         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/remove-expected.txt        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+Testing the LayoutNode.remove() method.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+node.children = [a, b, c]
+PASS node.children.length === 3 is true
+PASS node.children[0] === a is true
+PASS node.children[1] === b is true
+PASS node.children[2] === c is true
+
+b.remove()
+PASS node.children.length === 2 is true
+PASS node.children[0] === a is true
+PASS node.children[1] === c is true
+PASS retVal === b is true
+
+a.remove()
+PASS node.children.length === 1 is true
+PASS node.children[0] === c is true
+
+Layout was performed
+PASS node.element.childElementCount === 1 is true
+PASS node.element.firstElementChild === c.element is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnoderemovehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/remove.html (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/remove.html         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/remove.html        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,49 @@
</span><ins>+<script src="../../../resources/js-test-pre.js"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/scheduler.js" type="text/javascript"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/layout-node.js" type="text/javascript"></script>
+<script type="text/javascript">
+
+description("Testing the <code>LayoutNode.remove()</code> method.");
+
+window.jsTestIsAsync = true;
+
+const node = new LayoutNode;
+
+const a = new LayoutNode;
+const b = new LayoutNode;
+const c = new LayoutNode;
+
+debug("node.children = [a, b, c]");
+node.children = [a, b, c];
+shouldBeTrue("node.children.length === 3");
+shouldBeTrue("node.children[0] === a");
+shouldBeTrue("node.children[1] === b");
+shouldBeTrue("node.children[2] === c");
+
+debug("");
+debug("b.remove()");
+const retVal = b.remove();
+shouldBeTrue("node.children.length === 2");
+shouldBeTrue("node.children[0] === a");
+shouldBeTrue("node.children[1] === c");
+shouldBeTrue("retVal === b");
+
+debug("");
+debug("a.remove()");
+a.remove();
+shouldBeTrue("node.children.length === 1");
+shouldBeTrue("node.children[0] === c");
+
+scheduler.frameDidFire = function()
+{
+ debug("");
+ debug("Layout was performed");
+
+ shouldBeTrue("node.element.childElementCount === 1");
+ shouldBeTrue("node.element.firstElementChild === c.element");
+
+ finishJSTest();
+};
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnoderemoveChildexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/removeChild-expected.txt (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/removeChild-expected.txt         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/removeChild-expected.txt        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,32 @@
</span><ins>+Testing the LayoutNode.removeChild(child) method.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+node.children = [a, b, c]
+PASS node.children.length === 3 is true
+PASS node.children[0] === a is true
+PASS node.children[1] === b is true
+PASS node.children[2] === c is true
+
+node.removeChild(b)
+PASS node.children.length === 2 is true
+PASS node.children[0] === a is true
+PASS node.children[1] === c is true
+PASS retVal === b is true
+
+node.removeChild(a)
+PASS node.children.length === 1 is true
+PASS node.children[0] === c is true
+
+node.removeChild(a)
+PASS node.children.length === 1 is true
+PASS node.children[0] === c is true
+
+Layout was performed
+PASS node.element.childElementCount === 1 is true
+PASS node.element.firstElementChild === c.element is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnoderemoveChildhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/removeChild.html (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/removeChild.html         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/removeChild.html        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,55 @@
</span><ins>+<script src="../../../resources/js-test-pre.js"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/scheduler.js" type="text/javascript"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/layout-node.js" type="text/javascript"></script>
+<script type="text/javascript">
+
+description("Testing the <code>LayoutNode.removeChild(child)</code> method.");
+
+window.jsTestIsAsync = true;
+
+const node = new LayoutNode;
+
+const a = new LayoutNode;
+const b = new LayoutNode;
+const c = new LayoutNode;
+
+debug("node.children = [a, b, c]");
+node.children = [a, b, c];
+shouldBeTrue("node.children.length === 3");
+shouldBeTrue("node.children[0] === a");
+shouldBeTrue("node.children[1] === b");
+shouldBeTrue("node.children[2] === c");
+
+debug("");
+debug("node.removeChild(b)");
+const retVal = node.removeChild(b);
+shouldBeTrue("node.children.length === 2");
+shouldBeTrue("node.children[0] === a");
+shouldBeTrue("node.children[1] === c");
+shouldBeTrue("retVal === b");
+
+debug("");
+debug("node.removeChild(a)");
+node.removeChild(a);
+shouldBeTrue("node.children.length === 1");
+shouldBeTrue("node.children[0] === c");
+
+debug("");
+debug("node.removeChild(a)");
+node.removeChild(a);
+shouldBeTrue("node.children.length === 1");
+shouldBeTrue("node.children[0] === c");
+
+scheduler.frameDidFire = function()
+{
+ debug("");
+ debug("Layout was performed");
+
+ shouldBeTrue("node.element.childElementCount === 1");
+ shouldBeTrue("node.element.firstElementChild === c.element");
+
+ finishJSTest();
+};
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodesubclassingexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/subclassing-expected.txt (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/subclassing-expected.txt         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/subclassing-expected.txt        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+Subclassing LayoutNode by exposing a new custom property.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Check the node is not dirty by default
+PASS node.needsLayout is false
+
+node.opacity = 0.5
+PASS node.needsLayout is true
+
+Layout will be performed
+OpacityNode.layout() was called
+OpacityNode.commitProperty() was called with propertyName = opacity
+
+Layout was performed
+PASS node.element.style.opacity is "0.5"
+
+node.needsLayout = true
+
+Layout will be performed
+OpacityNode.layout() was called
+
+Layout was performed
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodesubclassinghtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/subclassing.html (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/subclassing.html         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/subclassing.html        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,79 @@
</span><ins>+<script src="../../../resources/js-test-pre.js"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/scheduler.js" type="text/javascript"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/layout-node.js" type="text/javascript"></script>
+<script type="text/javascript">
+
+description("Subclassing <code>LayoutNode</code> by exposing a new custom property.");
+
+window.jsTestIsAsync = true;
+
+class OpacityNode extends LayoutNode
+{
+
+ constructor(stringOrElement)
+ {
+ super(stringOrElement);
+
+ this._opacity = 1;
+ }
+
+ set opacity(opacity)
+ {
+ this._opacity = opacity;
+ this.markDirtyProperty("opacity");
+ }
+
+ commitProperty(propertyName)
+ {
+ debug(`OpacityNode.commitProperty() was called with propertyName = ${propertyName}`);
+ if (propertyName === "opacity")
+ this.element.style.opacity = this._opacity;
+ else
+ super.commitProperty(propertyName);
+ }
+
+ layout()
+ {
+ debug("OpacityNode.layout() was called");
+ super.layout();
+ }
+
+}
+
+const node = new OpacityNode;
+
+debug("Check the node is not dirty by default");
+shouldBeFalse("node.needsLayout");
+
+debug("");
+debug("node.opacity = 0.5");
+node.opacity = 0.5;
+shouldBeTrue("node.needsLayout");
+
+let numberOfFrames = 0;
+scheduler.frameDidFire = function()
+{
+ debug("");
+ debug("Layout was performed");
+
+ switch (++numberOfFrames) {
+ case 1:
+ shouldBeEqualToString("node.element.style.opacity", "0.5");
+ debug("");
+ debug("node.needsLayout = true");
+ node.needsLayout = true;
+ break;
+ case 2:
+ finishJSTest();
+ break;
+ }
+};
+
+scheduler.frameWillFire = function()
+{
+ debug("");
+ debug("Layout will be performed");
+};
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodevisibleexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/visible-expected.txt (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/visible-expected.txt         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/visible-expected.txt        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,26 @@
</span><ins>+Testing the LayoutNode.visible property.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Checking default value
+PASS node.visible is true
+PASS node.element.style.display is ""
+
+node.visible = false
+PASS node.visible is false
+PASS node.element.style.display is ""
+
+Layout was performed
+PASS node.visible is false
+PASS node.element.style.display is "none"
+
+node.visible = true
+
+Layout was performed
+PASS node.visible is true
+PASS node.element.style.display is "inherit"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodevisiblehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/visible.html (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/visible.html         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/visible.html        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,45 @@
</span><ins>+<script src="../../../resources/js-test-pre.js"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/scheduler.js" type="text/javascript"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/layout-node.js" type="text/javascript"></script>
+<script type="text/javascript">
+
+description("Testing the <code>LayoutNode.visible</code> property.");
+
+window.jsTestIsAsync = true;
+
+const node = new LayoutNode;
+
+debug("Checking default value");
+shouldBe("node.visible", "true");
+shouldBeEqualToString("node.element.style.display", "");
+
+debug("");
+debug("node.visible = false");
+node.visible = false;
+shouldBe("node.visible", "false");
+shouldBeEqualToString("node.element.style.display", "");
+
+let numberOfFrames = 0;
+scheduler.frameDidFire = function()
+{
+ debug("");
+ debug("Layout was performed");
+
+ switch (++numberOfFrames) {
+ case 1:
+ shouldBe("node.visible", "false");
+ shouldBeEqualToString("node.element.style.display", "none");
+ debug("");
+ debug("node.visible = true");
+ node.visible = true;
+ break;
+ case 2:
+ shouldBe("node.visible", "true");
+ shouldBeEqualToString("node.element.style.display", "inherit");
+ finishJSTest();
+ break;
+ }
+};
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodewidthexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/width-expected.txt (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/width-expected.txt         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/width-expected.txt        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,22 @@
</span><ins>+Testing the LayoutNode.width property.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Checking default value
+PASS node.width is 0
+PASS node.element.style.width is ""
+
+node.width = 10
+PASS node.width is 10
+PASS node.element.style.width is ""
+
+node.width = 20
+
+Layout was performed
+PASS node.width is 20
+PASS node.element.style.width is "20px"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodewidthhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/width.html (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/width.html         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/width.html        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,37 @@
</span><ins>+<script src="../../../resources/js-test-pre.js"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/scheduler.js" type="text/javascript"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/layout-node.js" type="text/javascript"></script>
+<script type="text/javascript">
+
+description("Testing the <code>LayoutNode.width</code> property.");
+
+window.jsTestIsAsync = true;
+
+const node = new LayoutNode;
+
+debug("Checking default value");
+shouldBe("node.width", "0");
+shouldBeEqualToString("node.element.style.width", "");
+
+debug("");
+debug("node.width = 10");
+node.width = 10;
+shouldBe("node.width", "10");
+shouldBeEqualToString("node.element.style.width", "");
+
+// Set the value to another one so we can check it's the one committed to the DOM.
+debug("");
+debug("node.width = 20");
+node.width = 20;
+
+scheduler.frameDidFire = function()
+{
+ debug("");
+ debug("Layout was performed");
+ shouldBe("node.width", "20");
+ shouldBeEqualToString("node.element.style.width", "20px");
+ finishJSTest();
+};
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodexexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/x-expected.txt (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/x-expected.txt         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/x-expected.txt        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,22 @@
</span><ins>+Testing the LayoutNode.x property.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Checking default value
+PASS node.x is 0
+PASS node.element.style.left is ""
+
+node.x = 10
+PASS node.x is 10
+PASS node.element.style.left is ""
+
+node.x = 20
+
+Layout was performed
+PASS node.x is 20
+PASS node.element.style.left is "20px"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodexhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/x.html (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/x.html         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/x.html        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,37 @@
</span><ins>+<script src="../../../resources/js-test-pre.js"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/scheduler.js" type="text/javascript"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/layout-node.js" type="text/javascript"></script>
+<script type="text/javascript">
+
+description("Testing the <code>LayoutNode.x</code> property.");
+
+window.jsTestIsAsync = true;
+
+const node = new LayoutNode;
+
+debug("Checking default value");
+shouldBe("node.x", "0");
+shouldBeEqualToString("node.element.style.left", "");
+
+debug("");
+debug("node.x = 10");
+node.x = 10;
+shouldBe("node.x", "10");
+shouldBeEqualToString("node.element.style.left", "");
+
+// Set the value to another one so we can check it's the one committed to the DOM.
+debug("");
+debug("node.x = 20");
+node.x = 20;
+
+scheduler.frameDidFire = function()
+{
+ debug("");
+ debug("Layout was performed");
+ shouldBe("node.x", "20");
+ shouldBeEqualToString("node.element.style.left", "20px");
+ finishJSTest();
+};
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodeyexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/y-expected.txt (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/y-expected.txt         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/y-expected.txt        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,22 @@
</span><ins>+Testing the LayoutNode.y property.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Checking default value
+PASS node.y is 0
+PASS node.element.style.top is ""
+
+node.y = 10
+PASS node.y is 10
+PASS node.element.style.top is ""
+
+node.y = 20
+
+Layout was performed
+PASS node.y is 20
+PASS node.element.style.top is "20px"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolslayoutnodeyhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/layout-node/y.html (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/layout-node/y.html         (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/layout-node/y.html        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,37 @@
</span><ins>+<script src="../../../resources/js-test-pre.js"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/scheduler.js" type="text/javascript"></script>
+<script src="../../../../Source/WebCore/Modules/modern-media-controls/controls/layout-node.js" type="text/javascript"></script>
+<script type="text/javascript">
+
+description("Testing the <code>LayoutNode.y</code> property.");
+
+window.jsTestIsAsync = true;
+
+const node = new LayoutNode;
+
+debug("Checking default value");
+shouldBe("node.y", "0");
+shouldBeEqualToString("node.element.style.top", "");
+
+debug("");
+debug("node.y = 10");
+node.y = 10;
+shouldBe("node.y", "10");
+shouldBeEqualToString("node.element.style.top", "");
+
+// Set the value to another one so we can check it's the one committed to the DOM.
+debug("");
+debug("node.y = 20");
+node.y = 20;
+
+scheduler.frameDidFire = function()
+{
+ debug("");
+ debug("Layout was performed");
+ shouldBe("node.y", "20");
+ shouldBeEqualToString("node.element.style.top", "20px");
+ finishJSTest();
+};
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (206685 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-09-30 22:43:40 UTC (rev 206685)
+++ trunk/Source/WebCore/ChangeLog        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -1,3 +1,81 @@
</span><ins>+2016-09-30 Antoine Quint <graouts@apple.com>
+
+ [Modern Media Controls] layout nodes
+ https://bugs.webkit.org/show_bug.cgi?id=162799
+ <rdar://problem/28569301>
+
+ Reviewed by Dean Jackson.
+
+ Modern media controls will be using a tree of LayoutNode objects that commit to the DOM
+ in coordinated `requestAnimationFrame()` calls to ensure all layouts are done in an efficient
+ and coordinated manner. As a preamble, we introduced the `scheduler` singleton in
+ https://webkit.org/b/162726 which is in charge of scheduling callbacks.
+
+ A LayoutNode is created by providing an Element to its constructor, or an HTML string. Not
+ providing a parameter creates a simple <div>.
+
+ When we set a property on a LayoutNode, we call `markDirtyProperty(propertyName)` which keeps
+ track of dirty properties in the `_dirtyProperties` set. When this set is non-empty, the node
+ is marked as dirty and registered in the global `dirtyNodes` map, asking the shared scheduler
+ that a layout is needed. When the layout is performed, all nodes in the `dirtyNodes` map are
+ processed such that `commitProperty(propertyName)` is called to commit dirty properties for
+ a given node to the DOM, and `layout()` is called to allow subclasses of LayoutNode to conduct
+ custom layout logic that goes beyond committing a given property.
+
+ Another reason why a node may be marked as dirty is when a DOM hierarchy change is needed. A
+ host of DOM-like methods are exposed to allow flexible manipulations of nodes, with an extra
+ `children` property which allows wholesale change of a node's subtree with a single array
+ property assignment. Changes to the DOM hierarchy are performed in the same scheduler callback
+ as style properties.
+
+ Nodes can be marked for layout explicitly with by setting the `needsLayout` property.
+
+ Tests: media/modern-media-controls/layout-node/addChild.html
+ media/modern-media-controls/layout-node/children.html
+ media/modern-media-controls/layout-node/constructor.html
+ media/modern-media-controls/layout-node/height.html
+ media/modern-media-controls/layout-node/insertAfter.html
+ media/modern-media-controls/layout-node/insertBefore.html
+ media/modern-media-controls/layout-node/parent.html
+ media/modern-media-controls/layout-node/remove.html
+ media/modern-media-controls/layout-node/removeChild.html
+ media/modern-media-controls/layout-node/subclassing.html
+ media/modern-media-controls/layout-node/visible.html
+ media/modern-media-controls/layout-node/width.html
+ media/modern-media-controls/layout-node/x.html
+ media/modern-media-controls/layout-node/y.html
+
+ * Modules/modern-media-controls/controls/layout-node.js: Added.
+ (LayoutNode):
+ (LayoutNode.prototype.get x):
+ (LayoutNode.prototype.set x):
+ (LayoutNode.prototype.get y):
+ (LayoutNode.prototype.set y):
+ (LayoutNode.prototype.get width):
+ (LayoutNode.prototype.set width):
+ (LayoutNode.prototype.get height):
+ (LayoutNode.prototype.set height):
+ (LayoutNode.prototype.get visible):
+ (LayoutNode.prototype.set visible):
+ (LayoutNode.prototype.get needsLayout):
+ (LayoutNode.prototype.set needsLayout):
+ (LayoutNode.prototype.get parent):
+ (LayoutNode.prototype.get children):
+ (LayoutNode.prototype.set children):
+ (LayoutNode.prototype.addChild):
+ (LayoutNode.prototype.insertBefore):
+ (LayoutNode.prototype.insertAfter):
+ (LayoutNode.prototype.removeChild):
+ (LayoutNode.prototype.remove):
+ (LayoutNode.prototype.markDirtyProperty):
+ (LayoutNode.prototype.commitProperty):
+ (LayoutNode.prototype.layout):
+ (LayoutNode.prototype._markNodeManipulation):
+ (LayoutNode.prototype._updateDirtyState):
+ (LayoutNode.prototype._updateChildren):
+ (performScheduledLayout):
+ (elementFromString):
+
</ins><span class="cx"> 2016-09-30 Said Abou-Hallawa <sabouhallawa@apple.com>
</span><span class="cx">
</span><span class="cx"> The dragged image should be the current frame only of the animated image
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmodernmediacontrolscontrolslayoutnodejs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/Modules/modern-media-controls/controls/layout-node.js (0 => 206686)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/modern-media-controls/controls/layout-node.js         (rev 0)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/layout-node.js        2016-09-30 22:45:17 UTC (rev 206686)
</span><span class="lines">@@ -0,0 +1,270 @@
</span><ins>+
+const dirtyNodes = new Set;
+const nodesRequiringChildrenUpdate = new Set;
+
+class LayoutNode
+{
+
+ constructor(stringOrElement)
+ {
+
+ if (!stringOrElement)
+ this.element = document.createElement("div");
+ else if (stringOrElement instanceof Element)
+ this.element = stringOrElement;
+ else if (typeof stringOrElement === "string" || stringOrElement instanceof String)
+ this.element = elementFromString(stringOrElement);
+
+ this._parent = null;
+ this._children = [];
+
+ this._x = 0;
+ this._y = 0;
+ this._width = 0;
+ this._height = 0;
+ this._visible = true;
+
+ this._needsLayout = false;
+ this._dirtyProperties = new Set;
+
+ this._pendingDOMManipulation = LayoutNode.DOMManipulation.None;
+ }
+
+ get x()
+ {
+ return this._x;
+ }
+
+ set x(x)
+ {
+ this._x = x;
+ this.markDirtyProperty("x");
+ }
+
+ get y()
+ {
+ return this._y;
+ }
+
+ set y(y)
+ {
+ this._y = y;
+ this.markDirtyProperty("y");
+ }
+
+ get width()
+ {
+ return this._width;
+ }
+
+ set width(width)
+ {
+ this._width = width;
+ this.markDirtyProperty("width");
+ }
+
+ get height()
+ {
+ return this._height;
+ }
+
+ set height(height)
+ {
+ this._height = height;
+ this.markDirtyProperty("height");
+ }
+
+ get visible()
+ {
+ return this._visible;
+ }
+
+ set visible(flag)
+ {
+ this._visible = flag;
+ this.markDirtyProperty("visible");
+ }
+
+ get needsLayout()
+ {
+ return this._needsLayout || this._pendingDOMManipulation !== LayoutNode.DOMManipulation.None || this._dirtyProperties.size > 0;
+ }
+
+ set needsLayout(flag)
+ {
+ if (this.needsLayout === flag)
+ return;
+
+ this._needsLayout = true;
+ this._updateDirtyState();
+ }
+
+ get parent()
+ {
+ return this._parent;
+ }
+
+ get children()
+ {
+ return this._children;
+ }
+
+ set children(children)
+ {
+ while (this._children.length)
+ this.removeChild(this._children[0]);
+
+ for (let child of children)
+ this.addChild(child);
+ }
+
+ addChild(child, index)
+ {
+ child.remove();
+
+ if (index === undefined || index < 0 || index > this._children.length)
+ index = this._children.length;
+
+ this._children.splice(index, 0, child);
+ child._parent = this;
+
+ child._markNodeManipulation(LayoutNode.DOMManipulation.Addition);
+
+ return child;
+ }
+
+ insertBefore(newSibling, referenceSibling)
+ {
+ return this.addChild(newSibling, this._children.indexOf(referenceSibling));
+ }
+
+ insertAfter(newSibling, referenceSibling)
+ {
+ const index = this._children.indexOf(referenceSibling);
+ return this.addChild(newSibling, index + 1);
+ }
+
+ removeChild(child)
+ {
+ if (child._parent !== this)
+ return;
+
+ const index = this._children.indexOf(child);
+ if (index === -1)
+ return;
+
+ this._children.splice(index, 1);
+ child._parent = null;
+
+ child._markNodeManipulation(LayoutNode.DOMManipulation.Removal);
+
+ return child;
+ }
+
+ remove()
+ {
+ if (this._parent instanceof LayoutNode)
+ return this._parent.removeChild(this);
+ }
+
+ markDirtyProperty(propertyName) {
+ const hadProperty = this._dirtyProperties.has(propertyName);
+ this._dirtyProperties.add(propertyName);
+
+ if (!hadProperty)
+ this._updateDirtyState();
+ }
+
+ commitProperty(propertyName)
+ {
+ const style = this.element.style;
+
+ switch (propertyName) {
+ case "x":
+ style.left = `${this._x}px`;
+ break;
+ case "y":
+ style.top = `${this._y}px`;
+ break;
+ case "width":
+ style.width = `${this._width}px`;
+ break;
+ case "height":
+ style.height = `${this._height}px`;
+ break;
+ case "visible":
+ style.display = this._visible ? "inherit" : "none";
+ break;
+ }
+ }
+
+ layout()
+ {
+ if (this._pendingDOMManipulation === LayoutNode.DOMManipulation.Removal) {
+ const parent = this.element.parentNode;
+ if (parent)
+ parent.removeChild(this.element);
+ }
+
+ for (let propertyName of this._dirtyProperties)
+ this.commitProperty(propertyName);
+
+ this._dirtyProperties.clear();
+
+ if (this._pendingDOMManipulation === LayoutNode.DOMManipulation.Addition)
+ nodesRequiringChildrenUpdate.add(this.parent);
+ }
+
+ // Private
+
+ _markNodeManipulation(manipulation) {
+ this._pendingDOMManipulation = manipulation;
+ this._updateDirtyState();
+ }
+
+ _updateDirtyState() {
+ if (this.needsLayout) {
+ dirtyNodes.add(this);
+ scheduler.scheduleLayout(performScheduledLayout);
+ } else
+ dirtyNodes.delete(node);
+ }
+
+ _updateChildren()
+ {
+ let nextChildElement = null;
+ const element = this.element;
+ for (let i = this.children.length - 1; i >= 0; --i) {
+ let child = this.children[i];
+ let childElement = child.element;
+
+ if (child._pendingDOMManipulation === LayoutNode.DOMManipulation.Addition) {
+ element.insertBefore(childElement, nextChildElement);
+ child._pendingDOMManipulation = LayoutNode.DOMManipulation.None;
+ }
+
+ nextChildElement = childElement;
+ }
+ }
+
+}
+
+LayoutNode.DOMManipulation = {
+ None: 0,
+ Removal: 1,
+ Addition: 2
+};
+
+function performScheduledLayout() {
+ dirtyNodes.forEach(node => node.layout());
+ dirtyNodes.clear();
+
+ nodesRequiringChildrenUpdate.forEach(node => node._updateChildren());
+ nodesRequiringChildrenUpdate.clear();
+}
+
+function elementFromString(elementString) {
+ const element = document.createElement("div");
+ element.innerHTML = elementString;
+ return element.firstElementChild;
+}
</ins></span></pre>
</div>
</div>
</body>
</html>