Changeset 278607 in webkit


Ignore:
Timestamp:
Jun 8, 2021 8:57:00 AM (14 months ago)
Author:
Razvan Caliman
Message:

Web Inspector: Styles panel slow to render when inspecting node with many inherited CSS variables
https://bugs.webkit.org/show_bug.cgi?id=225972
<rdar://problem/78211185>

Reviewed by Devin Rousso.

Source/WebInspectorUI:

Do not show unused inherited CSS variables in the Styles details sidebar.

When aggregating styles for the selected node in WI.DOMNodeStyles, collect a list of names of CSS variables used in CSS property values.
In the Styles details sidebar, skip rendering declarations of inherited CSS variables that are not found in this list.

Always show inherited variables that are used, either directly inherited or via reference (variables using other variables in their value).
Always show inherited variables used as values of inheritable properties like color, font-size, etc.

When a CSS rule contains hidden inherited variables, offer a button to request disclosing them for that rule.
Option-click to show unused inherited variables in all matching rules.

Clicking the "Go to variable" button automatically renders all the unused variables in the CSS rule where the target variable is declared.

  • Localizations/en.lproj/localizedStrings.js:
  • UserInterface/Models/CSSProperty.js:

(WI.CSSProperty.findVariableNames):

  • UserInterface/Models/DOMNodeStyles.js:

(WI.DOMNodeStyles):
(WI.DOMNodeStyles.prototype.get usedCSSVariables):
(WI.DOMNodeStyles.prototype._updateStyleCascade):
(WI.DOMNodeStyles.prototype._collectUsedCSSVariables):

  • UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css:

(.spreadsheet-style-declaration-editor .property):
(.spreadsheet-style-declaration-editor > .hidden-variables-button):

  • UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.js:

(WI.SpreadsheetCSSStyleDeclarationEditor):
(WI.SpreadsheetCSSStyleDeclarationEditor.prototype.layout):
(WI.SpreadsheetCSSStyleDeclarationEditor.prototype.get propertiesToRender):
(WI.SpreadsheetCSSStyleDeclarationEditor.prototype.highlightProperty):

  • UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js:

(WI.SpreadsheetCSSStyleDeclarationSection.prototype.set propertyVisibilityMode):
(WI.SpreadsheetCSSStyleDeclarationSection.prototype.spreadsheetCSSStyleDeclarationEditorSetAllPropertyVisibilityMode):

  • UserInterface/Views/SpreadsheetRulesStyleDetailsPanel.js:

(WI.SpreadsheetRulesStyleDetailsPanel.prototype.spreadsheetCSSStyleDeclarationSectionSetAllPropertyVisibilityMode):

LayoutTests:

Add tests for logic to aggregate used CSS variables in Web Inspector.

  • inspector/css/findVariableNames-expected.txt: Added.
  • inspector/css/findVariableNames.html: Added.
  • inspector/css/usedCSSVariables-expected.txt: Added.
  • inspector/css/usedCSSVariables.html: Added.
