| OLD | NEW | 
|    1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. |    1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 
|    2 // Use of this source code is governed by a BSD-style license that can be |    2 // Use of this source code is governed by a BSD-style license that can be | 
|    3 // found in the LICENSE file. |    3 // found in the LICENSE file. | 
|    4  |    4  | 
|    5 /** |    5 /** | 
|    6  * @constructor |    6  * @constructor | 
|    7  * @param {!WebInspector.SectionCascade} cascade |    7  * @param {!WebInspector.CSSStyleModel.MatchedStyleResult} matchedStyles | 
|    8  * @param {?WebInspector.CSSRule} rule |    8  * @param {!Array<!WebInspector.CSSStyleDeclaration>} styles | 
|    9  * @param {!WebInspector.CSSStyleDeclaration} style |  | 
|   10  * @param {string} customSelectorText |  | 
|   11  * @param {?WebInspector.DOMNode=} inheritedFromNode |  | 
|   12  */ |    9  */ | 
|   13 WebInspector.StylesSectionModel = function(cascade, rule, style, customSelectorT
     ext, inheritedFromNode) |   10 WebInspector.SectionCascade = function(matchedStyles, styles) | 
|   14 { |   11 { | 
|   15     this._cascade = cascade; |   12     this._matchedStyles = matchedStyles; | 
|   16     this._rule = rule; |   13     this._styles = styles; | 
|   17     this._style = style; |   14     this.resetActiveProperties(); | 
|   18     this._customSelectorText = customSelectorText; |  | 
|   19     this._editable = !!(this._style && this._style.styleSheetId); |  | 
|   20     this._inheritedFromNode = inheritedFromNode || null; |  | 
|   21 } |   15 } | 
|   22  |   16  | 
|   23 WebInspector.StylesSectionModel.prototype = { |   17 /** | 
 |   18  * @param {!WebInspector.CSSStyleModel.MatchedStyleResult} matchedStyles | 
 |   19  * @return {!{matched: !WebInspector.SectionCascade, pseudo: !Map.<number, !WebI
     nspector.SectionCascade>}} | 
 |   20  */ | 
 |   21 WebInspector.SectionCascade.fromMatchedStyles = function(matchedStyles) | 
 |   22 { | 
 |   23     var matched = new WebInspector.SectionCascade(matchedStyles, matchedStyles.n
     odeStyles()); | 
 |   24     var pseudo = new Map(); | 
 |   25  | 
 |   26     var pseudoStyles = matchedStyles.pseudoStyles(); | 
 |   27     var pseudoElements = pseudoStyles.keysArray(); | 
 |   28     for (var i = 0; i < pseudoElements.length; ++i) { | 
 |   29         var pseudoElement = pseudoElements[i]; | 
 |   30         var pseudoCascade = new WebInspector.SectionCascade(matchedStyles, /** @
     type {!Array<!WebInspector.CSSStyleDeclaration>} */(pseudoStyles.get(pseudoEleme
     nt))); | 
 |   31         pseudo.set(pseudoElement, pseudoCascade); | 
 |   32     } | 
 |   33  | 
 |   34     return { | 
 |   35         matched: matched, | 
 |   36         pseudo: pseudo | 
 |   37     }; | 
 |   38 } | 
 |   39  | 
 |   40 WebInspector.SectionCascade.prototype = { | 
|   24     /** |   41     /** | 
|   25      * @return {!WebInspector.SectionCascade} |   42      * @param {!WebInspector.CSSStyleDeclaration} style | 
 |   43      * @return {boolean} | 
|   26      */ |   44      */ | 
|   27     cascade: function() |   45     hasMatchingSelectors: function(style) | 
|   28     { |   46     { | 
|   29         return this._cascade; |   47         return style.parentRule ? style.parentRule.matchingSelectors && style.pa
     rentRule.matchingSelectors.length > 0 && this.mediaMatches(style) : true; | 
|   30     }, |   48     }, | 
|   31  |   49  | 
|   32     /** |   50     /** | 
 |   51      * @param {!WebInspector.CSSStyleDeclaration} style | 
|   33      * @return {boolean} |   52      * @return {boolean} | 
|   34      */ |   53      */ | 
|   35     hasMatchingSelectors: function() |   54     mediaMatches: function(style) | 
|   36     { |   55     { | 
|   37         return this.rule() ? this.rule().matchingSelectors.length > 0 && this.me
     diaMatches() : true; |   56         var media = style.parentRule ? style.parentRule.media : []; | 
|   38     }, |  | 
|   39  |  | 
|   40     /** |  | 
|   41      * @return {boolean} |  | 
|   42      */ |  | 
|   43     mediaMatches: function() |  | 
|   44     { |  | 
|   45         var media = this.media(); |  | 
|   46         for (var i = 0; media && i < media.length; ++i) { |   57         for (var i = 0; media && i < media.length; ++i) { | 
|   47             if (!media[i].active()) |   58             if (!media[i].active()) | 
|   48                 return false; |   59                 return false; | 
|   49         } |   60         } | 
|   50         return true; |   61         return true; | 
|   51     }, |   62     }, | 
|   52  |   63  | 
|   53     /** |   64     /** | 
|   54      * @return {boolean} |  | 
|   55      */ |  | 
|   56     inherited: function() |  | 
|   57     { |  | 
|   58         return !!this._inheritedFromNode; |  | 
|   59     }, |  | 
|   60  |  | 
|   61     /** |  | 
|   62      * @return {?WebInspector.DOMNode} |  | 
|   63      */ |  | 
|   64     parentNode: function() |  | 
|   65     { |  | 
|   66         return this._inheritedFromNode; |  | 
|   67     }, |  | 
|   68  |  | 
|   69     /** |  | 
|   70      * @return {string} |  | 
|   71      */ |  | 
|   72     selectorText: function() |  | 
|   73     { |  | 
|   74         if (this._customSelectorText) |  | 
|   75             return this._customSelectorText; |  | 
|   76         return this.rule() ? this.rule().selectorText() : ""; |  | 
|   77     }, |  | 
|   78  |  | 
|   79     /** |  | 
|   80      * @return {boolean} |  | 
|   81      */ |  | 
|   82     editable: function() |  | 
|   83     { |  | 
|   84         return this._editable; |  | 
|   85     }, |  | 
|   86  |  | 
|   87     /** |  | 
|   88      * @param {boolean} editable |  | 
|   89      */ |  | 
|   90     setEditable: function(editable) |  | 
|   91     { |  | 
|   92         this._editable = editable; |  | 
|   93     }, |  | 
|   94  |  | 
|   95     /** |  | 
|   96      * @return {!WebInspector.CSSStyleDeclaration} |  | 
|   97      */ |  | 
|   98     style: function() |  | 
|   99     { |  | 
|  100         return this._style; |  | 
|  101     }, |  | 
|  102  |  | 
|  103     /** |  | 
|  104      * @return {?WebInspector.CSSRule} |  | 
|  105      */ |  | 
|  106     rule: function() |  | 
|  107     { |  | 
|  108         return this._rule; |  | 
|  109     }, |  | 
|  110  |  | 
|  111     /** |  | 
|  112      * @return {?Array.<!WebInspector.CSSMedia>} |  | 
|  113      */ |  | 
|  114     media: function() |  | 
|  115     { |  | 
|  116         return this.rule() ? this.rule().media : null; |  | 
|  117     }, |  | 
|  118  |  | 
|  119     resetCachedData: function() |  | 
|  120     { |  | 
|  121         this._cascade._resetUsedProperties(); |  | 
|  122     } |  | 
|  123 } |  | 
|  124  |  | 
|  125 /** |  | 
|  126  * @constructor |  | 
|  127  */ |  | 
|  128 WebInspector.SectionCascade = function() |  | 
|  129 { |  | 
|  130     this._models = []; |  | 
|  131     this._resetUsedProperties(); |  | 
|  132 } |  | 
|  133  |  | 
|  134 WebInspector.SectionCascade.prototype = { |  | 
|  135     /** |  | 
|  136      * @return {!Array.<!WebInspector.StylesSectionModel>} |  | 
|  137      */ |  | 
|  138     sectionModels: function() |  | 
|  139     { |  | 
|  140         return this._models; |  | 
|  141     }, |  | 
|  142  |  | 
|  143     /** |  | 
|  144      * @param {!WebInspector.CSSRule} rule |  | 
|  145      * @param {!WebInspector.StylesSectionModel} insertAfterStyleRule |  | 
|  146      * @return {!WebInspector.StylesSectionModel} |  | 
|  147      */ |  | 
|  148     insertModelFromRule: function(rule, insertAfterStyleRule) |  | 
|  149     { |  | 
|  150         return this._insertModel(new WebInspector.StylesSectionModel(this, rule,
      rule.style, "", null), insertAfterStyleRule); |  | 
|  151     }, |  | 
|  152  |  | 
|  153     /** |  | 
|  154      * @param {!WebInspector.CSSStyleDeclaration} style |   65      * @param {!WebInspector.CSSStyleDeclaration} style | 
|  155      * @param {string} selectorText |   66      * @return {?WebInspector.DOMNode} | 
|  156      * @param {?WebInspector.DOMNode=} inheritedFromNode |  | 
|  157      * @return {!WebInspector.StylesSectionModel} |  | 
|  158      */ |   67      */ | 
|  159     appendModelFromStyle: function(style, selectorText, inheritedFromNode) |   68     nodeForStyle: function(style) | 
|  160     { |   69     { | 
|  161         return this._insertModel(new WebInspector.StylesSectionModel(this, style
     .parentRule, style, selectorText, inheritedFromNode)); |   70         return this._matchedStyles.nodeForStyle(style); | 
|  162     }, |   71     }, | 
|  163  |   72  | 
|  164     /** |   73     /** | 
|  165      * @param {!WebInspector.StylesSectionModel} model |   74      * @param {!WebInspector.CSSStyleDeclaration} style | 
|  166      * @param {!WebInspector.StylesSectionModel=} insertAfter |   75      * @return {boolean} | 
|  167      * @return {!WebInspector.StylesSectionModel} |  | 
|  168      */ |   76      */ | 
|  169     _insertModel: function(model, insertAfter) |   77     isInherited: function(style) | 
|  170     { |   78     { | 
|  171         if (insertAfter) { |   79         return this._matchedStyles.isInherited(style); | 
|  172             var index = this._models.indexOf(insertAfter); |  | 
|  173             console.assert(index !== -1, "The insertAfter anchor could not be fo
     und in cascade"); |  | 
|  174             this._models.splice(index + 1, 0, model); |  | 
|  175         } else { |  | 
|  176             this._models.push(model); |  | 
|  177         } |  | 
|  178         this._resetUsedProperties(); |  | 
|  179         return model; |  | 
|  180     }, |   80     }, | 
|  181  |   81  | 
|  182     /** |   82     /** | 
 |   83      * @return {!Array.<!WebInspector.CSSStyleDeclaration>} | 
 |   84      */ | 
 |   85     styles: function() | 
 |   86     { | 
 |   87         return this._styles; | 
 |   88     }, | 
 |   89  | 
 |   90     /** | 
 |   91      * @param {!WebInspector.CSSStyleDeclaration} style | 
 |   92      * @param {!WebInspector.CSSStyleDeclaration=} insertAfter | 
 |   93      */ | 
 |   94     insertStyle: function(style, insertAfter) | 
 |   95     { | 
 |   96         if (insertAfter) { | 
 |   97             var index = this._styles.indexOf(insertAfter); | 
 |   98             console.assert(index !== -1, "The insertAfter anchor could not be fo
     und in cascade"); | 
 |   99             this._styles.splice(index + 1, 0, style); | 
 |  100         } else { | 
 |  101             this._styles.push(style); | 
 |  102         } | 
 |  103         this.resetActiveProperties(); | 
 |  104     }, | 
 |  105  | 
 |  106     /** | 
|  183      * @param {!WebInspector.CSSProperty} property |  107      * @param {!WebInspector.CSSProperty} property | 
|  184      * @return {?WebInspector.SectionCascade.PropertyState} |  108      * @return {?WebInspector.SectionCascade.PropertyState} | 
|  185      */ |  109      */ | 
|  186     propertyState: function(property) |  110     propertyState: function(property) | 
|  187     { |  111     { | 
|  188         if (this._propertiesState.size === 0) |  112         if (this._propertiesState.size === 0) | 
|  189             this._propertiesState = WebInspector.SectionCascade._computeUsedProp
     erties(this._models); |  113             this._propertiesState = this._computeActiveProperties(); | 
|  190         return this._propertiesState.get(property) || null; |  114         return this._propertiesState.get(property) || null; | 
|  191     }, |  115     }, | 
|  192  |  116  | 
|  193     _resetUsedProperties: function() |  117     resetActiveProperties: function() | 
|  194     { |  118     { | 
|  195         /** @type {!Map<!WebInspector.CSSProperty, !WebInspector.SectionCascade.
     PropertyState>} */ |  119         /** @type {!Map<!WebInspector.CSSProperty, !WebInspector.SectionCascade.
     PropertyState>} */ | 
|  196         this._propertiesState = new Map(); |  120         this._propertiesState = new Map(); | 
|  197     } |  121     }, | 
|  198 } |  | 
|  199  |  122  | 
|  200 /** |  123     /** | 
|  201  * @param {!Array.<!WebInspector.StylesSectionModel>} styleRules |  124      * @return {!Map<!WebInspector.CSSProperty, !WebInspector.SectionCascade.Pro
     pertyState>} | 
|  202  * @return {!Map<!WebInspector.CSSProperty, !WebInspector.SectionCascade.Propert
     yState>} |  125      */ | 
|  203  */ |  126     _computeActiveProperties: function() | 
|  204 WebInspector.SectionCascade._computeUsedProperties = function(styleRules) |  127     { | 
|  205 { |  128         /** @type {!Set.<string>} */ | 
|  206     /** @type {!Set.<string>} */ |  129         var foundImportantProperties = new Set(); | 
|  207     var foundImportantProperties = new Set(); |  130         /** @type {!Map.<string, !Map<string, !WebInspector.CSSProperty>>} */ | 
|  208     /** @type {!Map.<string, !Map<string, !WebInspector.CSSProperty>>} */ |  131         var propertyToEffectiveRule = new Map(); | 
|  209     var propertyToEffectiveRule = new Map(); |  132         /** @type {!Map.<string, !WebInspector.DOMNode>} */ | 
|  210     /** @type {!Map.<string, !WebInspector.DOMNode>} */ |  133         var inheritedPropertyToNode = new Map(); | 
|  211     var inheritedPropertyToNode = new Map(); |  134         /** @type {!Set<string>} */ | 
|  212     /** @type {!Set<string>} */ |  135         var allUsedProperties = new Set(); | 
|  213     var allUsedProperties = new Set(); |  136         var result = new Map(); | 
|  214     var result = new Map(); |  137         for (var i = 0; i < this._styles.length; ++i) { | 
|  215     for (var i = 0; i < styleRules.length; ++i) { |  138             var style = this._styles[i]; | 
|  216         var styleRule = styleRules[i]; |  139             if (!this.hasMatchingSelectors(style)) | 
|  217         if (!styleRule.hasMatchingSelectors()) |  | 
|  218             continue; |  | 
|  219  |  | 
|  220         /** @type {!Map<string, !WebInspector.CSSProperty>} */ |  | 
|  221         var styleActiveProperties = new Map(); |  | 
|  222         var style = styleRule.style(); |  | 
|  223         var allProperties = style.allProperties; |  | 
|  224         for (var j = 0; j < allProperties.length; ++j) { |  | 
|  225             var property = allProperties[j]; |  | 
|  226  |  | 
|  227             // Do not pick non-inherited properties from inherited styles. |  | 
|  228             if (styleRule.inherited() && !WebInspector.CSSMetadata.isPropertyInh
     erited(property.name)) |  | 
|  229                 continue; |  140                 continue; | 
|  230  |  141  | 
|  231             if (!property.activeInStyle()) { |  142             /** @type {!Map<string, !WebInspector.CSSProperty>} */ | 
|  232                 result.set(property, WebInspector.SectionCascade.PropertyState.O
     verloaded); |  143             var styleActiveProperties = new Map(); | 
|  233                 continue; |  144             var allProperties = style.allProperties; | 
|  234             } |  145             for (var j = 0; j < allProperties.length; ++j) { | 
 |  146                 var property = allProperties[j]; | 
|  235  |  147  | 
|  236             var canonicalName = WebInspector.CSSMetadata.canonicalPropertyName(p
     roperty.name); |  148                 // Do not pick non-inherited properties from inherited styles. | 
|  237             if (foundImportantProperties.has(canonicalName)) { |  149                 var inherited = this._matchedStyles.isInherited(style); | 
|  238                 result.set(property, WebInspector.SectionCascade.PropertyState.O
     verloaded); |  150                 if (inherited && !WebInspector.CSSMetadata.isPropertyInherited(p
     roperty.name)) | 
|  239                 continue; |  151                     continue; | 
|  240             } |  | 
|  241  |  152  | 
|  242             if (!property.important && allUsedProperties.has(canonicalName)) { |  153                 if (!property.activeInStyle()) { | 
|  243                 result.set(property, WebInspector.SectionCascade.PropertyState.O
     verloaded); |  | 
|  244                 continue; |  | 
|  245             } |  | 
|  246  |  | 
|  247             var isKnownProperty = propertyToEffectiveRule.has(canonicalName); |  | 
|  248             var parentNode = styleRule.parentNode(); |  | 
|  249             if (!isKnownProperty && parentNode && !inheritedPropertyToNode.has(c
     anonicalName)) |  | 
|  250                 inheritedPropertyToNode.set(canonicalName, parentNode); |  | 
|  251  |  | 
|  252             if (property.important) { |  | 
|  253                 if (styleRule.inherited() && isKnownProperty && styleRule.parent
     Node() !== inheritedPropertyToNode.get(canonicalName)) { |  | 
|  254                     result.set(property, WebInspector.SectionCascade.PropertySta
     te.Overloaded); |  154                     result.set(property, WebInspector.SectionCascade.PropertySta
     te.Overloaded); | 
|  255                     continue; |  155                     continue; | 
|  256                 } |  156                 } | 
|  257  |  157  | 
|  258                 foundImportantProperties.add(canonicalName); |  158                 var canonicalName = WebInspector.CSSMetadata.canonicalPropertyNa
     me(property.name); | 
|  259                 if (isKnownProperty) { |  159                 if (foundImportantProperties.has(canonicalName)) { | 
|  260                     var overloaded = propertyToEffectiveRule.get(canonicalName).
     get(canonicalName); |  160                     result.set(property, WebInspector.SectionCascade.PropertySta
     te.Overloaded); | 
|  261                     result.set(overloaded, WebInspector.SectionCascade.PropertyS
     tate.Overloaded); |  161                     continue; | 
|  262                     propertyToEffectiveRule.get(canonicalName).delete(canonicalN
     ame); |  | 
|  263                 } |  162                 } | 
 |  163  | 
 |  164                 if (!property.important && allUsedProperties.has(canonicalName))
      { | 
 |  165                     result.set(property, WebInspector.SectionCascade.PropertySta
     te.Overloaded); | 
 |  166                     continue; | 
 |  167                 } | 
 |  168  | 
 |  169                 var isKnownProperty = propertyToEffectiveRule.has(canonicalName)
     ; | 
 |  170                 var inheritedFromNode = inherited ? this._matchedStyles.nodeForS
     tyle(style) : null; | 
 |  171                 if (!isKnownProperty && inheritedFromNode && !inheritedPropertyT
     oNode.has(canonicalName)) | 
 |  172                     inheritedPropertyToNode.set(canonicalName, inheritedFromNode
     ); | 
 |  173  | 
 |  174                 if (property.important) { | 
 |  175                     if (inherited && isKnownProperty && inheritedFromNode !== in
     heritedPropertyToNode.get(canonicalName)) { | 
 |  176                         result.set(property, WebInspector.SectionCascade.Propert
     yState.Overloaded); | 
 |  177                         continue; | 
 |  178                     } | 
 |  179  | 
 |  180                     foundImportantProperties.add(canonicalName); | 
 |  181                     if (isKnownProperty) { | 
 |  182                         var overloaded = propertyToEffectiveRule.get(canonicalNa
     me).get(canonicalName); | 
 |  183                         result.set(overloaded, WebInspector.SectionCascade.Prope
     rtyState.Overloaded); | 
 |  184                         propertyToEffectiveRule.get(canonicalName).delete(canoni
     calName); | 
 |  185                     } | 
 |  186                 } | 
 |  187  | 
 |  188                 styleActiveProperties.set(canonicalName, property); | 
 |  189                 allUsedProperties.add(canonicalName); | 
 |  190                 propertyToEffectiveRule.set(canonicalName, styleActiveProperties
     ); | 
 |  191                 result.set(property, WebInspector.SectionCascade.PropertyState.A
     ctive); | 
|  264             } |  192             } | 
|  265  |  193  | 
|  266             styleActiveProperties.set(canonicalName, property); |  194             // If every longhand of the shorthand is not active, then the shorth
     and is not active too. | 
|  267             allUsedProperties.add(canonicalName); |  195             for (var property of style.leadingProperties()) { | 
|  268             propertyToEffectiveRule.set(canonicalName, styleActiveProperties); |  196                 var canonicalName = WebInspector.CSSMetadata.canonicalPropertyNa
     me(property.name); | 
|  269             result.set(property, WebInspector.SectionCascade.PropertyState.Activ
     e); |  197                 if (!styleActiveProperties.has(canonicalName)) | 
 |  198                     continue; | 
 |  199                 var longhands = style.longhandProperties(property.name); | 
 |  200                 if (!longhands.length) | 
 |  201                     continue; | 
 |  202                 var notUsed = true; | 
 |  203                 for (var longhand of longhands) { | 
 |  204                     var longhandCanonicalName = WebInspector.CSSMetadata.canonic
     alPropertyName(longhand.name); | 
 |  205                     notUsed = notUsed && !styleActiveProperties.has(longhandCano
     nicalName); | 
 |  206                 } | 
 |  207                 if (!notUsed) | 
 |  208                     continue; | 
 |  209                 styleActiveProperties.delete(canonicalName); | 
 |  210                 allUsedProperties.delete(canonicalName); | 
 |  211                 result.set(property, WebInspector.SectionCascade.PropertyState.O
     verloaded); | 
 |  212             } | 
|  270         } |  213         } | 
|  271  |  214         return result; | 
|  272         // If every longhand of the shorthand is not active, then the shorthand 
     is not active too. |  | 
|  273         for (var property of style.leadingProperties()) { |  | 
|  274             var canonicalName = WebInspector.CSSMetadata.canonicalPropertyName(p
     roperty.name); |  | 
|  275             if (!styleActiveProperties.has(canonicalName)) |  | 
|  276                 continue; |  | 
|  277             var longhands = style.longhandProperties(property.name); |  | 
|  278             if (!longhands.length) |  | 
|  279                 continue; |  | 
|  280             var notUsed = true; |  | 
|  281             for (var longhand of longhands) { |  | 
|  282                 var longhandCanonicalName = WebInspector.CSSMetadata.canonicalPr
     opertyName(longhand.name); |  | 
|  283                 notUsed = notUsed && !styleActiveProperties.has(longhandCanonica
     lName); |  | 
|  284             } |  | 
|  285             if (!notUsed) |  | 
|  286                 continue; |  | 
|  287             styleActiveProperties.delete(canonicalName); |  | 
|  288             allUsedProperties.delete(canonicalName); |  | 
|  289             result.set(property, WebInspector.SectionCascade.PropertyState.Overl
     oaded); |  | 
|  290         } |  | 
|  291     } |  215     } | 
|  292     return result; |  | 
|  293 } |  216 } | 
|  294  |  217  | 
|  295 /** @enum {string} */ |  218 /** @enum {string} */ | 
|  296 WebInspector.SectionCascade.PropertyState = { |  219 WebInspector.SectionCascade.PropertyState = { | 
|  297     Active: "Active", |  220     Active: "Active", | 
|  298     Overloaded: "Overloaded" |  221     Overloaded: "Overloaded" | 
|  299 } |  222 } | 
| OLD | NEW |