Title: [193872] trunk/Source/WebInspectorUI
Revision
193872
Author
[email protected]
Date
2015-12-09 15:07:10 -0800 (Wed, 09 Dec 2015)

Log Message

Web Inspector: when a marked-dirty subview is attached to a parent View, dirtyDescendantsCount gets out of sync
https://bugs.webkit.org/show_bug.cgi?id=151876

Reviewed by Brian Burg.

* UserInterface/Base/Main.js:
Use root view singleton instead of creating it explicitly.

* UserInterface/Views/View.js:
(WebInspector.View):
(WebInspector.View.rootView):
Singleton root view access. Lazily create and return a view backed
by the document's body element.
(WebInspector.View.prototype.isDescendantOf):
(WebInspector.View.prototype.insertSubviewBefore):
(WebInspector.View.prototype.removeSubview):
(WebInspector.View.prototype.didMoveToWindow):
Notify the view when it becomes, or is no longer, descended from the root view.
(WebInspector.View.prototype.didMoveToParent):
Notify the view when it's added to, or removed from, a parent view.
(WebInspector.View._scheduleLayoutForView):
(WebInspector.View._cancelScheduledLayoutForView):
(WebInspector.View.prototype.makeRootView): Deleted.
No longer needed.
(WebInspector.View.prototype.didAttach): Deleted.
(WebInspector.View.prototype.didDetach): Deleted.
Replaced by didMoveToParent.

Modified Paths

Diff

Modified: trunk/Source/WebInspectorUI/ChangeLog (193871 => 193872)


--- trunk/Source/WebInspectorUI/ChangeLog	2015-12-09 22:46:10 UTC (rev 193871)
+++ trunk/Source/WebInspectorUI/ChangeLog	2015-12-09 23:07:10 UTC (rev 193872)
@@ -1,3 +1,33 @@
+2015-12-09  Matt Baker  <[email protected]>
+
+        Web Inspector: when a marked-dirty subview is attached to a parent View, dirtyDescendantsCount gets out of sync
+        https://bugs.webkit.org/show_bug.cgi?id=151876
+
+        Reviewed by Brian Burg.
+
+        * UserInterface/Base/Main.js:
+        Use root view singleton instead of creating it explicitly.
+
+        * UserInterface/Views/View.js:
+        (WebInspector.View):
+        (WebInspector.View.rootView):
+        Singleton root view access. Lazily create and return a view backed
+        by the document's body element.
+        (WebInspector.View.prototype.isDescendantOf):
+        (WebInspector.View.prototype.insertSubviewBefore):
+        (WebInspector.View.prototype.removeSubview):
+        (WebInspector.View.prototype.didMoveToWindow):
+        Notify the view when it becomes, or is no longer, descended from the root view.
+        (WebInspector.View.prototype.didMoveToParent):
+        Notify the view when it's added to, or removed from, a parent view.
+        (WebInspector.View._scheduleLayoutForView):
+        (WebInspector.View._cancelScheduledLayoutForView):
+        (WebInspector.View.prototype.makeRootView): Deleted.
+        No longer needed.
+        (WebInspector.View.prototype.didAttach): Deleted.
+        (WebInspector.View.prototype.didDetach): Deleted.
+        Replaced by didMoveToParent.
+
 2015-12-09  Brian Burg  <[email protected]>
 
         Web Inspector: control whether to collect and dump protocol messages using a WebInspector.Setting

Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Main.js (193871 => 193872)


--- trunk/Source/WebInspectorUI/UserInterface/Base/Main.js	2015-12-09 22:46:10 UTC (rev 193871)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Main.js	2015-12-09 23:07:10 UTC (rev 193872)
@@ -1438,7 +1438,7 @@
 
 WebInspector._setupViewHierarchy = function()
 {
-    let rootView = new WebInspector.View(document.body);
+    let rootView = WebInspector.View.rootView();
     rootView.addSubview(this.toolbar);
     rootView.addSubview(this.tabBar);
     rootView.addSubview(this.navigationSidebar);
@@ -1446,8 +1446,6 @@
     rootView.addSubview(this.splitContentBrowser);
     rootView.addSubview(this.quickConsole);
     rootView.addSubview(this.detailsSidebar);
-
-    rootView.makeRootView();
 };
 
 WebInspector._tabBrowserSelectedTabContentViewDidChange = function(event)

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/View.js (193871 => 193872)


--- trunk/Source/WebInspectorUI/UserInterface/Views/View.js	2015-12-09 22:46:10 UTC (rev 193871)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/View.js	2015-12-09 23:07:10 UTC (rev 193872)
@@ -35,8 +35,20 @@
         this._subviews = [];
         this._dirty = false;
         this._dirtyDescendantsCount = 0;
+        this._needsLayoutWhenAttachedToRoot = false;
+        this._isAttachedToRoot = false;
     }
 
+    // Static
+
+    static rootView()
+    {
+        if (!WebInspector.View._rootView)
+            WebInspector.View._rootView = new WebInspector.View(document.body);
+
+        return WebInspector.View._rootView;
+    }
+
     // Public
 
     get element()
