Title: [237436] trunk
Revision
237436
Author
[email protected]
Date
2018-10-25 16:59:43 -0700 (Thu, 25 Oct 2018)

Log Message

Web Inspector: Canvas Recording loading goes significantly slower when "Frame" tree element is expanded
https://bugs.webkit.org/show_bug.cgi?id=190497

Reviewed by Joseph Pecoraro.

Source/WebInspectorUI:

Save the `WI.TreeElement` that are in the DOM, and compare that with any `WI.TreeElement`
that would be added to the DOM. If all of the following are true, don't edit the DOM:
 - no focused `WI.TreeElement` that isn't currently visible (we would scroll otherwise)
 - the set of previously visible `WI.TreeElement`s (e.g. not used for scroll padding) has at
   least one of the `WI.TreeElement`s that would be added from this update
    - this means that the user hasn't scrolled beyond the padding `WI.TreeElement`
 - there are no `WI.TreeElement`s that would be added from this update that were NOT added
   in a previous update
    - this covers the case that a `WI.TreeElement` is inserted in the visible area

* UserInterface/Base/Utilities.js:

* UserInterface/Views/TreeOutline.js:
(WI.TreeOutline):
(WI.TreeOutline.prototype.registerScrollVirtualizer):
(WI.TreeOutline.prototype.updateVirtualizedElements.walk):
(WI.TreeOutline.prototype.updateVirtualizedElements):

LayoutTests:

* inspector/unit-tests/set-utilities-expected.txt: Added.
* inspector/unit-tests/set-utilities.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (237435 => 237436)


--- trunk/LayoutTests/ChangeLog	2018-10-25 23:55:12 UTC (rev 237435)
+++ trunk/LayoutTests/ChangeLog	2018-10-25 23:59:43 UTC (rev 237436)
@@ -1,3 +1,13 @@
+2018-10-25  Devin Rousso  <[email protected]>
+
+        Web Inspector: Canvas Recording loading goes significantly slower when "Frame" tree element is expanded
+        https://bugs.webkit.org/show_bug.cgi?id=190497
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/unit-tests/set-utilities-expected.txt: Added.
+        * inspector/unit-tests/set-utilities.html: Added.
+
 2018-10-25  Dawei Fenton  <[email protected]>
 
         Layout Test compositing/iframes/display-none-subframe.html is a flaky failure.

Added: trunk/LayoutTests/inspector/unit-tests/set-utilities-expected.txt (0 => 237436)


--- trunk/LayoutTests/inspector/unit-tests/set-utilities-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/set-utilities-expected.txt	2018-10-25 23:59:43 UTC (rev 237436)
@@ -0,0 +1,18 @@
+
+== Running test suite: SetUtilities
+-- Running test case: Set.prototype.intersects
+PASS: an empty set should not intersect another empty set.
+PASS: a non-empty set should not intersect an empty set.
+PASS: a set should intersect another set with the same values.
+PASS: a set should not intersect another set with different values.
+PASS: a set should intersect another set with same and additional values.
+PASS: a set should intersect another set with same and different values.
+
+-- Running test case: Set.prototype.isSubsetOf
+PASS: an empty set should be a subset of another empty set.
+PASS: an empty set should be a subset of a non-empty set.
+PASS: a set should be a subset of another set with the same values.
+PASS: a set should not be a subset of another set with different values.
+PASS: a set should be a subset of another set with same and additional values.
+PASS: a set should not be a subset of another set with same and different values.
+

Added: trunk/LayoutTests/inspector/unit-tests/set-utilities.html (0 => 237436)


