| 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 |