Changeset 201245 in webkit


Ignore:
Timestamp:
May 21, 2016 12:21:35 PM (8 years ago)
Author:
Matt Baker
Message:

Web Inspector: Creating the CSSStyleDetailsSidebarPanel takes about 50ms (20%) of main load
https://bugs.webkit.org/show_bug.cgi?id=156707
<rdar://problem/25780404>

Reviewed by Timothy Hatcher.

This patch adds new View concepts, initialLayout and widthDidChange,
making it possible for hidden views to postpone the creation of their
UI subtree until they are shown for the first time.

Sidebar panels get this performance improvement by virtue of SidebarPanel
and StyleDetailsPanel, which trigger a layout when shown. This can be
removed once <https://webkit.org/b/150741> is fixed, and this is done
automatically by View.

  • UserInterface/Views/CSSStyleDeclarationTextEditor.js:

(WebInspector.CSSStyleDeclarationTextEditor):
Should subclass View.
(WebInspector.CSSStyleDeclarationTextEditor.prototype.layout):
(WebInspector.CSSStyleDeclarationTextEditor.prototype.get element): Deleted.
Handled in View base class.
(WebInspector.CSSStyleDeclarationTextEditor.prototype.updateLayout): Deleted.
Relocate to layout override, ignore unused parameter force.

  • UserInterface/Views/CSSStyleDetailsSidebarPanel.js:

(WebInspector.CSSStyleDetailsSidebarPanel):
Create the minimum required initial state and UI elements. Relocate
anything that can be lazy loaded to initialLayout.

(WebInspector.CSSStyleDetailsSidebarPanel.prototype.initialLayout):
(WebInspector.CSSStyleDetailsSidebarPanel.prototype.sizeDidChange):
(WebInspector.CSSStyleDetailsSidebarPanel.prototype.widthDidChange): Deleted.

  • UserInterface/Views/ComputedStyleDetailsPanel.js:

(WebInspector.ComputedStyleDetailsPanel):
Relocate anything that can be lazy loaded to initialLayout.
(WebInspector.ComputedStyleDetailsPanel.prototype.initialLayout):
(WebInspector.ComputedStyleDetailsPanel.prototype.shown): Deleted.
(WebInspector.ComputedStyleDetailsPanel.prototype.widthDidChange): Deleted.
Handled in View base class.

  • UserInterface/Views/DataGrid.js:

(WebInspector.DataGrid.prototype.layout):
Resize logic can be safely moved to sizeDidChange, since columns are
always initialized when the width changes.
(WebInspector.DataGrid.prototype.sizeDidChange):
Reposition headers, scrollbars.
(WebInspector.DataGrid.prototype._updateHeaderAndScrollbar):
Broke out header repositioning, which needs to be called whenever
column widths are initialized or the view size changes.

  • UserInterface/Views/NavigationBar.js:

(WebInspector.NavigationBar.prototype.layout):

  • UserInterface/Views/RulesStyleDetailsPanel.js:

(WebInspector.RulesStyleDetailsPanel.prototype.sizeDidChange):
(WebInspector.RulesStyleDetailsPanel.prototype.widthDidChange): Deleted.

  • UserInterface/Views/Sidebar.js:

(WebInspector.Sidebar.prototype._recalculateWidth):
Width changes need to be coordinated by the View base class, since the
initial layout must have occurred before handling a width change.
Force a layout with a resize layout reason.

  • UserInterface/Views/SidebarPanel.js:

(WebInspector.SidebarPanel.prototype.get displayName):
Drive-by style fix: add getter so that CSSStyleDetailsSidebarPanel
doesn't have to read the private property directly.

(WebInspector.SidebarPanel.prototype.shown):
Force a layout whenever the panel is shown.
(WebInspector.SidebarPanel.prototype.sizeDidChange):
(WebInspector.SidebarPanel):
(WebInspector.SidebarPanel.prototype.widthDidChange): Deleted.

  • UserInterface/Views/StyleDetailsPanel.js:

(WebInspector.StyleDetailsPanel.prototype.shown):
Schedule a layout when shown. A forced layout isn't necessary.
Unlike SidebarPanels, the initial state of style panels doesn't depend
on its layout, and can be safely initialized by the next rAF.

(WebInspector.StyleDetailsPanel.prototype.hidden):
Cancel a pending layout if the panel is hidden before the next AF.
(WebInspector.StyleDetailsPanel.prototype.widthDidChange): Deleted.
Not needed, defined in View base class.

  • UserInterface/Views/TimelineOverview.js:

(WebInspector.TimelineOverview.prototype.sizeDidChange):
(WebInspector.TimelineOverview.prototype.layout):
Moved resize logic to sizeDidChange.

  • UserInterface/Views/TimelineRuler.js:

(WebInspector.TimelineRuler.prototype.sizeDidChange):
(WebInspector.TimelineRuler.prototype.layout):
Moved resize logic to sizeDidChange.

  • UserInterface/Views/View.js:

(WebInspector.View):
(WebInspector.View.prototype.updateLayout):
(WebInspector.View.prototype.cancelLayout):
Allow a pending layout to be canceled. Useful when a view with a
pending layout is hidden before the layout occurs.

(WebInspector.View.prototype.get layoutReason):
Protected getter for subclasses that need to check the layout reason
outside sizeDidChange.

(WebInspector.View.prototype.initialLayout):
Subclass hook to create UI subtree the first time a layout occurs.
Called only once during the lifetime of the View.

(WebInspector.View.prototype.layout):
Drive-by comment fix.
(WebInspector.View.prototype.sizeDidChange):
New layout cycle hook for subclasses.
(WebInspector.View.prototype._layoutSubtree):
Do an initial layout the first time layout is called.
Call the sizeDidChange hook so that subclasses can update state
which depends on size/position before doing layout.

  • UserInterface/Views/VisualStyleDetailsPanel.js:

