OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) | 3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) |
4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) | 4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) |
5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc.
All rights reserved. | 5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc.
All rights reserved. |
6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> | 6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> |
7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org> | 7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org> |
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t
orchmobile.com/) | 8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t
orchmobile.com/) |
9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. | 9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. |
10 * Copyright (C) Research In Motion Limited 2011. All rights reserved. | 10 * Copyright (C) Research In Motion Limited 2011. All rights reserved. |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 , m_canUseFastReject(m_selectorFilter.parentStackIsConsistent(context.parent
Node())) | 54 , m_canUseFastReject(m_selectorFilter.parentStackIsConsistent(context.parent
Node())) |
55 , m_sameOriginOnly(false) | 55 , m_sameOriginOnly(false) |
56 , m_matchingUARules(false) | 56 , m_matchingUARules(false) |
57 , m_scopeContainsLastMatchedElement(false) | 57 , m_scopeContainsLastMatchedElement(false) |
58 { } | 58 { } |
59 | 59 |
60 ElementRuleCollector::~ElementRuleCollector() | 60 ElementRuleCollector::~ElementRuleCollector() |
61 { | 61 { |
62 } | 62 } |
63 | 63 |
64 MatchResult& ElementRuleCollector::matchedResult() | 64 const MatchResult& ElementRuleCollector::matchedResult() |
65 { | 65 { |
66 return m_result; | 66 return m_result; |
67 } | 67 } |
68 | 68 |
69 PassRefPtrWillBeRawPtr<StyleRuleList> ElementRuleCollector::matchedStyleRuleList
() | 69 PassRefPtrWillBeRawPtr<StyleRuleList> ElementRuleCollector::matchedStyleRuleList
() |
70 { | 70 { |
71 ASSERT(m_mode == SelectorChecker::CollectingStyleRules); | 71 ASSERT(m_mode == SelectorChecker::CollectingStyleRules); |
72 return m_styleRuleList.release(); | 72 return m_styleRuleList.release(); |
73 } | 73 } |
74 | 74 |
(...skipping 19 matching lines...) Expand all Loading... |
94 { | 94 { |
95 if (!m_cssRuleList) | 95 if (!m_cssRuleList) |
96 m_cssRuleList = StaticCSSRuleList::create(); | 96 m_cssRuleList = StaticCSSRuleList::create(); |
97 return m_cssRuleList.get(); | 97 return m_cssRuleList.get(); |
98 } | 98 } |
99 | 99 |
100 void ElementRuleCollector::addElementStyleProperties(const StylePropertySet* pro
pertySet, bool isCacheable) | 100 void ElementRuleCollector::addElementStyleProperties(const StylePropertySet* pro
pertySet, bool isCacheable) |
101 { | 101 { |
102 if (!propertySet) | 102 if (!propertySet) |
103 return; | 103 return; |
104 m_result.ranges.lastAuthorRule = m_result.matchedProperties.size(); | |
105 if (m_result.ranges.firstAuthorRule == -1) | |
106 m_result.ranges.firstAuthorRule = m_result.ranges.lastAuthorRule; | |
107 m_result.addMatchedProperties(propertySet); | 104 m_result.addMatchedProperties(propertySet); |
108 if (!isCacheable) | 105 if (!isCacheable) |
109 m_result.isCacheable = false; | 106 m_result.isCacheable = false; |
110 } | 107 } |
111 | 108 |
112 static bool rulesApplicableInCurrentTreeScope(const Element* element, const Cont
ainerNode* scopingNode, bool matchingTreeBoundaryRules) | 109 static bool rulesApplicableInCurrentTreeScope(const Element* element, const Cont
ainerNode* scopingNode, bool matchingTreeBoundaryRules) |
113 { | 110 { |
114 // [skipped, because already checked] a) it's a UA rule | 111 // [skipped, because already checked] a) it's a UA rule |
115 // b) We're mathcing tree boundary rules. | 112 // b) We're mathcing tree boundary rules. |
116 if (matchingTreeBoundaryRules) | 113 if (matchingTreeBoundaryRules) |
117 return true; | 114 return true; |
118 // c) the rules comes from a scoped style sheet within the same tree scope | 115 // c) the rules comes from a scoped style sheet within the same tree scope |
119 if (!scopingNode || element->treeScope() == scopingNode->treeScope()) | 116 if (!scopingNode || element->treeScope() == scopingNode->treeScope()) |
120 return true; | 117 return true; |
121 // d) the rules comes from a scoped style sheet within an active shadow root
whose host is the given element | 118 // d) the rules comes from a scoped style sheet within an active shadow root
whose host is the given element |
122 if (element == scopingNode->shadowHost()) | 119 if (element == scopingNode->shadowHost()) |
123 return true; | 120 return true; |
124 return false; | 121 return false; |
125 } | 122 } |
126 | 123 |
127 template<typename RuleDataListType> | 124 template<typename RuleDataListType> |
128 void ElementRuleCollector::collectMatchingRulesForList(const RuleDataListType* r
ules, CascadeOrder cascadeOrder, const MatchRequest& matchRequest, RuleRange& ru
leRange) | 125 void ElementRuleCollector::collectMatchingRulesForList(const RuleDataListType* r
ules, CascadeOrder cascadeOrder, const MatchRequest& matchRequest) |
129 { | 126 { |
130 if (!rules) | 127 if (!rules) |
131 return; | 128 return; |
132 | 129 |
133 SelectorChecker checker(m_mode); | 130 SelectorChecker checker(m_mode); |
134 SelectorChecker::SelectorCheckingContext checkerContext(m_context.element(),
SelectorChecker::VisitedMatchEnabled); | 131 SelectorChecker::SelectorCheckingContext checkerContext(m_context.element(),
SelectorChecker::VisitedMatchEnabled); |
135 checkerContext.elementStyle = m_style.get(); | 132 checkerContext.elementStyle = m_style.get(); |
136 checkerContext.scope = matchRequest.scope; | 133 checkerContext.scope = matchRequest.scope; |
137 checkerContext.pseudoId = m_pseudoStyleRequest.pseudoId; | 134 checkerContext.pseudoId = m_pseudoStyleRequest.pseudoId; |
138 checkerContext.scrollbar = m_pseudoStyleRequest.scrollbar; | 135 checkerContext.scrollbar = m_pseudoStyleRequest.scrollbar; |
(...skipping 16 matching lines...) Expand all Loading... |
155 if (properties.isEmpty() && !matchRequest.includeEmptyRules) | 152 if (properties.isEmpty() && !matchRequest.includeEmptyRules) |
156 continue; | 153 continue; |
157 | 154 |
158 SelectorChecker::MatchResult result; | 155 SelectorChecker::MatchResult result; |
159 checkerContext.selector = &ruleData.selector(); | 156 checkerContext.selector = &ruleData.selector(); |
160 if (!checker.match(checkerContext, result)) | 157 if (!checker.match(checkerContext, result)) |
161 continue; | 158 continue; |
162 if (m_pseudoStyleRequest.pseudoId != NOPSEUDO && m_pseudoStyleRequest.ps
eudoId != result.dynamicPseudo) | 159 if (m_pseudoStyleRequest.pseudoId != NOPSEUDO && m_pseudoStyleRequest.ps
eudoId != result.dynamicPseudo) |
163 continue; | 160 continue; |
164 | 161 |
165 didMatchRule(ruleData, result, cascadeOrder, matchRequest, ruleRange); | 162 didMatchRule(ruleData, result, cascadeOrder, matchRequest); |
166 } | 163 } |
167 } | 164 } |
168 | 165 |
169 void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest
, RuleRange& ruleRange, CascadeOrder cascadeOrder, bool matchingTreeBoundaryRule
s) | 166 void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest
, CascadeOrder cascadeOrder, bool matchingTreeBoundaryRules) |
170 { | 167 { |
171 ASSERT(matchRequest.ruleSet); | 168 ASSERT(matchRequest.ruleSet); |
172 ASSERT(m_context.element()); | 169 ASSERT(m_context.element()); |
173 | 170 |
174 Element& element = *m_context.element(); | 171 Element& element = *m_context.element(); |
175 const AtomicString& pseudoId = element.shadowPseudoId(); | 172 const AtomicString& pseudoId = element.shadowPseudoId(); |
176 if (!pseudoId.isEmpty()) { | 173 if (!pseudoId.isEmpty()) { |
177 ASSERT(element.isStyledElement()); | 174 ASSERT(element.isStyledElement()); |
178 collectMatchingRulesForList(matchRequest.ruleSet->shadowPseudoElementRul
es(pseudoId), cascadeOrder, matchRequest, ruleRange); | 175 collectMatchingRulesForList(matchRequest.ruleSet->shadowPseudoElementRul
es(pseudoId), cascadeOrder, matchRequest); |
179 } | 176 } |
180 | 177 |
181 if (element.isVTTElement()) | 178 if (element.isVTTElement()) |
182 collectMatchingRulesForList(matchRequest.ruleSet->cuePseudoRules(), casc
adeOrder, matchRequest, ruleRange); | 179 collectMatchingRulesForList(matchRequest.ruleSet->cuePseudoRules(), casc
adeOrder, matchRequest); |
183 // Check whether other types of rules are applicable in the current tree sco
pe. Criteria for this: | 180 // Check whether other types of rules are applicable in the current tree sco
pe. Criteria for this: |
184 // a) it's a UA rule | 181 // a) it's a UA rule |
185 // b) the rules comes from a scoped style sheet within the same tree scope | 182 // b) the rules comes from a scoped style sheet within the same tree scope |
186 // c) the rules comes from a scoped style sheet within an active shadow root
whose host is the given element | 183 // c) the rules comes from a scoped style sheet within an active shadow root
whose host is the given element |
187 // d) the rules can cross boundaries | 184 // d) the rules can cross boundaries |
188 // b)-e) is checked in rulesApplicableInCurrentTreeScope. | 185 // b)-e) is checked in rulesApplicableInCurrentTreeScope. |
189 if (!m_matchingUARules && !rulesApplicableInCurrentTreeScope(&element, match
Request.scope, matchingTreeBoundaryRules)) | 186 if (!m_matchingUARules && !rulesApplicableInCurrentTreeScope(&element, match
Request.scope, matchingTreeBoundaryRules)) |
190 return; | 187 return; |
191 | 188 |
192 // We need to collect the rules for id, class, tag, and everything else into
a buffer and | 189 // We need to collect the rules for id, class, tag, and everything else into
a buffer and |
193 // then sort the buffer. | 190 // then sort the buffer. |
194 if (element.hasID()) | 191 if (element.hasID()) |
195 collectMatchingRulesForList(matchRequest.ruleSet->idRules(element.idForS
tyleResolution()), cascadeOrder, matchRequest, ruleRange); | 192 collectMatchingRulesForList(matchRequest.ruleSet->idRules(element.idForS
tyleResolution()), cascadeOrder, matchRequest); |
196 if (element.isStyledElement() && element.hasClass()) { | 193 if (element.isStyledElement() && element.hasClass()) { |
197 for (size_t i = 0; i < element.classNames().size(); ++i) | 194 for (size_t i = 0; i < element.classNames().size(); ++i) |
198 collectMatchingRulesForList(matchRequest.ruleSet->classRules(element
.classNames()[i]), cascadeOrder, matchRequest, ruleRange); | 195 collectMatchingRulesForList(matchRequest.ruleSet->classRules(element
.classNames()[i]), cascadeOrder, matchRequest); |
199 } | 196 } |
200 | 197 |
201 if (element.isLink()) | 198 if (element.isLink()) |
202 collectMatchingRulesForList(matchRequest.ruleSet->linkPseudoClassRules()
, cascadeOrder, matchRequest, ruleRange); | 199 collectMatchingRulesForList(matchRequest.ruleSet->linkPseudoClassRules()
, cascadeOrder, matchRequest); |
203 if (SelectorChecker::matchesFocusPseudoClass(element)) | 200 if (SelectorChecker::matchesFocusPseudoClass(element)) |
204 collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(
), cascadeOrder, matchRequest, ruleRange); | 201 collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(
), cascadeOrder, matchRequest); |
205 collectMatchingRulesForList(matchRequest.ruleSet->tagRules(element.localName
ForSelectorMatching()), cascadeOrder, matchRequest, ruleRange); | 202 collectMatchingRulesForList(matchRequest.ruleSet->tagRules(element.localName
ForSelectorMatching()), cascadeOrder, matchRequest); |
206 collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), cascadeO
rder, matchRequest, ruleRange); | 203 collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), cascadeO
rder, matchRequest); |
207 } | 204 } |
208 | 205 |
209 void ElementRuleCollector::collectMatchingShadowHostRules(const MatchRequest& ma
tchRequest, RuleRange& ruleRange, CascadeOrder cascadeOrder, bool matchingTreeBo
undaryRules) | 206 void ElementRuleCollector::collectMatchingShadowHostRules(const MatchRequest& ma
tchRequest, CascadeOrder cascadeOrder, bool matchingTreeBoundaryRules) |
210 { | 207 { |
211 collectMatchingRulesForList(matchRequest.ruleSet->shadowHostRules(), cascade
Order, matchRequest, ruleRange); | 208 collectMatchingRulesForList(matchRequest.ruleSet->shadowHostRules(), cascade
Order, matchRequest); |
212 } | 209 } |
213 | 210 |
214 template<class CSSRuleCollection> | 211 template<class CSSRuleCollection> |
215 CSSRule* ElementRuleCollector::findStyleRule(CSSRuleCollection* cssRules, StyleR
ule* styleRule) | 212 CSSRule* ElementRuleCollector::findStyleRule(CSSRuleCollection* cssRules, StyleR
ule* styleRule) |
216 { | 213 { |
217 if (!cssRules) | 214 if (!cssRules) |
218 return 0; | 215 return 0; |
219 CSSRule* result = 0; | 216 CSSRule* result = 0; |
220 for (unsigned i = 0; i < cssRules->length() && !result; ++i) { | 217 for (unsigned i = 0; i < cssRules->length() && !result; ++i) { |
221 CSSRule* cssRule = cssRules->item(i); | 218 CSSRule* cssRule = cssRules->item(i); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 for (unsigned i = 0; i < m_matchedRules.size(); ++i) | 262 for (unsigned i = 0; i < m_matchedRules.size(); ++i) |
266 appendCSSOMWrapperForRule(const_cast<CSSStyleSheet*>(m_matchedRules[
i].parentStyleSheet()), m_matchedRules[i].ruleData()->rule()); | 263 appendCSSOMWrapperForRule(const_cast<CSSStyleSheet*>(m_matchedRules[
i].parentStyleSheet()), m_matchedRules[i].ruleData()->rule()); |
267 return; | 264 return; |
268 } | 265 } |
269 | 266 |
270 // Now transfer the set of matched rules over to our list of declarations. | 267 // Now transfer the set of matched rules over to our list of declarations. |
271 for (unsigned i = 0; i < m_matchedRules.size(); i++) { | 268 for (unsigned i = 0; i < m_matchedRules.size(); i++) { |
272 const RuleData* ruleData = m_matchedRules[i].ruleData(); | 269 const RuleData* ruleData = m_matchedRules[i].ruleData(); |
273 m_result.addMatchedProperties(&ruleData->rule()->properties(), ruleData-
>linkMatchType(), ruleData->propertyWhitelistType(m_matchingUARules)); | 270 m_result.addMatchedProperties(&ruleData->rule()->properties(), ruleData-
>linkMatchType(), ruleData->propertyWhitelistType(m_matchingUARules)); |
274 } | 271 } |
| 272 |
| 273 if (m_matchingUARules) |
| 274 m_result.lastUARuleIndex = m_result.matchedProperties.size() - 1; |
275 } | 275 } |
276 | 276 |
277 void ElementRuleCollector::didMatchRule(const RuleData& ruleData, const Selector
Checker::MatchResult& result, CascadeOrder cascadeOrder, const MatchRequest& mat
chRequest, RuleRange& ruleRange) | 277 void ElementRuleCollector::didMatchRule(const RuleData& ruleData, const Selector
Checker::MatchResult& result, CascadeOrder cascadeOrder, const MatchRequest& mat
chRequest) |
278 { | 278 { |
279 PseudoId dynamicPseudo = result.dynamicPseudo; | 279 PseudoId dynamicPseudo = result.dynamicPseudo; |
280 // If we're matching normal rules, set a pseudo bit if | 280 // If we're matching normal rules, set a pseudo bit if |
281 // we really just matched a pseudo-element. | 281 // we really just matched a pseudo-element. |
282 if (dynamicPseudo != NOPSEUDO && m_pseudoStyleRequest.pseudoId == NOPSEUDO)
{ | 282 if (dynamicPseudo != NOPSEUDO && m_pseudoStyleRequest.pseudoId == NOPSEUDO)
{ |
283 if (m_mode == SelectorChecker::CollectingCSSRules || m_mode == SelectorC
hecker::CollectingStyleRules) | 283 if (m_mode == SelectorChecker::CollectingCSSRules || m_mode == SelectorC
hecker::CollectingStyleRules) |
284 return; | 284 return; |
285 // FIXME: Matching should not modify the style directly. | 285 // FIXME: Matching should not modify the style directly. |
286 if (!m_style || dynamicPseudo >= FIRST_INTERNAL_PSEUDOID) | 286 if (!m_style || dynamicPseudo >= FIRST_INTERNAL_PSEUDOID) |
287 return; | 287 return; |
288 if ((dynamicPseudo == BEFORE || dynamicPseudo == AFTER) && !ruleData.rul
e()->properties().hasProperty(CSSPropertyContent)) | 288 if ((dynamicPseudo == BEFORE || dynamicPseudo == AFTER) && !ruleData.rul
e()->properties().hasProperty(CSSPropertyContent)) |
289 return; | 289 return; |
290 m_style->setHasPseudoStyle(dynamicPseudo); | 290 m_style->setHasPseudoStyle(dynamicPseudo); |
291 } else { | 291 } else { |
292 // Update our first/last rule indices in the matched rules array. | |
293 ++ruleRange.lastRuleIndex; | |
294 if (ruleRange.firstRuleIndex == -1) | |
295 ruleRange.firstRuleIndex = ruleRange.lastRuleIndex; | |
296 | |
297 if (m_style && ruleData.containsUncommonAttributeSelector()) | 292 if (m_style && ruleData.containsUncommonAttributeSelector()) |
298 m_style->setUnique(); | 293 m_style->setUnique(); |
299 | 294 |
300 m_matchedRules.append(MatchedRule(&ruleData, result.specificity, cascade
Order, matchRequest.styleSheetIndex, matchRequest.styleSheet)); | 295 m_matchedRules.append(MatchedRule(&ruleData, result.specificity, cascade
Order, matchRequest.styleSheetIndex, matchRequest.styleSheet)); |
301 } | 296 } |
302 } | 297 } |
303 | 298 |
304 static inline bool compareRules(const MatchedRule& matchedRule1, const MatchedRu
le& matchedRule2) | 299 static inline bool compareRules(const MatchedRule& matchedRule1, const MatchedRu
le& matchedRule2) |
305 { | 300 { |
306 unsigned specificity1 = matchedRule1.specificity(); | 301 unsigned specificity1 = matchedRule1.specificity(); |
(...skipping 10 matching lines...) Expand all Loading... |
317 } | 312 } |
318 | 313 |
319 bool ElementRuleCollector::hasAnyMatchingRules(RuleSet* ruleSet) | 314 bool ElementRuleCollector::hasAnyMatchingRules(RuleSet* ruleSet) |
320 { | 315 { |
321 clearMatchedRules(); | 316 clearMatchedRules(); |
322 | 317 |
323 m_mode = SelectorChecker::SharingRules; | 318 m_mode = SelectorChecker::SharingRules; |
324 // To check whether a given RuleSet has any rule matching a given element, | 319 // To check whether a given RuleSet has any rule matching a given element, |
325 // should not see the element's treescope. Because RuleSet has no | 320 // should not see the element's treescope. Because RuleSet has no |
326 // information about "scope". | 321 // information about "scope". |
327 int firstRuleIndex = -1, lastRuleIndex = -1; | |
328 RuleRange ruleRange(firstRuleIndex, lastRuleIndex); | |
329 MatchRequest matchRequest(ruleSet); | 322 MatchRequest matchRequest(ruleSet); |
330 collectMatchingRules(matchRequest, ruleRange); | 323 collectMatchingRules(matchRequest); |
331 collectMatchingShadowHostRules(matchRequest, ruleRange); | 324 collectMatchingShadowHostRules(matchRequest); |
332 | 325 |
333 return !m_matchedRules.isEmpty(); | 326 return !m_matchedRules.isEmpty(); |
334 } | 327 } |
335 | 328 |
336 } // namespace blink | 329 } // namespace blink |
OLD | NEW |