OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 | |
5 /** | 4 /** |
6 * @constructor | 5 * @unrestricted |
7 * @param {!WebInspector.CSSModel} cssModel | |
8 * @param {!WebInspector.DOMNode} node | |
9 * @param {?CSSAgent.CSSStyle} inlinePayload | |
10 * @param {?CSSAgent.CSSStyle} attributesPayload | |
11 * @param {!Array.<!CSSAgent.RuleMatch>} matchedPayload | |
12 * @param {!Array.<!CSSAgent.PseudoElementMatches>} pseudoPayload | |
13 * @param {!Array.<!CSSAgent.InheritedStyleEntry>} inheritedPayload | |
14 * @param {!Array.<!CSSAgent.CSSKeyframesRule>} animationsPayload | |
15 */ | 6 */ |
16 WebInspector.CSSMatchedStyles = function(cssModel, node, inlinePayload, attribut
esPayload, matchedPayload, pseudoPayload, inheritedPayload, animationsPayload) | 7 WebInspector.CSSMatchedStyles = class { |
17 { | 8 /** |
| 9 * @param {!WebInspector.CSSModel} cssModel |
| 10 * @param {!WebInspector.DOMNode} node |
| 11 * @param {?CSSAgent.CSSStyle} inlinePayload |
| 12 * @param {?CSSAgent.CSSStyle} attributesPayload |
| 13 * @param {!Array.<!CSSAgent.RuleMatch>} matchedPayload |
| 14 * @param {!Array.<!CSSAgent.PseudoElementMatches>} pseudoPayload |
| 15 * @param {!Array.<!CSSAgent.InheritedStyleEntry>} inheritedPayload |
| 16 * @param {!Array.<!CSSAgent.CSSKeyframesRule>} animationsPayload |
| 17 */ |
| 18 constructor( |
| 19 cssModel, |
| 20 node, |
| 21 inlinePayload, |
| 22 attributesPayload, |
| 23 matchedPayload, |
| 24 pseudoPayload, |
| 25 inheritedPayload, |
| 26 animationsPayload) { |
18 this._cssModel = cssModel; | 27 this._cssModel = cssModel; |
19 this._node = node; | 28 this._node = node; |
20 this._nodeStyles = []; | 29 this._nodeStyles = []; |
21 this._nodeForStyle = new Map(); | 30 this._nodeForStyle = new Map(); |
22 this._inheritedStyles = new Set(); | 31 this._inheritedStyles = new Set(); |
23 this._keyframes = []; | 32 this._keyframes = []; |
24 /** @type {!Map<!DOMAgent.NodeId, !Map<string, boolean>>} */ | 33 /** @type {!Map<!DOMAgent.NodeId, !Map<string, boolean>>} */ |
25 this._matchingSelectors = new Map(); | 34 this._matchingSelectors = new Map(); |
26 | 35 |
27 /** | 36 /** |
28 * @this {WebInspector.CSSMatchedStyles} | 37 * @this {WebInspector.CSSMatchedStyles} |
29 */ | 38 */ |
30 function addAttributesStyle() | 39 function addAttributesStyle() { |
31 { | 40 if (!attributesPayload) |
32 if (!attributesPayload) | 41 return; |
33 return; | 42 var style = new WebInspector.CSSStyleDeclaration( |
34 var style = new WebInspector.CSSStyleDeclaration(cssModel, null, attribu
tesPayload, WebInspector.CSSStyleDeclaration.Type.Attributes); | 43 cssModel, null, attributesPayload, WebInspector.CSSStyleDeclaration.Ty
pe.Attributes); |
35 this._nodeForStyle.set(style, this._node); | 44 this._nodeForStyle.set(style, this._node); |
36 this._nodeStyles.push(style); | 45 this._nodeStyles.push(style); |
37 } | 46 } |
38 | 47 |
39 // Inline style has the greatest specificity. | 48 // Inline style has the greatest specificity. |
40 if (inlinePayload && this._node.nodeType() === Node.ELEMENT_NODE) { | 49 if (inlinePayload && this._node.nodeType() === Node.ELEMENT_NODE) { |
41 var style = new WebInspector.CSSStyleDeclaration(cssModel, null, inlineP
ayload, WebInspector.CSSStyleDeclaration.Type.Inline); | 50 var style = new WebInspector.CSSStyleDeclaration( |
42 this._nodeForStyle.set(style, this._node); | 51 cssModel, null, inlinePayload, WebInspector.CSSStyleDeclaration.Type.I
nline); |
43 this._nodeStyles.push(style); | 52 this._nodeForStyle.set(style, this._node); |
| 53 this._nodeStyles.push(style); |
44 } | 54 } |
45 | 55 |
46 // Add rules in reverse order to match the cascade order. | 56 // Add rules in reverse order to match the cascade order. |
47 var addedAttributesStyle; | 57 var addedAttributesStyle; |
48 for (var i = matchedPayload.length - 1; i >= 0; --i) { | 58 for (var i = matchedPayload.length - 1; i >= 0; --i) { |
49 var rule = new WebInspector.CSSStyleRule(cssModel, matchedPayload[i].rul
e); | 59 var rule = new WebInspector.CSSStyleRule(cssModel, matchedPayload[i].rule)
; |
50 if ((rule.isInjected() || rule.isUserAgent()) && !addedAttributesStyle)
{ | 60 if ((rule.isInjected() || rule.isUserAgent()) && !addedAttributesStyle) { |
51 // Show element's Style Attributes after all author rules. | 61 // Show element's Style Attributes after all author rules. |
52 addedAttributesStyle = true; | 62 addedAttributesStyle = true; |
53 addAttributesStyle.call(this); | 63 addAttributesStyle.call(this); |
54 } | 64 } |
55 this._nodeForStyle.set(rule.style, this._node); | 65 this._nodeForStyle.set(rule.style, this._node); |
56 this._nodeStyles.push(rule.style); | 66 this._nodeStyles.push(rule.style); |
57 addMatchingSelectors.call(this, this._node, rule, matchedPayload[i].matc
hingSelectors); | 67 addMatchingSelectors.call(this, this._node, rule, matchedPayload[i].matchi
ngSelectors); |
58 } | 68 } |
59 | 69 |
60 if (!addedAttributesStyle) | 70 if (!addedAttributesStyle) |
61 addAttributesStyle.call(this); | 71 addAttributesStyle.call(this); |
62 | 72 |
63 // Walk the node structure and identify styles with inherited properties. | 73 // Walk the node structure and identify styles with inherited properties. |
64 var parentNode = this._node.parentNode; | 74 var parentNode = this._node.parentNode; |
65 for (var i = 0; parentNode && inheritedPayload && i < inheritedPayload.lengt
h; ++i) { | 75 for (var i = 0; parentNode && inheritedPayload && i < inheritedPayload.lengt
h; ++i) { |
66 var entryPayload = inheritedPayload[i]; | 76 var entryPayload = inheritedPayload[i]; |
67 var inheritedInlineStyle = entryPayload.inlineStyle ? new WebInspector.C
SSStyleDeclaration(cssModel, null, entryPayload.inlineStyle, WebInspector.CSSSty
leDeclaration.Type.Inline) : null; | 77 var inheritedInlineStyle = entryPayload.inlineStyle ? |
68 if (inheritedInlineStyle && this._containsInherited(inheritedInlineStyle
)) { | 78 new WebInspector.CSSStyleDeclaration( |
69 this._nodeForStyle.set(inheritedInlineStyle, parentNode); | 79 cssModel, null, entryPayload.inlineStyle, WebInspector.CSSStyleDec
laration.Type.Inline) : |
70 this._nodeStyles.push(inheritedInlineStyle); | 80 null; |
71 this._inheritedStyles.add(inheritedInlineStyle); | 81 if (inheritedInlineStyle && this._containsInherited(inheritedInlineStyle))
{ |
72 } | 82 this._nodeForStyle.set(inheritedInlineStyle, parentNode); |
| 83 this._nodeStyles.push(inheritedInlineStyle); |
| 84 this._inheritedStyles.add(inheritedInlineStyle); |
| 85 } |
73 | 86 |
74 var inheritedMatchedCSSRules = entryPayload.matchedCSSRules || []; | 87 var inheritedMatchedCSSRules = entryPayload.matchedCSSRules || []; |
75 for (var j = inheritedMatchedCSSRules.length - 1; j >= 0; --j) { | 88 for (var j = inheritedMatchedCSSRules.length - 1; j >= 0; --j) { |
76 var inheritedRule = new WebInspector.CSSStyleRule(cssModel, inherite
dMatchedCSSRules[j].rule); | 89 var inheritedRule = new WebInspector.CSSStyleRule(cssModel, inheritedMat
chedCSSRules[j].rule); |
77 addMatchingSelectors.call(this, parentNode, inheritedRule, inherited
MatchedCSSRules[j].matchingSelectors); | 90 addMatchingSelectors.call(this, parentNode, inheritedRule, inheritedMatc
hedCSSRules[j].matchingSelectors); |
78 if (!this._containsInherited(inheritedRule.style)) | 91 if (!this._containsInherited(inheritedRule.style)) |
79 continue; | 92 continue; |
80 this._nodeForStyle.set(inheritedRule.style, parentNode); | 93 this._nodeForStyle.set(inheritedRule.style, parentNode); |
81 this._nodeStyles.push(inheritedRule.style); | 94 this._nodeStyles.push(inheritedRule.style); |
82 this._inheritedStyles.add(inheritedRule.style); | 95 this._inheritedStyles.add(inheritedRule.style); |
83 } | 96 } |
84 parentNode = parentNode.parentNode; | 97 parentNode = parentNode.parentNode; |
85 } | 98 } |
86 | 99 |
87 // Set up pseudo styles map. | 100 // Set up pseudo styles map. |
88 this._pseudoStyles = new Map(); | 101 this._pseudoStyles = new Map(); |
89 if (pseudoPayload) { | 102 if (pseudoPayload) { |
90 for (var i = 0; i < pseudoPayload.length; ++i) { | 103 for (var i = 0; i < pseudoPayload.length; ++i) { |
91 var entryPayload = pseudoPayload[i]; | 104 var entryPayload = pseudoPayload[i]; |
92 // PseudoElement nodes are not created unless "content" css property
is set. | 105 // PseudoElement nodes are not created unless "content" css property is
set. |
93 var pseudoElement = this._node.pseudoElements().get(entryPayload.pse
udoType) || null; | 106 var pseudoElement = this._node.pseudoElements().get(entryPayload.pseudoT
ype) || null; |
94 var pseudoStyles = []; | 107 var pseudoStyles = []; |
95 var rules = entryPayload.matches || []; | 108 var rules = entryPayload.matches || []; |
96 for (var j = rules.length - 1; j >= 0; --j) { | 109 for (var j = rules.length - 1; j >= 0; --j) { |
97 var pseudoRule = new WebInspector.CSSStyleRule(cssModel, rules[j
].rule); | 110 var pseudoRule = new WebInspector.CSSStyleRule(cssModel, rules[j].rule
); |
98 pseudoStyles.push(pseudoRule.style); | 111 pseudoStyles.push(pseudoRule.style); |
99 this._nodeForStyle.set(pseudoRule.style, pseudoElement); | 112 this._nodeForStyle.set(pseudoRule.style, pseudoElement); |
100 if (pseudoElement) | 113 if (pseudoElement) |
101 addMatchingSelectors.call(this, pseudoElement, pseudoRule, r
ules[j].matchingSelectors); | 114 addMatchingSelectors.call(this, pseudoElement, pseudoRule, rules[j].
matchingSelectors); |
102 } | |
103 this._pseudoStyles.set(entryPayload.pseudoType, pseudoStyles); | |
104 } | 115 } |
| 116 this._pseudoStyles.set(entryPayload.pseudoType, pseudoStyles); |
| 117 } |
105 } | 118 } |
106 | 119 |
107 if (animationsPayload) | 120 if (animationsPayload) |
108 this._keyframes = animationsPayload.map(rule => new WebInspector.CSSKeyf
ramesRule(cssModel, rule)); | 121 this._keyframes = animationsPayload.map(rule => new WebInspector.CSSKeyfra
mesRule(cssModel, rule)); |
109 | 122 |
110 this.resetActiveProperties(); | 123 this.resetActiveProperties(); |
111 | 124 |
112 /** | 125 /** |
113 * @param {!WebInspector.DOMNode} node | 126 * @param {!WebInspector.DOMNode} node |
114 * @param {!WebInspector.CSSStyleRule} rule | 127 * @param {!WebInspector.CSSStyleRule} rule |
115 * @param {!Array<number>} matchingSelectorIndices | 128 * @param {!Array<number>} matchingSelectorIndices |
116 * @this {WebInspector.CSSMatchedStyles} | 129 * @this {WebInspector.CSSMatchedStyles} |
117 */ | 130 */ |
118 function addMatchingSelectors(node, rule, matchingSelectorIndices) | 131 function addMatchingSelectors(node, rule, matchingSelectorIndices) { |
119 { | 132 for (var matchingSelectorIndex of matchingSelectorIndices) { |
120 for (var matchingSelectorIndex of matchingSelectorIndices) { | 133 var selector = rule.selectors[matchingSelectorIndex]; |
121 var selector = rule.selectors[matchingSelectorIndex]; | 134 this._setSelectorMatches(node, selector.text, true); |
122 this._setSelectorMatches(node, selector.text, true); | 135 } |
123 } | 136 } |
124 } | 137 } |
125 }; | 138 |
126 | 139 /** |
127 WebInspector.CSSMatchedStyles.prototype = { | 140 * @return {!WebInspector.DOMNode} |
128 /** | 141 */ |
129 * @return {!WebInspector.DOMNode} | 142 node() { |
130 */ | 143 return this._node; |
131 node: function() | 144 } |
132 { | 145 |
133 return this._node; | 146 /** |
134 }, | 147 * @return {!WebInspector.CSSModel} |
135 | 148 */ |
136 /** | 149 cssModel() { |
137 * @return {!WebInspector.CSSModel} | 150 return this._cssModel; |
138 */ | 151 } |
139 cssModel: function() | 152 |
140 { | 153 /** |
141 return this._cssModel; | 154 * @param {!WebInspector.CSSStyleRule} rule |
142 }, | 155 * @return {boolean} |
143 | 156 */ |
144 /** | 157 hasMatchingSelectors(rule) { |
145 * @param {!WebInspector.CSSStyleRule} rule | 158 var matchingSelectors = this.matchingSelectors(rule); |
146 * @return {boolean} | 159 return matchingSelectors.length > 0 && this.mediaMatches(rule.style); |
147 */ | 160 } |
148 hasMatchingSelectors: function(rule) | 161 |
149 { | 162 /** |
150 var matchingSelectors = this.matchingSelectors(rule); | 163 * @param {!WebInspector.CSSStyleRule} rule |
151 return matchingSelectors.length > 0 && this.mediaMatches(rule.style); | 164 * @return {!Array<number>} |
152 }, | 165 */ |
153 | 166 matchingSelectors(rule) { |
154 /** | 167 var node = this.nodeForStyle(rule.style); |
155 * @param {!WebInspector.CSSStyleRule} rule | 168 if (!node) |
156 * @return {!Array<number>} | 169 return []; |
157 */ | 170 var map = this._matchingSelectors.get(node.id); |
158 matchingSelectors: function(rule) | 171 if (!map) |
159 { | 172 return []; |
160 var node = this.nodeForStyle(rule.style); | 173 var result = []; |
161 if (!node) | 174 for (var i = 0; i < rule.selectors.length; ++i) { |
162 return []; | 175 if (map.get(rule.selectors[i].text)) |
163 var map = this._matchingSelectors.get(node.id); | 176 result.push(i); |
164 if (!map) | 177 } |
165 return []; | 178 return result; |
166 var result = []; | 179 } |
167 for (var i = 0; i < rule.selectors.length; ++i) { | 180 |
168 if (map.get(rule.selectors[i].text)) | 181 /** |
169 result.push(i); | 182 * @param {!WebInspector.CSSStyleRule} rule |
170 } | 183 * @return {!Promise} |
171 return result; | 184 */ |
172 }, | 185 recomputeMatchingSelectors(rule) { |
173 | 186 var node = this.nodeForStyle(rule.style); |
174 /** | 187 if (!node) |
175 * @param {!WebInspector.CSSStyleRule} rule | 188 return Promise.resolve(); |
176 * @return {!Promise} | 189 var promises = []; |
177 */ | 190 for (var selector of rule.selectors) |
178 recomputeMatchingSelectors: function(rule) | 191 promises.push(querySelector.call(this, node, selector.text)); |
179 { | 192 return Promise.all(promises); |
180 var node = this.nodeForStyle(rule.style); | |
181 if (!node) | |
182 return Promise.resolve(); | |
183 var promises = []; | |
184 for (var selector of rule.selectors) | |
185 promises.push(querySelector.call(this, node, selector.text)); | |
186 return Promise.all(promises); | |
187 | |
188 /** | |
189 * @param {!WebInspector.DOMNode} node | |
190 * @param {string} selectorText | |
191 * @return {!Promise} | |
192 * @this {WebInspector.CSSMatchedStyles} | |
193 */ | |
194 function querySelector(node, selectorText) | |
195 { | |
196 var ownerDocument = node.ownerDocument || null; | |
197 // We assume that "matching" property does not ever change during th
e | |
198 // MatchedStyleResult's lifetime. | |
199 var map = this._matchingSelectors.get(node.id); | |
200 if ((map && map.has(selectorText)) || !ownerDocument) | |
201 return Promise.resolve(); | |
202 | |
203 var resolve; | |
204 var promise = new Promise(fulfill => resolve = fulfill); | |
205 this._node.domModel().querySelectorAll(ownerDocument.id, selectorTex
t, onQueryComplete.bind(this, node, selectorText, resolve)); | |
206 return promise; | |
207 } | |
208 | |
209 /** | |
210 * @param {!WebInspector.DOMNode} node | |
211 * @param {string} selectorText | |
212 * @param {function()} callback | |
213 * @param {!Array.<!DOMAgent.NodeId>=} matchingNodeIds | |
214 * @this {WebInspector.CSSMatchedStyles} | |
215 */ | |
216 function onQueryComplete(node, selectorText, callback, matchingNodeIds) | |
217 { | |
218 if (matchingNodeIds) | |
219 this._setSelectorMatches(node, selectorText, matchingNodeIds.ind
exOf(node.id) !== -1); | |
220 callback(); | |
221 } | |
222 }, | |
223 | |
224 /** | |
225 * @param {!WebInspector.CSSStyleRule} rule | |
226 * @param {!WebInspector.DOMNode} node | |
227 * @return {!Promise} | |
228 */ | |
229 addNewRule: function(rule, node) | |
230 { | |
231 this._nodeForStyle.set(rule.style, node); | |
232 return this.recomputeMatchingSelectors(rule); | |
233 }, | |
234 | 193 |
235 /** | 194 /** |
236 * @param {!WebInspector.DOMNode} node | 195 * @param {!WebInspector.DOMNode} node |
237 * @param {string} selectorText | 196 * @param {string} selectorText |
238 * @param {boolean} value | 197 * @return {!Promise} |
| 198 * @this {WebInspector.CSSMatchedStyles} |
239 */ | 199 */ |
240 _setSelectorMatches: function(node, selectorText, value) | 200 function querySelector(node, selectorText) { |
241 { | 201 var ownerDocument = node.ownerDocument || null; |
242 var map = this._matchingSelectors.get(node.id); | 202 // We assume that "matching" property does not ever change during the |
243 if (!map) { | 203 // MatchedStyleResult's lifetime. |
244 map = new Map(); | 204 var map = this._matchingSelectors.get(node.id); |
245 this._matchingSelectors.set(node.id, map); | 205 if ((map && map.has(selectorText)) || !ownerDocument) |
246 } | 206 return Promise.resolve(); |
247 map.set(selectorText, value); | 207 |
248 }, | 208 var resolve; |
| 209 var promise = new Promise(fulfill => resolve = fulfill); |
| 210 this._node.domModel().querySelectorAll( |
| 211 ownerDocument.id, selectorText, onQueryComplete.bind(this, node, selec
torText, resolve)); |
| 212 return promise; |
| 213 } |
249 | 214 |
250 /** | 215 /** |
251 * @param {!WebInspector.CSSStyleDeclaration} style | 216 * @param {!WebInspector.DOMNode} node |
252 * @return {boolean} | 217 * @param {string} selectorText |
| 218 * @param {function()} callback |
| 219 * @param {!Array.<!DOMAgent.NodeId>=} matchingNodeIds |
| 220 * @this {WebInspector.CSSMatchedStyles} |
253 */ | 221 */ |
254 mediaMatches: function(style) | 222 function onQueryComplete(node, selectorText, callback, matchingNodeIds) { |
255 { | 223 if (matchingNodeIds) |
256 var media = style.parentRule ? style.parentRule.media : []; | 224 this._setSelectorMatches(node, selectorText, matchingNodeIds.indexOf(nod
e.id) !== -1); |
257 for (var i = 0; media && i < media.length; ++i) { | 225 callback(); |
258 if (!media[i].active()) | 226 } |
259 return false; | 227 } |
260 } | 228 |
| 229 /** |
| 230 * @param {!WebInspector.CSSStyleRule} rule |
| 231 * @param {!WebInspector.DOMNode} node |
| 232 * @return {!Promise} |
| 233 */ |
| 234 addNewRule(rule, node) { |
| 235 this._nodeForStyle.set(rule.style, node); |
| 236 return this.recomputeMatchingSelectors(rule); |
| 237 } |
| 238 |
| 239 /** |
| 240 * @param {!WebInspector.DOMNode} node |
| 241 * @param {string} selectorText |
| 242 * @param {boolean} value |
| 243 */ |
| 244 _setSelectorMatches(node, selectorText, value) { |
| 245 var map = this._matchingSelectors.get(node.id); |
| 246 if (!map) { |
| 247 map = new Map(); |
| 248 this._matchingSelectors.set(node.id, map); |
| 249 } |
| 250 map.set(selectorText, value); |
| 251 } |
| 252 |
| 253 /** |
| 254 * @param {!WebInspector.CSSStyleDeclaration} style |
| 255 * @return {boolean} |
| 256 */ |
| 257 mediaMatches(style) { |
| 258 var media = style.parentRule ? style.parentRule.media : []; |
| 259 for (var i = 0; media && i < media.length; ++i) { |
| 260 if (!media[i].active()) |
| 261 return false; |
| 262 } |
| 263 return true; |
| 264 } |
| 265 |
| 266 /** |
| 267 * @return {!Array<!WebInspector.CSSStyleDeclaration>} |
| 268 */ |
| 269 nodeStyles() { |
| 270 return this._nodeStyles; |
| 271 } |
| 272 |
| 273 /** |
| 274 * @return {!Array.<!WebInspector.CSSKeyframesRule>} |
| 275 */ |
| 276 keyframes() { |
| 277 return this._keyframes; |
| 278 } |
| 279 |
| 280 /** |
| 281 * @return {!Map.<!DOMAgent.PseudoType, !Array<!WebInspector.CSSStyleDeclarati
on>>} |
| 282 */ |
| 283 pseudoStyles() { |
| 284 return this._pseudoStyles; |
| 285 } |
| 286 |
| 287 /** |
| 288 * @param {!WebInspector.CSSStyleDeclaration} style |
| 289 * @return {boolean} |
| 290 */ |
| 291 _containsInherited(style) { |
| 292 var properties = style.allProperties; |
| 293 for (var i = 0; i < properties.length; ++i) { |
| 294 var property = properties[i]; |
| 295 // Does this style contain non-overridden inherited property? |
| 296 if (property.activeInStyle() && WebInspector.cssMetadata().isPropertyInher
ited(property.name)) |
261 return true; | 297 return true; |
262 }, | 298 } |
263 | 299 return false; |
264 /** | 300 } |
265 * @return {!Array<!WebInspector.CSSStyleDeclaration>} | 301 |
266 */ | 302 /** |
267 nodeStyles: function() | 303 * @param {!WebInspector.CSSStyleDeclaration} style |
268 { | 304 * @return {?WebInspector.DOMNode} |
269 return this._nodeStyles; | 305 */ |
270 }, | 306 nodeForStyle(style) { |
271 | 307 return this._nodeForStyle.get(style) || null; |
272 /** | 308 } |
273 * @return {!Array.<!WebInspector.CSSKeyframesRule>} | 309 |
274 */ | 310 /** |
275 keyframes: function() | 311 * @param {!WebInspector.CSSStyleDeclaration} style |
276 { | 312 * @return {boolean} |
277 return this._keyframes; | 313 */ |
278 }, | 314 isInherited(style) { |
279 | 315 return this._inheritedStyles.has(style); |
280 /** | 316 } |
281 * @return {!Map.<!DOMAgent.PseudoType, !Array<!WebInspector.CSSStyleDeclara
tion>>} | 317 |
282 */ | 318 /** |
283 pseudoStyles: function() | 319 * @param {!WebInspector.CSSProperty} property |
284 { | 320 * @return {?WebInspector.CSSMatchedStyles.PropertyState} |
285 return this._pseudoStyles; | 321 */ |
286 }, | 322 propertyState(property) { |
287 | 323 if (this._propertiesState.size === 0) { |
288 /** | 324 this._computeActiveProperties(this._nodeStyles, this._propertiesState); |
289 * @param {!WebInspector.CSSStyleDeclaration} style | 325 for (var pseudoElementStyles of this._pseudoStyles.valuesArray()) |
290 * @return {boolean} | 326 this._computeActiveProperties(pseudoElementStyles, this._propertiesState
); |
291 */ | 327 } |
292 _containsInherited: function(style) | 328 return this._propertiesState.get(property) || null; |
293 { | 329 } |
294 var properties = style.allProperties; | 330 |
295 for (var i = 0; i < properties.length; ++i) { | 331 resetActiveProperties() { |
296 var property = properties[i]; | 332 /** @type {!Map<!WebInspector.CSSProperty, !WebInspector.CSSMatchedStyles.Pr
opertyState>} */ |
297 // Does this style contain non-overridden inherited property? | 333 this._propertiesState = new Map(); |
298 if (property.activeInStyle() && WebInspector.cssMetadata().isPropert
yInherited(property.name)) | 334 } |
299 return true; | 335 |
300 } | 336 /** |
301 return false; | 337 * @param {!Array<!WebInspector.CSSStyleDeclaration>} styles |
302 }, | 338 * @param {!Map<!WebInspector.CSSProperty, !WebInspector.CSSMatchedStyles.Prop
ertyState>} result |
303 | 339 */ |
304 /** | 340 _computeActiveProperties(styles, result) { |
305 * @param {!WebInspector.CSSStyleDeclaration} style | 341 /** @type {!Set.<string>} */ |
306 * @return {?WebInspector.DOMNode} | 342 var foundImportantProperties = new Set(); |
307 */ | 343 /** @type {!Map.<string, !Map<string, !WebInspector.CSSProperty>>} */ |
308 nodeForStyle: function(style) | 344 var propertyToEffectiveRule = new Map(); |
309 { | 345 /** @type {!Map.<string, !WebInspector.DOMNode>} */ |
310 return this._nodeForStyle.get(style) || null; | 346 var inheritedPropertyToNode = new Map(); |
311 }, | 347 /** @type {!Set<string>} */ |
312 | 348 var allUsedProperties = new Set(); |
313 /** | 349 for (var i = 0; i < styles.length; ++i) { |
314 * @param {!WebInspector.CSSStyleDeclaration} style | 350 var style = styles[i]; |
315 * @return {boolean} | 351 var rule = style.parentRule; |
316 */ | 352 // Compute cascade for CSSStyleRules only. |
317 isInherited: function(style) | 353 if (rule && !(rule instanceof WebInspector.CSSStyleRule)) |
318 { | 354 continue; |
319 return this._inheritedStyles.has(style); | 355 if (rule && !this.hasMatchingSelectors(rule)) |
320 }, | 356 continue; |
321 | 357 |
322 /** | 358 /** @type {!Map<string, !WebInspector.CSSProperty>} */ |
323 * @param {!WebInspector.CSSProperty} property | 359 var styleActiveProperties = new Map(); |
324 * @return {?WebInspector.CSSMatchedStyles.PropertyState} | 360 var allProperties = style.allProperties; |
325 */ | 361 for (var j = 0; j < allProperties.length; ++j) { |
326 propertyState: function(property) | 362 var property = allProperties[j]; |
327 { | 363 |
328 if (this._propertiesState.size === 0) { | 364 // Do not pick non-inherited properties from inherited styles. |
329 this._computeActiveProperties(this._nodeStyles, this._propertiesStat
e); | 365 var inherited = this.isInherited(style); |
330 for (var pseudoElementStyles of this._pseudoStyles.valuesArray()) | 366 if (inherited && !WebInspector.cssMetadata().isPropertyInherited(propert
y.name)) |
331 this._computeActiveProperties(pseudoElementStyles, this._propert
iesState); | 367 continue; |
332 } | 368 |
333 return this._propertiesState.get(property) || null; | 369 if (!property.activeInStyle()) { |
334 }, | 370 result.set(property, WebInspector.CSSMatchedStyles.PropertyState.Overl
oaded); |
335 | 371 continue; |
336 resetActiveProperties: function() | 372 } |
337 { | 373 |
338 /** @type {!Map<!WebInspector.CSSProperty, !WebInspector.CSSMatchedStyle
s.PropertyState>} */ | 374 var canonicalName = WebInspector.cssMetadata().canonicalPropertyName(pro
perty.name); |
339 this._propertiesState = new Map(); | 375 if (foundImportantProperties.has(canonicalName)) { |
340 }, | 376 result.set(property, WebInspector.CSSMatchedStyles.PropertyState.Overl
oaded); |
341 | 377 continue; |
342 /** | 378 } |
343 * @param {!Array<!WebInspector.CSSStyleDeclaration>} styles | 379 |
344 * @param {!Map<!WebInspector.CSSProperty, !WebInspector.CSSMatchedStyles.Pr
opertyState>} result | 380 if (!property.important && allUsedProperties.has(canonicalName)) { |
345 */ | 381 result.set(property, WebInspector.CSSMatchedStyles.PropertyState.Overl
oaded); |
346 _computeActiveProperties: function(styles, result) | 382 continue; |
347 { | 383 } |
348 /** @type {!Set.<string>} */ | 384 |
349 var foundImportantProperties = new Set(); | 385 var isKnownProperty = propertyToEffectiveRule.has(canonicalName); |
350 /** @type {!Map.<string, !Map<string, !WebInspector.CSSProperty>>} */ | 386 var inheritedFromNode = inherited ? this.nodeForStyle(style) : null; |
351 var propertyToEffectiveRule = new Map(); | 387 if (!isKnownProperty && inheritedFromNode && !inheritedPropertyToNode.ha
s(canonicalName)) |
352 /** @type {!Map.<string, !WebInspector.DOMNode>} */ | 388 inheritedPropertyToNode.set(canonicalName, inheritedFromNode); |
353 var inheritedPropertyToNode = new Map(); | 389 |
354 /** @type {!Set<string>} */ | 390 if (property.important) { |
355 var allUsedProperties = new Set(); | 391 if (inherited && isKnownProperty && inheritedFromNode !== inheritedPro
pertyToNode.get(canonicalName)) { |
356 for (var i = 0; i < styles.length; ++i) { | 392 result.set(property, WebInspector.CSSMatchedStyles.PropertyState.Ove
rloaded); |
357 var style = styles[i]; | 393 continue; |
358 var rule = style.parentRule; | 394 } |
359 // Compute cascade for CSSStyleRules only. | 395 |
360 if (rule && !(rule instanceof WebInspector.CSSStyleRule)) | 396 foundImportantProperties.add(canonicalName); |
361 continue; | 397 if (isKnownProperty) { |
362 if (rule && !this.hasMatchingSelectors(rule)) | 398 var overloaded = /** @type {!WebInspector.CSSProperty} */ ( |
363 continue; | 399 propertyToEffectiveRule.get(canonicalName).get(canonicalName)); |
364 | 400 result.set(overloaded, WebInspector.CSSMatchedStyles.PropertyState.O
verloaded); |
365 /** @type {!Map<string, !WebInspector.CSSProperty>} */ | 401 propertyToEffectiveRule.get(canonicalName).delete(canonicalName); |
366 var styleActiveProperties = new Map(); | 402 } |
367 var allProperties = style.allProperties; | 403 } |
368 for (var j = 0; j < allProperties.length; ++j) { | 404 |
369 var property = allProperties[j]; | 405 styleActiveProperties.set(canonicalName, property); |
370 | 406 allUsedProperties.add(canonicalName); |
371 // Do not pick non-inherited properties from inherited styles. | 407 propertyToEffectiveRule.set(canonicalName, styleActiveProperties); |
372 var inherited = this.isInherited(style); | 408 result.set(property, WebInspector.CSSMatchedStyles.PropertyState.Active)
; |
373 if (inherited && !WebInspector.cssMetadata().isPropertyInherited
(property.name)) | 409 } |
374 continue; | 410 |
375 | 411 // If every longhand of the shorthand is not active, then the shorthand is
not active too. |
376 if (!property.activeInStyle()) { | 412 for (var property of style.leadingProperties()) { |
377 result.set(property, WebInspector.CSSMatchedStyles.PropertyS
tate.Overloaded); | 413 var canonicalName = WebInspector.cssMetadata().canonicalPropertyName(pro
perty.name); |
378 continue; | 414 if (!styleActiveProperties.has(canonicalName)) |
379 } | 415 continue; |
380 | 416 var longhands = style.longhandProperties(property.name); |
381 var canonicalName = WebInspector.cssMetadata().canonicalProperty
Name(property.name); | 417 if (!longhands.length) |
382 if (foundImportantProperties.has(canonicalName)) { | 418 continue; |
383 result.set(property, WebInspector.CSSMatchedStyles.PropertyS
tate.Overloaded); | 419 var notUsed = true; |
384 continue; | 420 for (var longhand of longhands) { |
385 } | 421 var longhandCanonicalName = WebInspector.cssMetadata().canonicalProper
tyName(longhand.name); |
386 | 422 notUsed = notUsed && !styleActiveProperties.has(longhandCanonicalName)
; |
387 if (!property.important && allUsedProperties.has(canonicalName))
{ | 423 } |
388 result.set(property, WebInspector.CSSMatchedStyles.PropertyS
tate.Overloaded); | 424 if (!notUsed) |
389 continue; | 425 continue; |
390 } | 426 styleActiveProperties.delete(canonicalName); |
391 | 427 allUsedProperties.delete(canonicalName); |
392 var isKnownProperty = propertyToEffectiveRule.has(canonicalName)
; | 428 result.set(property, WebInspector.CSSMatchedStyles.PropertyState.Overloa
ded); |
393 var inheritedFromNode = inherited ? this.nodeForStyle(style) : n
ull; | 429 } |
394 if (!isKnownProperty && inheritedFromNode && !inheritedPropertyT
oNode.has(canonicalName)) | 430 } |
395 inheritedPropertyToNode.set(canonicalName, inheritedFromNode
); | 431 } |
396 | |
397 if (property.important) { | |
398 if (inherited && isKnownProperty && inheritedFromNode !== in
heritedPropertyToNode.get(canonicalName)) { | |
399 result.set(property, WebInspector.CSSMatchedStyles.Prope
rtyState.Overloaded); | |
400 continue; | |
401 } | |
402 | |
403 foundImportantProperties.add(canonicalName); | |
404 if (isKnownProperty) { | |
405 var overloaded = /** @type {!WebInspector.CSSProperty} *
/(propertyToEffectiveRule.get(canonicalName).get(canonicalName)); | |
406 result.set(overloaded, WebInspector.CSSMatchedStyles.Pro
pertyState.Overloaded); | |
407 propertyToEffectiveRule.get(canonicalName).delete(canoni
calName); | |
408 } | |
409 } | |
410 | |
411 styleActiveProperties.set(canonicalName, property); | |
412 allUsedProperties.add(canonicalName); | |
413 propertyToEffectiveRule.set(canonicalName, styleActiveProperties
); | |
414 result.set(property, WebInspector.CSSMatchedStyles.PropertyState
.Active); | |
415 } | |
416 | |
417 // If every longhand of the shorthand is not active, then the shorth
and is not active too. | |
418 for (var property of style.leadingProperties()) { | |
419 var canonicalName = WebInspector.cssMetadata().canonicalProperty
Name(property.name); | |
420 if (!styleActiveProperties.has(canonicalName)) | |
421 continue; | |
422 var longhands = style.longhandProperties(property.name); | |
423 if (!longhands.length) | |
424 continue; | |
425 var notUsed = true; | |
426 for (var longhand of longhands) { | |
427 var longhandCanonicalName = WebInspector.cssMetadata().canon
icalPropertyName(longhand.name); | |
428 notUsed = notUsed && !styleActiveProperties.has(longhandCano
nicalName); | |
429 } | |
430 if (!notUsed) | |
431 continue; | |
432 styleActiveProperties.delete(canonicalName); | |
433 allUsedProperties.delete(canonicalName); | |
434 result.set(property, WebInspector.CSSMatchedStyles.PropertyState
.Overloaded); | |
435 } | |
436 } | |
437 } | |
438 }; | 432 }; |
439 | 433 |
440 /** @enum {string} */ | 434 /** @enum {string} */ |
441 WebInspector.CSSMatchedStyles.PropertyState = { | 435 WebInspector.CSSMatchedStyles.PropertyState = { |
442 Active: "Active", | 436 Active: 'Active', |
443 Overloaded: "Overloaded" | 437 Overloaded: 'Overloaded' |
444 }; | 438 }; |
OLD | NEW |