--- trunk/LayoutTests/inspector/unit-tests/set-utilities.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/set-utilities.html	2018-10-25 23:59:43 UTC (rev 237436)
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script>
+function test()
+{
+    let suite = InspectorTest.createSyncSuite("SetUtilities");
+
+    suite.addTestCase({
+        name: "Set.prototype.intersects",
+        test() {
+            function testTrue(a, b, message) {
+                InspectorTest.expectThat((new Set(a)).intersects(new Set(b)), message);
+            }
+
+            function testFalse(a, b, message) {
+                InspectorTest.expectFalse((new Set(a)).intersects(new Set(b)), message);
+            }
+
+            const object1 = {a: 1};
+            const object2 = {b: 2};
+            const object3 = {c: 3};
+
+            testFalse([], [], "an empty set should not intersect another empty set.");
+            testFalse([1, "a", object1], [], "a non-empty set should not intersect an empty set.");
+            testTrue([1, "a", object1], [1, "a", object1], "a set should intersect another set with the same values.");
+            testFalse([1, "a", object1], [2, "b", object2], "a set should not intersect another set with different values.");
+            testTrue([1, "a", object1], [1, 3, "a", "c", object1, object3], "a set should intersect another set with same and additional values.");
+            testTrue([1, 2, "a", "b", object1, object2], [1, 3, "a", "c", object1, object3], "a set should intersect another set with same and different values.");
+
+            return true;
+        }
+    });
+
+    suite.addTestCase({
+        name: "Set.prototype.isSubsetOf",
+        test() {
+            function testTrue(a, b, message) {
+                InspectorTest.expectThat((new Set(a)).isSubsetOf(new Set(b)), message);
+            }
+
+            function testFalse(a, b, message) {
+                InspectorTest.expectFalse((new Set(a)).isSubsetOf(new Set(b)), message);
+            }
+
+            const object1 = {a: 1};
+            const object2 = {b: 2};
+            const object3 = {c: 3};
+
+            testTrue([], [], "an empty set should be a subset of another empty set.");
+            testTrue([], [2, "b", object2], "an empty set should be a subset of a non-empty set.");
+            testTrue([1, "a", object1], [1, "a", object1], "a set should be a subset of another set with the same values.");
+            testFalse([1, "a", object1], [2, "b", object2], "a set should not be a subset of another set with different values.");
+            testTrue([1, "a", object1], [1, 3, "a", "c", object1, object3], "a set should be a subset of another set with same and additional values.");
+            testFalse([1, 2, "a", "b", object1, object2], [1, 3, "a", "c", object1, object3], "a set should not be a subset of another set with same and different values.");
+
+            return true;
+        }
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onLoad_="runTest()">
+</body>
+</html>

Modified: trunk/Source/WebInspectorUI/ChangeLog (237435 => 237436)


--- trunk/Source/WebInspectorUI/ChangeLog	2018-10-25 23:55:12 UTC (rev 237435)
+++ trunk/Source/WebInspectorUI/ChangeLog	2018-10-25 23:59:43 UTC (rev 237436)
@@ -1,3 +1,28 @@
+2018-10-25  Devin Rousso  <[email protected]>
+
+        Web Inspector: Canvas Recording loading goes significantly slower when "Frame" tree element is expanded
+        https://bugs.webkit.org/show_bug.cgi?id=190497
+
+        Reviewed by Joseph Pecoraro.
+
+        Save the `WI.TreeElement` that are in the DOM, and compare that with any `WI.TreeElement`
+        that would be added to the DOM. If all of the following are true, don't edit the DOM:
+         - no focused `WI.TreeElement` that isn't currently visible (we would scroll otherwise)
+         - the set of previously visible `WI.TreeElement`s (e.g. not used for scroll padding) has at
+           least one of the `WI.TreeElement`s that would be added from this update
+            - this means that the user hasn't scrolled beyond the padding `WI.TreeElement`
+         - there are no `WI.TreeElement`s that would be added from this update that were NOT added
+           in a previous update
+            - this covers the case that a `WI.TreeElement` is inserted in the visible area
+
+        * UserInterface/Base/Utilities.js:
+
+        * UserInterface/Views/TreeOutline.js:
+        (WI.TreeOutline):
+        (WI.TreeOutline.prototype.registerScrollVirtualizer):
+        (WI.TreeOutline.prototype.updateVirtualizedElements.walk):
+        (WI.TreeOutline.prototype.updateVirtualizedElements):
+
 2018-10-25  Joseph Pecoraro  <[email protected]>
 
         JSContext Inspector: Broken frontend, DOMAgent is used but does not exist

Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js (237435 => 237436)


--- trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js	2018-10-25 23:55:12 UTC (rev 237435)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js	2018-10-25 23:59:43 UTC (rev 237436)
@@ -118,6 +118,35 @@
     }
 });
 