@@ -59,14 +71,16 @@
         return this._subviews;
     }
 
-    makeRootView()
+    isDescendantOf(view)
     {
-        console.assert(!WebInspector.View._rootView, "Root view already exists.");
-        console.assert(!this._parentView, "Root view cannot be a subview.");
-        if (WebInspector.View._rootView)
-            return;
+        let parentView = this._parentView;
+        while (parentView) {
+            if (parentView === view)
+                return true;
+            parentView = parentView.parentView;
+        }
 
-        WebInspector.View._rootView = this;
+        return false;
     }
 
     addSubview(view)
@@ -96,7 +110,7 @@
         if (!view.element.parentNode)
             this._element.insertBefore(view.element, referenceView ? referenceView.element : null);
 
-        view.didAttach(this);
+        view.didMoveToParent(this);
     }
 
     removeSubview(view)
@@ -111,7 +125,8 @@
 
         this._subviews.remove(view, true);
         this._element.removeChild(view.element);
-        view.didDetach();
+
+        view.didMoveToParent(null);
     }
 
     replaceSubview(oldView, newView)
@@ -146,16 +161,38 @@
 
     // Protected
 
-    didAttach(parentView)
+    didMoveToWindow(isAttachedToRoot)
     {
-        console.assert(!this._parentView, "Attached view already has a parent.", this._parentView);
-        this._parentView = parentView;
+        this._isAttachedToRoot = isAttachedToRoot;
+
+        if (this._isAttachedToRoot && this._needsLayoutWhenAttachedToRoot) {
+            WebInspector.View._scheduleLayoutForView(this);
+            this._needsLayoutWhenAttachedToRoot = false;
+        }
+
+        for (let view of this._subviews)
+            view.didMoveToWindow(isAttachedToRoot);
     }
 
-    didDetach()
+    didMoveToParent(parentView)
     {
-        console.assert(this._parentView, "Detached view has no parent.");
-        this._parentView = null;
+        this._parentView = parentView;
+
+        let isAttachedToRoot = this.isDescendantOf(WebInspector.View._rootView);
+        this.didMoveToWindow(isAttachedToRoot);
+
+        if (!this._parentView)
+            return;
+
+        let pendingLayoutsCount = this._dirtyDescendantsCount;
+        if (this._dirty)
+            pendingLayoutsCount++;
+
+        let view = this._parentView;
+        while (view) {
+            view._dirtyDescendantsCount += pendingLayoutsCount;
+            view = view.parentView;
+        }
     }
 
     layout()
@@ -178,17 +215,10 @@
             view._layoutSubtree();
     }
 
-    // Private layout controller logic
+    // Layout controller logic
 
     static _scheduleLayoutForView(view)
     {
-        // Asynchronous layouts aren't scheduled until the root view has been set.
-        // If the root view hasn't been set, switch to a synchronous layout.
-        if (!WebInspector.View._rootView) {
-            view._layoutSubtree();
-            return;
-        }
-
         view._dirty = true;
 
         let parentView = view.parentView;
@@ -197,6 +227,13 @@
             parentView = parentView.parentView;
         }
 
+        if (!view._isAttachedToRoot) {
+            // Don't schedule layout of the view unless it is a descendant of the root view.
+            // When it moves to a rooted view tree, schedule an initial layout.
+            view._needsLayoutWhenAttachedToRoot = true;
+            return;
+        }
+
         if (WebInspector.View._scheduledLayoutUpdateIdentifier)
             return;
 
@@ -205,23 +242,23 @@
 
     static _cancelScheduledLayoutForView(view)
     {
-        // Asynchronous layouts aren't scheduled until the root view has been set.
-        if (!WebInspector.View._rootView)
-            return;
+        let cancelledLayoutsCount = view._dirtyDescendantsCount;
+        if (view.layoutPending)
+            cancelledLayoutsCount++;
 
-        let cancelledLayouts = view._dirtyDescendantsCount;
-        if (this._dirty)
-            cancelledLayouts++;
-
         let parentView = view.parentView;
         while (parentView) {
-            parentView._dirtyDescendantsCount = Math.max(0, parentView._dirtyDescendantsCount - cancelledLayouts);
+            parentView._dirtyDescendantsCount = Math.max(0, parentView._dirtyDescendantsCount - cancelledLayoutsCount);
             parentView = parentView.parentView;
         }
 
-        if (WebInspector.View._rootView._dirtyDescendantsCount || !WebInspector.View._scheduledLayoutUpdateIdentifier)
+        if (!WebInspector.View._scheduledLayoutUpdateIdentifier)
             return;
 
+        let rootView = WebInspector.View._rootView;
+        if (!rootView || rootView._dirtyDescendantsCount)
+            return;
+
         // No views need layout, so cancel the pending requestAnimationFrame.
         cancelAnimationFrame(WebInspector.View._scheduledLayoutUpdateIdentifier);
         WebInspector.View._scheduledLayoutUpdateIdentifier = undefined;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to