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 |