+Object.defineProperty(Set.prototype, "intersects",
+{
+    value(other)
+    {
+        if (!this.size || !other.size)
+            return false;
+
+        for (let item of this) {
+            if (other.has(item))
+                return true;
+        }
+
+        return false;
+    }
+});
+
+Object.defineProperty(Set.prototype, "isSubsetOf",
+{
+    value(other)
+    {
+        for (let item of this) {
+            if (!other.has(item))
+                return false;
+        }
+
+        return true;
+    }
+});
+
 Object.defineProperty(Node.prototype, "enclosingNodeOrSelfWithClass",
 {
     value(className)

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TreeOutline.js (237435 => 237436)


--- trunk/Source/WebInspectorUI/UserInterface/Views/TreeOutline.js	2018-10-25 23:55:12 UTC (rev 237435)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TreeOutline.js	2018-10-25 23:59:43 UTC (rev 237436)
@@ -55,7 +55,8 @@
         this._customIndent = false;
         this._selectable = selectable;
 
-        this._virtualizedCurrentMiddleItem = NaN;
+        this._virtualizedVisibleTreeElements = null;
+        this._virtualizedAttachedTreeElements = null;
         this._virtualizedScrollContainer = null;
         this._virtualizedTreeItemHeight = NaN;
         this._virtualizedTopSpacer = null;
@@ -654,16 +655,16 @@
     {
         console.assert(!isNaN(treeItemHeight));
 
+        this._virtualizedVisibleTreeElements = new Set;
+        this._virtualizedAttachedTreeElements = new Set;
         this._virtualizedScrollContainer = scrollContainer;
         this._virtualizedTreeItemHeight = treeItemHeight;
         this._virtualizedTopSpacer = document.createElement("div");
         this._virtualizedBottomSpacer = document.createElement("div");
 
+        let throttler = this.throttle(1000 / 16);
         this._virtualizedScrollContainer.addEventListener("scroll", (event) => {
-            let {numberVisible, extraRows, firstItem} = this._calculateVirtualizedValues();
-
-            if (Math.abs(firstItem + (numberVisible / 2) - this._virtualizedCurrentMiddleItem) >= extraRows)
-                this.updateVirtualizedElements();
+            throttler.updateVirtualizedElements();
         });
     }
 
@@ -678,11 +679,7 @@
                 if (!child.revealed(false))
                     continue;
 
-                shouldReturn = callback({
-                    parent,
-                    treeElement: child,
-                    count,
-                });
+                shouldReturn = callback(child, count);
                 if (shouldReturn)
                     break;
 
@@ -701,7 +698,7 @@
 
         let shouldScroll = false;
         if (focusedTreeElement && focusedTreeElement.revealed(false)) {
-            let index = walk(this, ({treeElement}) => treeElement === focusedTreeElement).count;
+            let index = walk(this, (treeElement) => treeElement === focusedTreeElement).count;
             if (index < firstItem) {
                 firstItem = index - extraRows;
                 lastItem = index + numberVisible + extraRows;
@@ -715,27 +712,54 @@
             shouldScroll = (index < firstItem + extraRows) || (index > lastItem - extraRows);
         }
 
-        let totalItems = walk(this, ({parent, treeElement, count}) => {
+        console.assert(firstItem < lastItem);
+
+        let visibleTreeElements = new Set;
+        let treeElementsToAttach = new Set;
+        let treeElementsToDetach = new Set;
+        let totalItems = walk(this, (treeElement, count) => {
             if (count >= firstItem && count <= lastItem) {
-                parent._childrenListNode.appendChild(treeElement.element);
-                if (treeElement._childrenListNode)
-                    parent._childrenListNode.appendChild(treeElement._childrenListNode);
-            } else
-                treeElement.element.remove();
+                treeElementsToAttach.add(treeElement);
+                if (count >= firstItem + extraRows && count <= lastItem - extraRows)
+                    visibleTreeElements.add(treeElement);
+            } else if (treeElement.element.parentNode)
+                treeElementsToDetach.add(treeElement);
 
             return false;
         }).count;
 
+        // Redraw if we are about to scroll.
+        if (!shouldScroll) {
+            // Redraw if all of the previously centered `WI.TreeElement` are no longer centered.
+            if (visibleTreeElements.intersects(this._virtualizedVisibleTreeElements)) {
+                // Redraw if there is a `WI.TreeElement` that should be shown that isn't attached.
+                if (visibleTreeElements.isSubsetOf(this._virtualizedAttachedTreeElements))
+                    return;
+            }
+        }
+
+        this._virtualizedVisibleTreeElements = visibleTreeElements;
+        this._virtualizedAttachedTreeElements = treeElementsToAttach;
+
+        for (let treeElement of treeElementsToDetach)
+            treeElement.element.remove();
+
+        for (let treeElement of treeElementsToAttach) {
+            treeElement.parent._childrenListNode.appendChild(treeElement.element);
+            if (treeElement._childrenListNode)
+                treeElement.parent._childrenListNode.appendChild(treeElement._childrenListNode);
+        }
+
         this._virtualizedTopSpacer.style.height = (Math.max(firstItem, 0) * this._virtualizedTreeItemHeight) + "px";
-        this.element.parentNode.insertBefore(this._virtualizedTopSpacer, this.element);
+        if (this.element.previousElementSibling !== this._virtualizedTopSpacer)
+            this.element.parentNode.insertBefore(this._virtualizedTopSpacer, this.element);
 
         this._virtualizedBottomSpacer.style.height = (Math.max(totalItems - lastItem, 0) * this._virtualizedTreeItemHeight) + "px";
-        this.element.parentNode.insertBefore(this._virtualizedBottomSpacer, this.element.nextElementSibling);
+        if (this.element.nextElementSibling !== this._virtualizedBottomSpacer)
+            this.element.parentNode.insertBefore(this._virtualizedBottomSpacer, this.element.nextElementSibling);
 
         if (shouldScroll)
             this._virtualizedScrollContainer.scrollTop = (firstItem + extraRows) * this._virtualizedTreeItemHeight;
-
-        this._virtualizedCurrentMiddleItem = firstItem + (numberVisible / 2);
     }
 
     // Protected
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to