Location:
trunk
Files:
4 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r278605 r278607  
     12021-06-08  Razvan Caliman  <rcaliman@apple.com>
     2
     3        Web Inspector: Styles panel slow to render when inspecting node with many inherited CSS variables
     4        https://bugs.webkit.org/show_bug.cgi?id=225972
     5        <rdar://problem/78211185>
     6
     7        Reviewed by Devin Rousso.
     8
     9        Add tests for logic to aggregate used CSS variables in Web Inspector.
     10
     11        * inspector/css/findVariableNames-expected.txt: Added.
     12        * inspector/css/findVariableNames.html: Added.
     13        * inspector/css/usedCSSVariables-expected.txt: Added.
     14        * inspector/css/usedCSSVariables.html: Added.
     15
    1162021-06-08  Alan Bujtas  <zalan@apple.com>
    217
  • trunk/Source/WebInspectorUI/ChangeLog

    r278513 r278607  
     12021-06-08  Razvan Caliman  <rcaliman@apple.com>
     2
     3        Web Inspector: Styles panel slow to render when inspecting node with many inherited CSS variables
     4        https://bugs.webkit.org/show_bug.cgi?id=225972
     5        <rdar://problem/78211185>
     6
     7        Reviewed by Devin Rousso.
     8
     9        Do not show unused inherited CSS variables in the Styles details sidebar.
     10
     11        When aggregating styles for the selected node in `WI.DOMNodeStyles`, collect a list of names of CSS variables used in CSS property values.
     12        In the Styles details sidebar, skip rendering declarations of inherited CSS variables that are not found in this list.
     13
     14        Always show inherited variables that are used, either directly inherited or via reference (variables using other variables in their value).
     15        Always show inherited variables used as values of inheritable properties like color, font-size, etc.
     16
     17        When a CSS rule contains hidden inherited variables, offer a button to request disclosing them for that rule.
     18        Option-click to show unused inherited variables in all matching rules.
     19
     20        Clicking the "Go to variable" button automatically renders all the unused variables in the CSS rule where the target variable is declared.
     21
     22        * Localizations/en.lproj/localizedStrings.js:
     23        * UserInterface/Models/CSSProperty.js:
     24        (WI.CSSProperty.findVariableNames):
     25        * UserInterface/Models/DOMNodeStyles.js:
     26        (WI.DOMNodeStyles):
     27        (WI.DOMNodeStyles.prototype.get usedCSSVariables):
     28        (WI.DOMNodeStyles.prototype._updateStyleCascade):
     29        (WI.DOMNodeStyles.prototype._collectUsedCSSVariables):
     30        * UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css:
     31        (.spreadsheet-style-declaration-editor .property):
     32        (.spreadsheet-style-declaration-editor > .hidden-variables-button):
     33        * UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.js:
     34        (WI.SpreadsheetCSSStyleDeclarationEditor):
     35        (WI.SpreadsheetCSSStyleDeclarationEditor.prototype.layout):
     36        (WI.SpreadsheetCSSStyleDeclarationEditor.prototype.get propertiesToRender):
     37        (WI.SpreadsheetCSSStyleDeclarationEditor.prototype.highlightProperty):
     38        * UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js:
     39        (WI.SpreadsheetCSSStyleDeclarationSection.prototype.set propertyVisibilityMode):
     40        (WI.SpreadsheetCSSStyleDeclarationSection.prototype.spreadsheetCSSStyleDeclarationEditorSetAllPropertyVisibilityMode):
     41        * UserInterface/Views/SpreadsheetRulesStyleDetailsPanel.js:
     42        (WI.SpreadsheetRulesStyleDetailsPanel.prototype.spreadsheetCSSStyleDeclarationSectionSetAllPropertyVisibilityMode):
     43
    1442021-06-04  Devin Rousso  <drousso@apple.com>
    245
  • trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js

    r277289 r278607  
    10291029localizedStrings["Open in New Window @ Context Menu Item"] = "Open in New Window";
    10301030localizedStrings["Option-click to show source"] = "Option-click to show source";
     1031/* Tooltip with instructions on how to show all hidden CSS variables */
     1032localizedStrings["Option-click to show unused CSS variables from all rules @ Styles Sidebar Panel Tooltip"] = "Option-click to show unused CSS variables from all rules";
    10311033localizedStrings["Options"] = "Options";
    10321034/* Property value for `font-variant-numeric: ordinal`. */
     
    13201322localizedStrings["Shortest property path to %s"] = "Shortest property path to %s";
    13211323localizedStrings["Show %d More"] = "Show %d More";
     1324/* Text label for button to reveal multiple unused CSS variables */
     1325localizedStrings["Show %d unused CSS variable (singular) @ Styles Sidebar Panel"] = "Show %d unused CSS variable";
     1326/* Text label for button to reveal one unused CSS variable */
     1327localizedStrings["Show %d unused CSS variables (plural) @ Styles Sidebar Panel"] = "Show %d unused CSS variables";
    13221328localizedStrings["Show All"] = "Show All";
    13231329localizedStrings["Show All (%d More)"] = "Show All (%d More)";
  • trunk/Source/WebInspectorUI/UserInterface/Models/CSSProperty.js

    r253172 r278607  
    5050    }
    5151
     52    // FIXME: <https://webkit.org/b/226647> This naively collects variable-like names used in values. It should be hardened.
     53    static findVariableNames(string)
     54    {
     55        const prefix = "var(--";
     56        let prefixCursor = 0;
     57        let cursor = 0;
     58        let nameStartIndex = 0;
     59        let names = [];
     60
     61        function isTerminatingChar(char) {
     62            return char === ")" || char === "," || char === " " || char === "\n" || char === "\t";
     63        }
     64
     65        while (cursor < string.length) {
     66            if (nameStartIndex && isTerminatingChar(string.charAt(cursor))) {
     67                names.push("--" + string.substring(nameStartIndex, cursor));
     68                nameStartIndex = 0;
     69            }
     70
     71            if (prefixCursor === prefix.length) {
     72                prefixCursor = 0;
     73                nameStartIndex = cursor;
     74            }
     75
     76            if (string.charAt(cursor) === prefix.charAt(prefixCursor))
     77                prefixCursor++;
     78
     79            cursor++;
     80        }
     81
     82        return names;
     83    }
     84
    5285    // Public
    5386
  • trunk/Source/WebInspectorUI/UserInterface/Models/DOMNodeStyles.js

    r270637 r278607  
    4747
    4848        this._propertyNameToEffectivePropertyMap = {};
     49        this._usedCSSVariables = new Set;
    4950
    5051        this._pendingRefreshTask = null;
     
    130131    get orderedStyles() { return this._orderedStyles; }
    131132    get computedPrimaryFont() { return this._computedPrimaryFont; }
     133    get usedCSSVariables() { return this._usedCSSVariables; }
    132134
    133135    get needsRefresh()
     
    768770        this._associateRelatedProperties(cascadeOrderedStyleDeclarations, this._propertyNameToEffectivePropertyMap);
    769771        this._markOverriddenProperties(cascadeOrderedStyleDeclarations, this._propertyNameToEffectivePropertyMap);
     772        this._collectUsedCSSVariables(cascadeOrderedStyleDeclarations);
    770773
    771774        for (let pseudoElementInfo of this._pseudoElements.values()) {
     
    943946    }
    944947
     948    _collectUsedCSSVariables(styles)
     949    {
     950        this._usedCSSVariables = new Set;
     951
     952        for (let style of styles) {
     953            for (let property of style.enabledProperties) {
     954                let variables = WI.CSSProperty.findVariableNames(property.value);
     955
     956                if (!style.inherited) {
     957                    // FIXME: <https://webkit.org/b/226648> Support the case of variables declared on matching styles but not used anywhere.
     958                    this._usedCSSVariables.addAll(variables);
     959                    continue;
     960                }
     961
     962                // Always collect variables used in values of inheritable properties.
     963                if (WI.CSSKeywordCompletions.InheritedProperties.has(property.name)) {
     964                    this._usedCSSVariables.addAll(variables);
     965                    continue;
     966                }
     967
     968                // For variables from inherited styles, leverage the fact that styles are already sorted in cascade order to support inherited variables referencing other variables.
     969                // If the variable was found to be used before, collect any variables used in its declaration value
     970                // (if any variables are found, this isn't the end of the variable reference chain in the inheritance stack).
     971                if (property.isVariable && this._usedCSSVariables.has(property.name))
     972                    this._usedCSSVariables.addAll(variables);
     973            }
     974        }
     975    }
     976
    945977    _isPropertyFoundInMatchingRules(propertyName)
    946978    {
  • trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css

    r269166 r278607  
    3434    --background-color-selected: var(--selected-text-background-color);
    3535    --border-color-selected: var(--selected-background-color);
     36    --property-checkbox-width: 17px;
     37    --property-indentation: calc(var(--css-declaration-horizontal-padding) + var(--property-checkbox-width));
    3638}
    3739
     
    4244.spreadsheet-style-declaration-editor .property {
    4345    padding-right: var(--css-declaration-horizontal-padding);
    44     padding-left: calc(var(--css-declaration-horizontal-padding) + 17px);
     46    padding-left: var(--property-indentation);
    4547    border-right: 2px solid transparent;
    4648    border-left: 1px solid transparent;
     
    232234    left: 16px;
    233235    white-space: nowrap;
     236}
     237
     238.spreadsheet-style-declaration-editor > .hidden-variables-button {
     239    margin-left: var(--property-indentation);
    234240}
    235241
  • trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.js

    r270134 r278607  
    4141        this._showsImplicitProperties = false;
    4242        this._alwaysShowPropertyNames = new Set;
    43         this._propertyVisibilityMode = WI.SpreadsheetCSSStyleDeclarationEditor.PropertyVisibilityMode.ShowAll;
     43        this._propertyVisibilityMode = WI.SpreadsheetCSSStyleDeclarationEditor.PropertyVisibilityMode.HideUnusedInheritedVariables;
     44        this._hiddenUnusedVariables = new Set;
    4445        this._hideFilterNonMatchingProperties = false;
    4546        this._sortPropertiesByName = false;
     
    105106        }
    106107
     108        if (this._hiddenUnusedVariables.size) {
     109            let showHiddenVariablesButtonElement = this.element.appendChild(document.createElement("button"));
     110            showHiddenVariablesButtonElement.classList.add("hidden-variables-button");
     111            showHiddenVariablesButtonElement.title = WI.UIString("Option-click to show unused CSS variables from all rules", "Option-click to show unused CSS variables from all rules @ Styles Sidebar Panel Tooltip", "Tooltip with instructions on how to show all hidden CSS variables");
     112
     113            const labelSingular = WI.UIString("Show %d unused CSS variable", "Show %d unused CSS variable (singular) @ Styles Sidebar Panel", "Text label for button to reveal one unused CSS variable");
     114            const labelPlural = WI.UIString("Show %d unused CSS variables", "Show %d unused CSS variables (plural) @ Styles Sidebar Panel", "Text label for button to reveal multiple unused CSS variables");
     115            let label = this._hiddenUnusedVariables.size > 1 ? labelPlural : labelSingular;
     116
     117            showHiddenVariablesButtonElement.textContent = label.format(this._hiddenUnusedVariables.size);
     118            showHiddenVariablesButtonElement.addEventListener("click", (event) => {
     119                if (event.altKey) {
     120                    this._setAllPropertyVisibilityMode(WI.SpreadsheetCSSStyleDeclarationEditor.PropertyVisibilityMode.ShowAll);
     121                    return;
     122                }
     123
     124                this.propertyVisibilityMode = WI.SpreadsheetCSSStyleDeclarationEditor.PropertyVisibilityMode.ShowAll;
     125            });
     126        }
     127
    107128        if (propertyViewPendingStartEditing) {
    108129            propertyViewPendingStartEditing.startEditingName();
     
    118139            this.selectProperties(this._anchorIndex, this._focusIndex);
    119140
     141        if (this._pendingPropertyToHighlight) {
     142            this.highlightProperty(this._pendingPropertyToHighlight);
     143            this._pendingPropertyToHighlight = null;
     144        }
     145
    120146        this._updateDebugLockStatus();
    121147    }
     
    235261        let hideVariables = this._propertyVisibilityMode === SpreadsheetCSSStyleDeclarationEditor.PropertyVisibilityMode.HideVariables;
    236262        let hideNonVariables = this._propertyVisibilityMode === SpreadsheetCSSStyleDeclarationEditor.PropertyVisibilityMode.HideNonVariables;
     263        let hideUnusedInheritedVariables = this._propertyVisibilityMode === SpreadsheetCSSStyleDeclarationEditor.PropertyVisibilityMode.HideUnusedInheritedVariables;
     264
     265        this._hiddenUnusedVariables = new Set;
    237266
    238267        return properties.filter((property) => {
     
    242271            if (property.isVariable && hideVariables)
    243272                return false;
     273
     274            if (property.isVariable && hideUnusedInheritedVariables && this._style.inherited && !this._style.nodeStyles.usedCSSVariables.has(property.name)) {
     275                this._hiddenUnusedVariables.add(property);
     276                return false;
     277            }
    244278
    245279            return !property.implicit || this._showsImplicitProperties || this._alwaysShowPropertyNames.has(property.canonicalName);
     
    278312    highlightProperty(property)
    279313    {
     314        if (!property.overridden && this._hiddenUnusedVariables.has(property)) {
     315            this._pendingPropertyToHighlight = property;
     316            this.propertyVisibilityMode = WI.SpreadsheetCSSStyleDeclarationEditor.PropertyVisibilityMode.ShowAll;
     317            return true;
     318        }
     319
    280320        let propertiesMatch = (cssProperty) => {
    281321            if (cssProperty.attached && !cssProperty.overridden) {
     
    684724        this.element.classList.toggle("debug-style-locked", this._style.locked);
    685725    }
     726
     727    _setAllPropertyVisibilityMode(propertyVisibilityMode)
     728    {
     729        this._delegate?.spreadsheetCSSStyleDeclarationEditorSetAllPropertyVisibilityMode?.(this, propertyVisibilityMode);
     730    }
    686731};
    687732
     
    696741    HideVariables: Symbol("variable-visibility-hide-variables"),
    697742    HideNonVariables: Symbol("variable-visibility-hide-non-variables"),
     743    HideUnusedInheritedVariables: Symbol("variable-visibility-hide-unused-inherited-variables"),
    698744};
  • trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js

    r270134 r278607  
    5959    }
    6060
     61    set propertyVisibilityMode(propertyVisibilityMode)
     62    {
     63        this._propertiesEditor.propertyVisibilityMode = propertyVisibilityMode;
     64    }
     65
    6166    initialLayout()
    6267    {
     
    285290    }
    286291
     292    spreadsheetCSSStyleDeclarationEditorSetAllPropertyVisibilityMode(editor, propertyVisibilityMode)
     293    {
     294        this._delegate?.spreadsheetCSSStyleDeclarationSectionSetAllPropertyVisibilityMode?.(this, propertyVisibilityMode);
     295    }
     296
    287297    applyFilter(filterText)
    288298    {
  • trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetRulesStyleDetailsPanel.js

    r276278 r278607  
    204204    }
    205205
     206    spreadsheetCSSStyleDeclarationSectionSetAllPropertyVisibilityMode(section, propertyVisibilityMode)
     207    {
     208        for (let section of this._sections)
     209            section.propertyVisibilityMode = propertyVisibilityMode;
     210    }
     211
    206212    // Protected
    207213
Note: See TracChangeset for help on using the changeset viewer.