(WebInspector.VisualStyleDetailsPanel):
Create the minimum required initial state and UI elements. Relocate
anything that can be lazy loaded to initialLayout.

(WebInspector.VisualStyleDetailsPanel.prototype.refresh):
No changes, shifting line numbers confused the diff.
(WebInspector.VisualStyleDetailsPanel.prototype.initialLayout):
(WebInspector.VisualStyleDetailsPanel.prototype.sizeDidChange):
(WebInspector.VisualStyleDetailsPanel.prototype.widthDidChange): Deleted.

Location:
trunk/Source/WebInspectorUI
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebInspectorUI/ChangeLog

    r201243 r201245  
     12016-05-21  Matt Baker  <mattbaker@apple.com>
     2
     3        Web Inspector: Creating the CSSStyleDetailsSidebarPanel takes about 50ms (20%) of main load
     4        https://bugs.webkit.org/show_bug.cgi?id=156707
     5        <rdar://problem/25780404>
     6
     7        Reviewed by Timothy Hatcher.
     8
     9        This patch adds new View concepts, `initialLayout` and `widthDidChange`,
     10        making it possible for hidden views to postpone the creation of their
     11        UI subtree until they are shown for the first time.
     12
     13        Sidebar panels get this performance improvement by virtue of SidebarPanel
     14        and StyleDetailsPanel, which trigger a layout when shown. This can be
     15        removed once <https://webkit.org/b/150741> is fixed, and this is done
     16        automatically by View.
     17
     18        * UserInterface/Views/CSSStyleDeclarationTextEditor.js:
     19        (WebInspector.CSSStyleDeclarationTextEditor):
     20        Should subclass View.
     21        (WebInspector.CSSStyleDeclarationTextEditor.prototype.layout):
     22        (WebInspector.CSSStyleDeclarationTextEditor.prototype.get element): Deleted.
     23        Handled in View base class.
     24        (WebInspector.CSSStyleDeclarationTextEditor.prototype.updateLayout): Deleted.
     25        Relocate to `layout` override, ignore unused parameter `force`.
     26
     27        * UserInterface/Views/CSSStyleDetailsSidebarPanel.js:
     28        (WebInspector.CSSStyleDetailsSidebarPanel):
     29        Create the minimum required initial state and UI elements. Relocate
     30        anything that can be lazy loaded to `initialLayout`.
     31
     32        (WebInspector.CSSStyleDetailsSidebarPanel.prototype.initialLayout):
     33        (WebInspector.CSSStyleDetailsSidebarPanel.prototype.sizeDidChange):
     34        (WebInspector.CSSStyleDetailsSidebarPanel.prototype.widthDidChange): Deleted.
     35
     36        * UserInterface/Views/ComputedStyleDetailsPanel.js:
     37        (WebInspector.ComputedStyleDetailsPanel):
     38        Relocate anything that can be lazy loaded to `initialLayout`.
     39        (WebInspector.ComputedStyleDetailsPanel.prototype.initialLayout):
     40        (WebInspector.ComputedStyleDetailsPanel.prototype.shown): Deleted.
     41        (WebInspector.ComputedStyleDetailsPanel.prototype.widthDidChange): Deleted.
     42        Handled in View base class.
     43
     44        * UserInterface/Views/DataGrid.js:
     45        (WebInspector.DataGrid.prototype.layout):
     46        Resize logic can be safely moved to `sizeDidChange`, since columns are
     47        always initialized when the width changes.
     48        (WebInspector.DataGrid.prototype.sizeDidChange):
     49        Reposition headers, scrollbars.
     50        (WebInspector.DataGrid.prototype._updateHeaderAndScrollbar):
     51        Broke out header repositioning, which needs to be called whenever
     52        column widths are initialized or the view size changes.
     53
     54        * UserInterface/Views/NavigationBar.js:
     55        (WebInspector.NavigationBar.prototype.layout):
     56
     57        * UserInterface/Views/RulesStyleDetailsPanel.js:
     58        (WebInspector.RulesStyleDetailsPanel.prototype.sizeDidChange):
     59        (WebInspector.RulesStyleDetailsPanel.prototype.widthDidChange): Deleted.
     60
     61        * UserInterface/Views/Sidebar.js:
     62        (WebInspector.Sidebar.prototype._recalculateWidth):
     63        Width changes need to be coordinated by the View base class, since the
     64        initial layout must have occurred before handling a width change.
     65        Force a layout with a resize layout reason.
     66
     67        * UserInterface/Views/SidebarPanel.js:
     68        (WebInspector.SidebarPanel.prototype.get displayName):
     69        Drive-by style fix: add getter so that CSSStyleDetailsSidebarPanel
     70        doesn't have to read the private property directly.
     71
     72        (WebInspector.SidebarPanel.prototype.shown):
     73        Force a layout whenever the panel is shown.
     74        (WebInspector.SidebarPanel.prototype.sizeDidChange):
     75        (WebInspector.SidebarPanel):
     76        (WebInspector.SidebarPanel.prototype.widthDidChange): Deleted.
     77
     78        * UserInterface/Views/StyleDetailsPanel.js:
     79        (WebInspector.StyleDetailsPanel.prototype.shown):
     80        Schedule a layout when shown. A forced layout isn't necessary.
     81        Unlike SidebarPanels, the initial state of style panels doesn't depend
     82        on its layout, and can be safely initialized by the next rAF.
     83
     84        (WebInspector.StyleDetailsPanel.prototype.hidden):
     85        Cancel a pending layout if the panel is hidden before the next AF.
     86        (WebInspector.StyleDetailsPanel.prototype.widthDidChange): Deleted.
     87        Not needed, defined in View base class.
     88
     89        * UserInterface/Views/TimelineOverview.js:
     90        (WebInspector.TimelineOverview.prototype.sizeDidChange):
     91        (WebInspector.TimelineOverview.prototype.layout):
     92        Moved resize logic to `sizeDidChange`.
     93
     94        * UserInterface/Views/TimelineRuler.js:
     95        (WebInspector.TimelineRuler.prototype.sizeDidChange):
     96        (WebInspector.TimelineRuler.prototype.layout):
     97        Moved resize logic to `sizeDidChange`.
     98
     99        * UserInterface/Views/View.js:
     100        (WebInspector.View):
     101        (WebInspector.View.prototype.updateLayout):
     102        (WebInspector.View.prototype.cancelLayout):
     103        Allow a pending layout to be canceled. Useful when a view with a
     104        pending layout is hidden before the layout occurs.
     105
     106        (WebInspector.View.prototype.get layoutReason):
     107        Protected getter for subclasses that need to check the layout reason
     108        outside `sizeDidChange`.
     109
     110        (WebInspector.View.prototype.initialLayout):
     111        Subclass hook to create UI subtree the first time a layout occurs.
     112        Called only once during the lifetime of the View.
     113
     114        (WebInspector.View.prototype.layout):
     115        Drive-by comment fix.
     116        (WebInspector.View.prototype.sizeDidChange):
     117        New layout cycle hook for subclasses.
     118        (WebInspector.View.prototype._layoutSubtree):
     119        Do an initial layout the first time layout is called.
     120        Call the `sizeDidChange` hook so that subclasses can update state
     121        which depends on size/position before doing layout.
     122
     123        * UserInterface/Views/VisualStyleDetailsPanel.js:
     124        (WebInspector.VisualStyleDetailsPanel):
     125        Create the minimum required initial state and UI elements. Relocate
     126        anything that can be lazy loaded to `initialLayout`.
     127
     128        (WebInspector.VisualStyleDetailsPanel.prototype.refresh):
     129        No changes, shifting line numbers confused the diff.
     130        (WebInspector.VisualStyleDetailsPanel.prototype.initialLayout):
     131        (WebInspector.VisualStyleDetailsPanel.prototype.sizeDidChange):
     132        (WebInspector.VisualStyleDetailsPanel.prototype.widthDidChange): Deleted.
     133
    11342016-05-21  Matt Baker  <mattbaker@apple.com>
    2135
  • trunk/Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationTextEditor.js

    r201111 r201245  
    2525 */
    2626
    27 WebInspector.CSSStyleDeclarationTextEditor = class CSSStyleDeclarationTextEditor extends WebInspector.Object
     27WebInspector.CSSStyleDeclarationTextEditor = class CSSStyleDeclarationTextEditor extends WebInspector.View
    2828{
    29     constructor(delegate, style, element)
     29    constructor(delegate, style)
    3030    {
    3131        super();
    3232
    33         this._element = element || document.createElement("div");
    34         this._element.classList.add(WebInspector.CSSStyleDeclarationTextEditor.StyleClassName);
    35         this._element.classList.add(WebInspector.SyntaxHighlightedStyleClassName);
    36         this._element.addEventListener("mousedown", this._handleMouseDown.bind(this));
    37         this._element.addEventListener("mouseup", this._handleMouseUp.bind(this));
     33        this.element.classList.add(WebInspector.CSSStyleDeclarationTextEditor.StyleClassName);
     34        this.element.classList.add(WebInspector.SyntaxHighlightedStyleClassName);
     35        this.element.addEventListener("mousedown", this._handleMouseDown.bind(this));
     36        this.element.addEventListener("mouseup", this._handleMouseUp.bind(this));
    3837
    3938        this._mouseDownCursorPosition = null;
     
    9493    // Public
    9594
    96     get element()
    97     {
    98         return this._element;
    99     }
    100 
    10195    get delegate()
    10296    {
     
    193187    {
    194188        this._resetContent();
    195     }
    196 
    197     updateLayout(force)
    198     {
    199         this._codeMirror.refresh();
    200189    }
    201190
     
    399388        else
    400389            this._propertiesChanged();
     390    }
     391
     392    layout()
     393    {
     394        this._codeMirror.refresh();
    401395    }
    402396
  • trunk/Source/WebInspectorUI/UserInterface/Views/CSSStyleDetailsSidebarPanel.js

    r195456 r201245  
    3131
    3232        this._selectedPanel = null;
     33        this._computedStyleDetailsPanel = new WebInspector.ComputedStyleDetailsPanel(this);
     34        this._rulesStyleDetailsPanel = new WebInspector.RulesStyleDetailsPanel(this);
     35        this._visualStyleDetailsPanel = new WebInspector.VisualStyleDetailsPanel(this);
     36
     37        this._panels = [this._computedStyleDetailsPanel, this._rulesStyleDetailsPanel, this._visualStyleDetailsPanel];
     38        this._panelNavigationInfo = [this._computedStyleDetailsPanel.navigationInfo, this._rulesStyleDetailsPanel.navigationInfo, this._visualStyleDetailsPanel.navigationInfo];
     39
     40        this._lastSelectedSectionSetting = new WebInspector.Setting("last-selected-style-details-panel", this._rulesStyleDetailsPanel.navigationInfo.identifier);
     41
     42        this._initiallySelectedPanel = this._panelMatchingIdentifier(this._lastSelectedSectionSetting.value) || this._rulesStyleDetailsPanel;
     43
     44        this._navigationItem = new WebInspector.ScopeRadioButtonNavigationItem(this.identifier, this.displayName, this._panelNavigationInfo, this._initiallySelectedPanel.navigationInfo);
     45        this._navigationItem.addEventListener(WebInspector.ScopeRadioButtonNavigationItem.Event.SelectedItemChanged, this._handleSelectedItemChanged, this);
    3346
    3447        this._forcedPseudoClassCheckboxes = {};
    35 
     48    }
     49
     50    // Public
     51
     52    supportsDOMNode(nodeToInspect)
     53    {
     54        return nodeToInspect.nodeType() === Node.ELEMENT_NODE;
     55    }
     56
     57    refresh()
     58    {
     59        let domNode = this.domNode;
     60        if (!domNode)
     61            return;
     62
     63        this.contentView.element.scrollTop = this._initialScrollOffset;
     64
     65        for (let panel of this._panels) {
     66            panel.element._savedScrollTop = undefined;
     67            panel.markAsNeedsRefresh(domNode);
     68        }
     69
     70        this._updatePseudoClassCheckboxes();
     71
     72        if (!this._classListContainer.hidden)
     73            this._populateClassToggles();
     74    }
     75
     76    visibilityDidChange()
     77    {
     78        super.visibilityDidChange();
     79
     80        if (!this._selectedPanel)
     81            return;
     82
     83        if (!this.visible) {
     84            this._selectedPanel.hidden();
     85            return;
     86        }
     87
     88        this._updateNoForcedPseudoClassesScrollOffset();
     89
     90        this._selectedPanel.shown();
     91        this._selectedPanel.markAsNeedsRefresh(this.domNode);
     92    }
     93
     94    computedStyleDetailsPanelShowProperty(property)
     95    {
     96        this._rulesStyleDetailsPanel.scrollToSectionAndHighlightProperty(property);
     97        this._switchPanels(this._rulesStyleDetailsPanel);
     98
     99        this._navigationItem.selectedItemIdentifier = this._lastSelectedSectionSetting.value;
     100    }
     101
     102    // Protected
     103
     104    addEventListeners()
     105    {
     106        let effectiveDOMNode = this.domNode.isPseudoElement() ? this.domNode.parentNode : this.domNode;
     107        if (!effectiveDOMNode)
     108            return;
     109
     110        effectiveDOMNode.addEventListener(WebInspector.DOMNode.Event.EnabledPseudoClassesChanged, this._updatePseudoClassCheckboxes, this);
     111        effectiveDOMNode.addEventListener(WebInspector.DOMNode.Event.AttributeModified, this._handleNodeAttributeModified, this);
     112        effectiveDOMNode.addEventListener(WebInspector.DOMNode.Event.AttributeRemoved, this._handleNodeAttributeRemoved, this);
     113    }
     114
     115    removeEventListeners()
     116    {
     117        let effectiveDOMNode = this.domNode.isPseudoElement() ? this.domNode.parentNode : this.domNode;
     118        if (!effectiveDOMNode)
     119            return;
     120
     121        effectiveDOMNode.removeEventListener(null, null, this);
     122    }
     123
     124    initialLayout()
     125    {
    36126        if (WebInspector.cssStyleManager.canForcePseudoClasses()) {
    37127            this._forcedPseudoClassContainer = document.createElement("div");
     
    67157        }
    68158
    69         this._computedStyleDetailsPanel = new WebInspector.ComputedStyleDetailsPanel(this);
    70         this._rulesStyleDetailsPanel = new WebInspector.RulesStyleDetailsPanel(this);
    71         this._visualStyleDetailsPanel = new WebInspector.VisualStyleDetailsPanel(this);
    72 
    73159        this._computedStyleDetailsPanel.addEventListener(WebInspector.StyleDetailsPanel.Event.Refreshed, this._filterDidChange, this);
    74160        this._rulesStyleDetailsPanel.addEventListener(WebInspector.StyleDetailsPanel.Event.Refreshed, this._filterDidChange, this);
    75161
    76         this._panels = [this._computedStyleDetailsPanel, this._rulesStyleDetailsPanel, this._visualStyleDetailsPanel];
    77         this._panelNavigationInfo = [this._computedStyleDetailsPanel.navigationInfo, this._rulesStyleDetailsPanel.navigationInfo, this._visualStyleDetailsPanel.navigationInfo];
    78 
    79         this._lastSelectedSectionSetting = new WebInspector.Setting("last-selected-style-details-panel", this._rulesStyleDetailsPanel.navigationInfo.identifier);
    80 
    81         let selectedPanel = this._panelMatchingIdentifier(this._lastSelectedSectionSetting.value);
    82         if (!selectedPanel)
    83             selectedPanel = this._rulesStyleDetailsPanel;
    84 
    85         this._switchPanels(selectedPanel);
    86 
    87         this._navigationItem = new WebInspector.ScopeRadioButtonNavigationItem(this._identifier, this._displayName, this._panelNavigationInfo, selectedPanel.navigationInfo);
    88         this._navigationItem.addEventListener(WebInspector.ScopeRadioButtonNavigationItem.Event.SelectedItemChanged, this._handleSelectedItemChanged, this);
     162        console.assert(this._initiallySelectedPanel, "Should have an initially selected panel.");
     163
     164        this._switchPanels(this._initiallySelectedPanel);
     165        this._initiallySelectedPanel = null;
    89166
    90167        let optionsContainer = this.element.createChild("div", "options-container");
     
    127204    }
    128205
    129     // Public
    130 
    131     supportsDOMNode(nodeToInspect)
    132     {
    133         return nodeToInspect.nodeType() === Node.ELEMENT_NODE;
    134     }
    135 
    136     refresh()
    137     {
    138         let domNode = this.domNode;
    139         if (!domNode)
    140             return;
    141 
    142         this.contentView.element.scrollTop = this._initialScrollOffset;
    143 
    144         for (let panel of this._panels) {
    145             panel.element._savedScrollTop = undefined;
    146             panel.markAsNeedsRefresh(domNode);
    147         }
    148 
    149         this._updatePseudoClassCheckboxes();
    150 
    151         if (!this._classListContainer.hidden)
    152             this._populateClassToggles();
    153     }
    154 
    155     visibilityDidChange()
    156     {
    157         super.visibilityDidChange();
    158 
    159         if (!this._selectedPanel)
    160             return;
    161 
    162         if (!this.visible) {
    163             this._selectedPanel.hidden();
    164             return;
    165         }
     206    sizeDidChange()
     207    {
     208        super.sizeDidChange();
    166209
    167210        this._updateNoForcedPseudoClassesScrollOffset();
    168211
    169         this._selectedPanel.shown();
    170         this._selectedPanel.markAsNeedsRefresh(this.domNode);
    171     }
    172 
    173     widthDidChange()
    174     {
    175         super.widthDidChange();
    176 
    177         this._updateNoForcedPseudoClassesScrollOffset();
    178 
    179212        if (this._selectedPanel)
    180             this._selectedPanel.widthDidChange();
    181     }
    182 
    183     computedStyleDetailsPanelShowProperty(property)
    184     {
    185         this._rulesStyleDetailsPanel.scrollToSectionAndHighlightProperty(property);
    186         this._switchPanels(this._rulesStyleDetailsPanel);
    187 
    188         this._navigationItem.selectedItemIdentifier = this._lastSelectedSectionSetting.value;
    189     }
    190 
    191     // Protected
    192 
    193     addEventListeners()
    194     {
    195         let effectiveDOMNode = this.domNode.isPseudoElement() ? this.domNode.parentNode : this.domNode;
    196         if (!effectiveDOMNode)
    197             return;
    198 
    199         effectiveDOMNode.addEventListener(WebInspector.DOMNode.Event.EnabledPseudoClassesChanged, this._updatePseudoClassCheckboxes, this);
    200         effectiveDOMNode.addEventListener(WebInspector.DOMNode.Event.AttributeModified, this._handleNodeAttributeModified, this);
    201         effectiveDOMNode.addEventListener(WebInspector.DOMNode.Event.AttributeRemoved, this._handleNodeAttributeRemoved, this);
    202     }
    203 
    204     removeEventListeners()
    205     {
    206         let effectiveDOMNode = this.domNode.isPseudoElement() ? this.domNode.parentNode : this.domNode;
    207         if (!effectiveDOMNode)
    208             return;
    209 
    210         effectiveDOMNode.removeEventListener(null, null, this);
     213            this._selectedPanel.sizeDidChange();
    211214    }
    212215
     
    459462};
    460463
    461 WebInspector.CSSStyleDetailsSidebarPanel.NoForcedPseudoClassesScrollOffset = 30; // Default height of the forced pseudo classes container. Updated in widthDidChange.
     464WebInspector.CSSStyleDetailsSidebarPanel.NoForcedPseudoClassesScrollOffset = 30; // Default height of the forced pseudo classes container. Updated in sizeDidChange.
    462465WebInspector.CSSStyleDetailsSidebarPanel.FilterInProgressClassName = "filter-in-progress";
    463466WebInspector.CSSStyleDetailsSidebarPanel.FilterMatchingSectionHasLabelClassName = "filter-section-has-label";
  • trunk/Source/WebInspectorUI/UserInterface/Views/ComputedStyleDetailsPanel.js

    r199747 r201245  
    3131
    3232        this._computedStyleShowAllSetting = new WebInspector.Setting("computed-style-show-all", false);
    33 
    34         var computedStyleShowAllLabel = document.createElement("label");
    35         computedStyleShowAllLabel.textContent = WebInspector.UIString("Show All");
    36 
    37         this._computedStyleShowAllCheckbox = document.createElement("input");
    38         this._computedStyleShowAllCheckbox.type = "checkbox";
    39         this._computedStyleShowAllCheckbox.checked = this._computedStyleShowAllSetting.value;
    40         this._computedStyleShowAllCheckbox.addEventListener("change", this._computedStyleShowAllCheckboxValueChanged.bind(this));
    41         computedStyleShowAllLabel.appendChild(this._computedStyleShowAllCheckbox);
    42 
    43         this._propertiesTextEditor = new WebInspector.CSSStyleDeclarationTextEditor(this);
    44         this._propertiesTextEditor.showsImplicitProperties = this._computedStyleShowAllSetting.value;
    45         this._propertiesTextEditor.alwaysShowPropertyNames = ["display", "width", "height"];
    46         this._propertiesTextEditor.sortProperties = true;
    47 
    48         var propertiesRow = new WebInspector.DetailsSectionRow;
    49         var propertiesGroup = new WebInspector.DetailsSectionGroup([propertiesRow]);
    50         var propertiesSection = new WebInspector.DetailsSection("computed-style-properties", WebInspector.UIString("Properties"), [propertiesGroup], computedStyleShowAllLabel);
    51         propertiesSection.addEventListener(WebInspector.DetailsSection.Event.CollapsedStateChanged, this._handleCollapsedStateChanged, this);
    52 
    53         propertiesRow.element.appendChild(this._propertiesTextEditor.element);
    54 
    55         // Region flow name is used to display the "flow-from" property of the Region Containers.
    56         this._regionFlowFragment = document.createElement("span");
    57         this._regionFlowFragment.appendChild(document.createElement("img")).className = "icon";
    58         this._regionFlowNameLabelValue = this._regionFlowFragment.appendChild(document.createElement("span"));
    59 
    60         var goToRegionFlowButton = this._regionFlowFragment.appendChild(WebInspector.createGoToArrowButton());
    61         goToRegionFlowButton.addEventListener("click", this._goToRegionFlowArrowWasClicked.bind(this));
    62 
    63         this._regionFlowNameRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Region Flow"));
    64         this._regionFlowNameRow.element.classList.add("content-flow-link");
    65 
    66         // Content flow name is used to display the "flow-into" property of the Content nodes.
    67         this._contentFlowFragment = document.createElement("span");
    68         this._contentFlowFragment.appendChild(document.createElement("img")).className = "icon";
    69         this._contentFlowNameLabelValue = this._contentFlowFragment.appendChild(document.createElement("span"));
    70 
    71         var goToContentFlowButton = this._contentFlowFragment.appendChild(WebInspector.createGoToArrowButton());
    72         goToContentFlowButton.addEventListener("click", this._goToContentFlowArrowWasClicked.bind(this));
    73 
    74         this._contentFlowNameRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Content Flow"));
    75         this._contentFlowNameRow.element.classList.add("content-flow-link");
    76 
    77         var flowNamesGroup = new WebInspector.DetailsSectionGroup([this._regionFlowNameRow, this._contentFlowNameRow]);
    78         this._flowNamesSection = new WebInspector.DetailsSection("content-flow", WebInspector.UIString("Flows"), [flowNamesGroup]);
    79 
    80         this._containerRegionsDataGrid = new WebInspector.DOMTreeDataGrid;
    81         this._containerRegionsDataGrid.element.classList.add("no-header");
    82 
    83         var containerRegionsRow = new WebInspector.DetailsSectionDataGridRow(this._containerRegionsDataGrid);
    84         var containerRegionsGroup = new WebInspector.DetailsSectionGroup([containerRegionsRow]);
    85         this._containerRegionsFlowSection = new WebInspector.DetailsSection("container-regions", WebInspector.UIString("Container Regions"), [containerRegionsGroup]);
    86 
    87         this.element.appendChild(propertiesSection.element);
    88         this.element.appendChild(this._flowNamesSection.element);
    89         this.element.appendChild(this._containerRegionsFlowSection.element);
    90 
    91         this._resetFlowDetails();
    92 
    93         this._boxModelDiagramRow = new WebInspector.BoxModelDetailsSectionRow;
    94 
    95         var boxModelGroup = new WebInspector.DetailsSectionGroup([this._boxModelDiagramRow]);
    96         var boxModelSection = new WebInspector.DetailsSection("style-box-model", WebInspector.UIString("Box Model"), [boxModelGroup]);
    97 
    98         this.element.appendChild(boxModelSection.element);
    9933       
    10034        this.cssStyleDeclarationTextEditorShouldAddPropertyGoToArrows = true;
     
    208142    // Protected
    209143
    210     shown()
    211     {
    212         super.shown();
    213 
    214         this._propertiesTextEditor.updateLayout();
    215     }
    216 
    217     widthDidChange()
    218     {
    219         this._propertiesTextEditor.updateLayout();
     144    initialLayout()
     145    {
     146        let computedStyleShowAllLabel = document.createElement("label");
     147        computedStyleShowAllLabel.textContent = WebInspector.UIString("Show All");
     148
     149        this._computedStyleShowAllCheckbox = document.createElement("input");
     150        this._computedStyleShowAllCheckbox.type = "checkbox";
     151        this._computedStyleShowAllCheckbox.checked = this._computedStyleShowAllSetting.value;
     152        this._computedStyleShowAllCheckbox.addEventListener("change", this._computedStyleShowAllCheckboxValueChanged.bind(this));
     153        computedStyleShowAllLabel.appendChild(this._computedStyleShowAllCheckbox);
     154
     155        this._propertiesTextEditor = new WebInspector.CSSStyleDeclarationTextEditor(this);
     156        this._propertiesTextEditor.showsImplicitProperties = this._computedStyleShowAllSetting.value;
     157        this._propertiesTextEditor.alwaysShowPropertyNames = ["display", "width", "height"];
     158        this._propertiesTextEditor.sortProperties = true;
     159
     160        let propertiesRow = new WebInspector.DetailsSectionRow;
     161        let propertiesGroup = new WebInspector.DetailsSectionGroup([propertiesRow]);
     162        let propertiesSection = new WebInspector.DetailsSection("computed-style-properties", WebInspector.UIString("Properties"), [propertiesGroup], computedStyleShowAllLabel);
     163        propertiesSection.addEventListener(WebInspector.DetailsSection.Event.CollapsedStateChanged, this._handleCollapsedStateChanged, this);
     164
     165        this.addSubview(this._propertiesTextEditor);
     166
     167        propertiesRow.element.appendChild(this._propertiesTextEditor.element);
     168
     169        // Region flow name is used to display the "flow-from" property of the Region Containers.
     170        this._regionFlowFragment = document.createElement("span");
     171        this._regionFlowFragment.appendChild(document.createElement("img")).className = "icon";
     172        this._regionFlowNameLabelValue = this._regionFlowFragment.appendChild(document.createElement("span"));
     173
     174        let goToRegionFlowButton = this._regionFlowFragment.appendChild(WebInspector.createGoToArrowButton());
     175        goToRegionFlowButton.addEventListener("click", this._goToRegionFlowArrowWasClicked.bind(this));
     176
     177        this._regionFlowNameRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Region Flow"));
     178        this._regionFlowNameRow.element.classList.add("content-flow-link");
     179
     180        // Content flow name is used to display the "flow-into" property of the Content nodes.
     181        this._contentFlowFragment = document.createElement("span");
     182        this._contentFlowFragment.appendChild(document.createElement("img")).className = "icon";
     183        this._contentFlowNameLabelValue = this._contentFlowFragment.appendChild(document.createElement("span"));
     184
     185        let goToContentFlowButton = this._contentFlowFragment.appendChild(WebInspector.createGoToArrowButton());
     186        goToContentFlowButton.addEventListener("click", this._goToContentFlowArrowWasClicked.bind(this));
     187
     188        this._contentFlowNameRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Content Flow"));
     189        this._contentFlowNameRow.element.classList.add("content-flow-link");
     190
     191        let flowNamesGroup = new WebInspector.DetailsSectionGroup([this._regionFlowNameRow, this._contentFlowNameRow]);
     192        this._flowNamesSection = new WebInspector.DetailsSection("content-flow", WebInspector.UIString("Flows"), [flowNamesGroup]);
     193
     194        this._containerRegionsDataGrid = new WebInspector.DOMTreeDataGrid;
     195        this._containerRegionsDataGrid.element.classList.add("no-header");
     196
     197        let containerRegionsRow = new WebInspector.DetailsSectionDataGridRow(this._containerRegionsDataGrid);
     198        let containerRegionsGroup = new WebInspector.DetailsSectionGroup([containerRegionsRow]);
     199        this._containerRegionsFlowSection = new WebInspector.DetailsSection("container-regions", WebInspector.UIString("Container Regions"), [containerRegionsGroup]);
     200
     201        this.element.appendChild(propertiesSection.element);
     202        this.element.appendChild(this._flowNamesSection.element);
     203        this.element.appendChild(this._containerRegionsFlowSection.element);
     204
     205        this._resetFlowDetails();
     206
     207        this._boxModelDiagramRow = new WebInspector.BoxModelDetailsSectionRow;
     208
     209        let boxModelGroup = new WebInspector.DetailsSectionGroup([this._boxModelDiagramRow]);
     210        let boxModelSection = new WebInspector.DetailsSection("style-box-model", WebInspector.UIString("Box Model"), [boxModelGroup]);
     211
     212        this.element.appendChild(boxModelSection.element);
    220213    }
    221214
  • trunk/Source/WebInspectorUI/UserInterface/Views/DataGrid.js

    r201102 r201245  
    793793    // If this function is not called after the DataGrid is attached to its
    794794    // parent element, then the DataGrid's columns will not be resizable.
    795     layout(layoutReason)
    796     {
    797         let firstUpdate = false;
    798 
     795    layout()
     796    {
    799797        // Do not attempt to use offsets if we're not attached to the document tree yet.
    800798        if (!this._columnWidthsInitialized && this.element.offsetWidth) {
     
    803801            // their widths, all the other columns already have percent values
    804802            // for their widths.
    805             var headerTableColumnElements = this._headerTableColumnGroupElement.children;
    806             var tableWidth = this._dataTableElement.offsetWidth;
    807             var numColumns = headerTableColumnElements.length;
    808             var cells = this._headerTableBodyElement.rows[0].cells;
     803            let headerTableColumnElements = this._headerTableColumnGroupElement.children;
     804            let tableWidth = this._dataTableElement.offsetWidth;
     805            let numColumns = headerTableColumnElements.length;
     806            let cells = this._headerTableBodyElement.rows[0].cells;
    809807
    810808            // Calculate widths.
    811             var columnWidths = [];
    812             for (var i = 0; i < numColumns; ++i) {
    813                 var headerCellElement = cells[i];
     809            let columnWidths = [];
     810            for (let i = 0; i < numColumns; ++i) {
     811                let headerCellElement = cells[i];
    814812                if (this._isColumnVisible(headerCellElement.columnIdentifier)) {
    815                     var columnWidth = headerCellElement.offsetWidth;
    816                     var percentWidth = ((columnWidth / tableWidth) * 100) + "%";
     813                    let columnWidth = headerCellElement.offsetWidth;
     814                    let percentWidth = ((columnWidth / tableWidth) * 100) + "%";
    817815                    columnWidths.push(percentWidth);
    818816                } else
     
    821819
    822820            // Apply widths.
    823             for (var i = 0; i < numColumns; i++) {
     821            for (let i = 0; i < numColumns; i++) {
    824822                let percentWidth = columnWidths[i];
    825823                this._headerTableColumnGroupElement.children[i].style.width = percentWidth;
     
    828826
    829827            this._columnWidthsInitialized = true;
    830             firstUpdate = true;
    831         }
    832 
    833         if (layoutReason === WebInspector.View.LayoutReason.Resize || firstUpdate) {
    834             this._positionResizerElements();
    835             this._positionHeaderViews();
    836             this._updateScrollbarPadding();
    837 
    838             this._cachedScrollTop = NaN;
    839             this._cachedScrollableOffsetHeight = NaN;
     828            this._updateHeaderAndScrollbar();
    840829        }
    841830
    842831        this._updateVisibleRows();
     832    }
     833
     834    sizeDidChange()
     835    {
     836        this._updateHeaderAndScrollbar();
     837    }
     838
     839    _updateHeaderAndScrollbar()
     840    {
     841        this._positionResizerElements();
     842        this._positionHeaderViews();
     843        this._updateScrollbarPadding();
     844
     845        this._cachedScrollTop = NaN;
     846        this._cachedScrollableOffsetHeight = NaN;
    843847    }
    844848
  • trunk/Source/WebInspectorUI/UserInterface/Views/NavigationBar.js

    r198620 r201245  
    169169    }
    170170
    171     layout(layoutReason)
    172     {
    173         if (layoutReason !== WebInspector.View.LayoutReason.Resize && !this._forceLayout)
     171    layout()
     172    {
     173        if (this.layoutReason !== WebInspector.View.LayoutReason.Resize && !this._forceLayout)
    174174            return;
    175175
  • trunk/Source/WebInspectorUI/UserInterface/Views/RulesStyleDetailsPanel.js

    r196798 r201245  
    453453    }
    454454
    455     widthDidChange()
     455    sizeDidChange()
    456456    {
    457457        for (var i = 0; i < this._sections.length; ++i)
  • trunk/Source/WebInspectorUI/UserInterface/Views/Sidebar.js

    r201243 r201245  
    274274
    275275        if (!this.collapsed && this._selectedSidebarPanel)
    276             this._selectedSidebarPanel.widthDidChange();
     276            this._selectedSidebarPanel.updateLayout(WebInspector.View.LayoutReason.Resize);
    277277
    278278        this.dispatchEventToListeners(WebInspector.Sidebar.Event.WidthDidChange);
  • trunk/Source/WebInspectorUI/UserInterface/Views/SidebarPanel.js

    r201243 r201245  
    5757    {
    5858        return this._contentView;
     59    }
     60
     61    get displayName()
     62    {
     63        return this._displayName;
    5964    }
    6065
     
    130135        this._contentView.element.scrollTop = this._savedScrollPosition;
    131136
     137        // FIXME: remove once <https://webkit.org/b/150741> is fixed.
     138        this.updateLayout();
     139
    132140        // Implemented by subclasses.
    133141    }
     
    140148    }
    141149
    142     widthDidChange()
     150    visibilityDidChange()
     151    {
     152        // Implemented by subclasses.
     153    }
     154
     155    // Protected
     156
     157    sizeDidChange()
    143158    {
    144159        let width = this.element.realOffsetWidth;
     
    148163        // Implemented by subclasses.
    149164    }
    150 
    151     visibilityDidChange()
    152     {
    153         // Implemented by subclasses.
    154     }
    155165};
  • trunk/Source/WebInspectorUI/UserInterface/Views/StyleDetailsPanel.js

    r194116 r201245  
    6161
    6262        this._refreshNodeStyles();
     63
     64        // FIXME: remove once <https://webkit.org/b/150741> is fixed.
     65        this.needsLayout();
    6366    }
    6467
     
    6669    {
    6770        this._visible = false;
    68     }
    6971
    70     widthDidChange()
    71     {
    72         // Implemented by subclasses.
     72        this.cancelLayout();
    7373    }
    7474
  • trunk/Source/WebInspectorUI/UserInterface/Views/TimelineOverview.js

    r201177 r201245  
    430430    }
    431431
    432     layout(layoutReason)
    433     {
    434         if (layoutReason === WebInspector.View.LayoutReason.Resize)
    435             this._cachedScrollContainerWidth = NaN;
    436 
     432    layout()
     433    {
    437434        let startTime = this._startTime;
    438435        let endTime = this._endTime;
     
    487484            overviewGraph.endTime = scrollStartTime + visibleDuration;
    488485        }
     486    }
     487
     488    sizeDidChange()
     489    {
     490        this._cachedScrollContainerWidth = NaN;
    489491    }
    490492
  • trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRuler.js

    r200745 r201245  
    416416    // Protected
    417417
    418     layout(layoutReason)
    419     {
    420         if (layoutReason === WebInspector.View.LayoutReason.Resize)
    421             this._cachedClientWidth = this.element.clientWidth;
    422 
     418    layout()
     419    {
    423420        let visibleWidth = this._recalculate();
    424421        if (visibleWidth <= 0)
     
    531528        this._updateMarkers(visibleWidth, duration);
    532529        this._updateSelection(visibleWidth, duration);
     530    }
     531
     532    sizeDidChange()
     533    {
     534        this._cachedClientWidth = this.element.clientWidth;
    533535    }
    534536
  • trunk/Source/WebInspectorUI/UserInterface/Views/View.js

    r195995 r201245  
    3939        this._isAttachedToRoot = false;
    4040        this._layoutReason = null;
     41        this._didInitialLayout = false;
    4142    }
    4243
     
    141142    updateLayout(layoutReason)
    142143    {
    143         WebInspector.View._cancelScheduledLayoutForView(this);
     144        this.cancelLayout();
    144145
    145146        this._setLayoutReason(layoutReason);
     
    165166    }
    166167
     168    cancelLayout()
     169    {
     170        WebInspector.View._cancelScheduledLayoutForView(this);
     171    }
     172
    167173    // Protected
     174
     175    get layoutReason() { return this._layoutReason; }
    168176
    169177    didMoveToWindow(isAttachedToRoot)
     
    201209    }
    202210
     211    initialLayout()
     212    {
     213        // Implemented by subclasses.
     214
     215        // Called once when the view is shown for the first time.
     216        // Views with complex DOM subtrees should create UI elements in
     217        // initialLayout rather than at construction time.
     218    }
     219
    203220    layout()
    204221    {
    205         // Overridden by subclasses.
     222        // Implemented by subclasses.
     223
    206224        // Not responsible for recursing to child views.
    207225        // Should not be called directly; use updateLayout() instead.
    208226    }
    209227
     228    sizeDidChange()
     229    {
     230        // Implemented by subclasses.
     231
     232        // Called after initialLayout, and before layout.
     233    }
     234
    210235    // Private
    211236
     
    215240        this._dirtyDescendantsCount = 0;
    216241
    217         this.layout(this._layoutReason);
     242        if (!this._didInitialLayout) {
     243            this.initialLayout();
     244            this._didInitialLayout = true;
     245        }
     246
     247        if (this._layoutReason === WebInspector.View.LayoutReason.Resize)
     248            this.sizeDidChange();
     249
     250        this.layout();
    218251
    219252        for (let view of this._subviews) {
  • trunk/Source/WebInspectorUI/UserInterface/Views/VisualStyleDetailsPanel.js

    r197059 r201245  
    5555            advanced: this._units.defaultsSansPercent.advanced
    5656        };
    57 
     57    }
     58
     59    // Public
     60
     61    refresh(significantChange)
     62    {
     63        if (significantChange)
     64            this._selectorSection.update(this._nodeStyles);
     65        else
     66            this._updateSections();
     67
     68        super.refresh();
     69    }
     70
     71    // Protected
     72
     73    initialLayout()
     74    {
    5875        // Selector Section
    5976        this._selectorSection = new WebInspector.VisualStyleSelectorSection(this);
     
    103120    }
    104121
    105     // Public
    106 
    107     refresh(significantChange)
    108     {
    109         if (significantChange)
    110             this._selectorSection.update(this._nodeStyles);
    111         else
    112             this._updateSections();
    113 
    114         super.refresh();
    115     }
    116 
    117     widthDidChange()
    118     {
    119         super.widthDidChange();
     122    sizeDidChange()
     123    {
     124        super.sizeDidChange();
    120125
    121126        let sidebarWidth = this.element.realOffsetWidth;
Note: See TracChangeset for help on using the changeset viewer.