| 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 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 return true; | 153 return true; |
| 154 return context.element->isLink(); | 154 return context.element->isLink(); |
| 155 } | 155 } |
| 156 | 156 |
| 157 // Recursive check of selectors and combinators | 157 // Recursive check of selectors and combinators |
| 158 // It can return 4 different values: | 158 // It can return 4 different values: |
| 159 // * SelectorMatches - the selector matches the element e | 159 // * SelectorMatches - the selector matches the element e |
| 160 // * SelectorFailsLocally - the selector fails for the element e | 160 // * SelectorFailsLocally - the selector fails for the element e |
| 161 // * SelectorFailsAllSiblings - the selector fails for e and any sibling of e | 161 // * SelectorFailsAllSiblings - the selector fails for e and any sibling of e |
| 162 // * SelectorFailsCompletely - the selector fails for e and any sibling or ance
stor of e | 162 // * SelectorFailsCompletely - the selector fails for e and any sibling or ance
stor of e |
| 163 template<typename SiblingTraversalStrategy> | 163 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext& con
text, MatchResult* result) const |
| 164 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext& con
text, const SiblingTraversalStrategy& siblingTraversalStrategy, MatchResult* res
ult) const | |
| 165 { | 164 { |
| 166 // first selector has to match | 165 // first selector has to match |
| 167 unsigned specificity = 0; | 166 unsigned specificity = 0; |
| 168 if (!checkOne(context, siblingTraversalStrategy, &specificity)) | 167 if (!checkOne(context, &specificity)) |
| 169 return SelectorFailsLocally; | 168 return SelectorFailsLocally; |
| 170 | 169 |
| 171 if (context.selector->match() == CSSSelector::PseudoElement) { | 170 if (context.selector->match() == CSSSelector::PseudoElement) { |
| 172 if (context.selector->isCustomPseudoElement()) { | 171 if (context.selector->isCustomPseudoElement()) { |
| 173 if (!matchesCustomPseudoElement(context.element, *context.selector)) | 172 if (!matchesCustomPseudoElement(context.element, *context.selector)) |
| 174 return SelectorFailsLocally; | 173 return SelectorFailsLocally; |
| 175 } else if (context.selector->isContentPseudoElement()) { | 174 } else if (context.selector->isContentPseudoElement()) { |
| 176 if (!context.element->isInShadowTree() || !context.element->isInsert
ionPoint()) | 175 if (!context.element->isInShadowTree() || !context.element->isInsert
ionPoint()) |
| 177 return SelectorFailsLocally; | 176 return SelectorFailsLocally; |
| 178 } else if (context.selector->isShadowPseudoElement()) { | 177 } else if (context.selector->isShadowPseudoElement()) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 205 // Abort if the next selector would exceed the scope. | 204 // Abort if the next selector would exceed the scope. |
| 206 if (nextSelectorExceedsScope(context)) | 205 if (nextSelectorExceedsScope(context)) |
| 207 return SelectorFailsCompletely; | 206 return SelectorFailsCompletely; |
| 208 | 207 |
| 209 // Bail-out if this selector is irrelevant for the pseudoId | 208 // Bail-out if this selector is irrelevant for the pseudoId |
| 210 if (context.pseudoId != NOPSEUDO && (!result || context.pseudoId != resu
lt->dynamicPseudo)) | 209 if (context.pseudoId != NOPSEUDO && (!result || context.pseudoId != resu
lt->dynamicPseudo)) |
| 211 return SelectorFailsCompletely; | 210 return SelectorFailsCompletely; |
| 212 | 211 |
| 213 if (result) { | 212 if (result) { |
| 214 TemporaryChange<PseudoId> dynamicPseudoScope(result->dynamicPseudo,
NOPSEUDO); | 213 TemporaryChange<PseudoId> dynamicPseudoScope(result->dynamicPseudo,
NOPSEUDO); |
| 215 match = matchForRelation(context, siblingTraversalStrategy, result); | 214 match = matchForRelation(context, result); |
| 216 } else { | 215 } else { |
| 217 return matchForRelation(context, siblingTraversalStrategy, 0); | 216 return matchForRelation(context, 0); |
| 218 } | 217 } |
| 219 } else { | 218 } else { |
| 220 match = matchForSubSelector(context, siblingTraversalStrategy, result); | 219 match = matchForSubSelector(context, result); |
| 221 } | 220 } |
| 222 if (match != SelectorMatches || !result) | 221 if (match != SelectorMatches || !result) |
| 223 return match; | 222 return match; |
| 224 | 223 |
| 225 result->specificity += specificity; | 224 result->specificity += specificity; |
| 226 return SelectorMatches; | 225 return SelectorMatches; |
| 227 } | 226 } |
| 228 | 227 |
| 229 static inline SelectorChecker::SelectorCheckingContext prepareNextContextForRela
tion(const SelectorChecker::SelectorCheckingContext& context) | 228 static inline SelectorChecker::SelectorCheckingContext prepareNextContextForRela
tion(const SelectorChecker::SelectorCheckingContext& context) |
| 230 { | 229 { |
| 231 SelectorChecker::SelectorCheckingContext nextContext(context); | 230 SelectorChecker::SelectorCheckingContext nextContext(context); |
| 232 ASSERT(context.selector->tagHistory()); | 231 ASSERT(context.selector->tagHistory()); |
| 233 nextContext.selector = context.selector->tagHistory(); | 232 nextContext.selector = context.selector->tagHistory(); |
| 234 return nextContext; | 233 return nextContext; |
| 235 } | 234 } |
| 236 | 235 |
| 237 static inline bool isOpenShadowRoot(const Node* node) | 236 static inline bool isOpenShadowRoot(const Node* node) |
| 238 { | 237 { |
| 239 return node && node->isShadowRoot() && toShadowRoot(node)->type() == ShadowR
oot::OpenShadowRoot; | 238 return node && node->isShadowRoot() && toShadowRoot(node)->type() == ShadowR
oot::OpenShadowRoot; |
| 240 } | 239 } |
| 241 | 240 |
| 242 template<typename SiblingTraversalStrategy> | 241 SelectorChecker::Match SelectorChecker::matchForSubSelector(const SelectorChecki
ngContext& context, MatchResult* result) const |
| 243 SelectorChecker::Match SelectorChecker::matchForSubSelector(const SelectorChecki
ngContext& context, const SiblingTraversalStrategy& siblingTraversalStrategy, Ma
tchResult* result) const | |
| 244 { | 242 { |
| 245 SelectorCheckingContext nextContext = prepareNextContextForRelation(context)
; | 243 SelectorCheckingContext nextContext = prepareNextContextForRelation(context)
; |
| 246 | 244 |
| 247 PseudoId dynamicPseudo = result ? result->dynamicPseudo : NOPSEUDO; | 245 PseudoId dynamicPseudo = result ? result->dynamicPseudo : NOPSEUDO; |
| 248 // a selector is invalid if something follows a pseudo-element | 246 // a selector is invalid if something follows a pseudo-element |
| 249 // We make an exception for scrollbar pseudo elements and allow a set of pse
udo classes (but nothing else) | 247 // We make an exception for scrollbar pseudo elements and allow a set of pse
udo classes (but nothing else) |
| 250 // to follow the pseudo elements. | 248 // to follow the pseudo elements. |
| 251 nextContext.hasScrollbarPseudo = dynamicPseudo != NOPSEUDO && (context.scrol
lbar || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER); | 249 nextContext.hasScrollbarPseudo = dynamicPseudo != NOPSEUDO && (context.scrol
lbar || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER); |
| 252 nextContext.hasSelectionPseudo = dynamicPseudo == SELECTION; | 250 nextContext.hasSelectionPseudo = dynamicPseudo == SELECTION; |
| 253 if ((context.elementStyle || m_mode == CollectingCSSRules || m_mode == Colle
ctingStyleRules || m_mode == QueryingRules) && dynamicPseudo != NOPSEUDO | 251 if ((context.elementStyle || m_mode == CollectingCSSRules || m_mode == Colle
ctingStyleRules || m_mode == QueryingRules) && dynamicPseudo != NOPSEUDO |
| 254 && !nextContext.hasSelectionPseudo | 252 && !nextContext.hasSelectionPseudo |
| 255 && !(nextContext.hasScrollbarPseudo && nextContext.selector->match() ==
CSSSelector::PseudoClass)) | 253 && !(nextContext.hasScrollbarPseudo && nextContext.selector->match() ==
CSSSelector::PseudoClass)) |
| 256 return SelectorFailsCompletely; | 254 return SelectorFailsCompletely; |
| 257 | 255 |
| 258 nextContext.isSubSelector = true; | 256 nextContext.isSubSelector = true; |
| 259 return match(nextContext, siblingTraversalStrategy, result); | 257 return match(nextContext, result); |
| 260 } | 258 } |
| 261 | 259 |
| 262 static bool selectorMatchesShadowRoot(const CSSSelector* selector) | 260 static bool selectorMatchesShadowRoot(const CSSSelector* selector) |
| 263 { | 261 { |
| 264 return selector && selector->isShadowPseudoElement(); | 262 return selector && selector->isShadowPseudoElement(); |
| 265 } | 263 } |
| 266 | 264 |
| 267 static inline Element* parentOrShadowHostButDisallowEscapingUserAgentShadowTree(
const Element& element) | 265 static inline Element* parentOrShadowHostButDisallowEscapingUserAgentShadowTree(
const Element& element) |
| 268 { | 266 { |
| 269 ContainerNode* parent = element.parentOrShadowHostNode(); | 267 ContainerNode* parent = element.parentOrShadowHostNode(); |
| 270 if (!parent) | 268 if (!parent) |
| 271 return nullptr; | 269 return nullptr; |
| 272 if (parent->isShadowRoot()) | 270 if (parent->isShadowRoot()) |
| 273 return (toShadowRoot(parent)->type() == ShadowRoot::UserAgentShadowRoot)
? nullptr : toShadowRoot(parent)->host(); | 271 return (toShadowRoot(parent)->type() == ShadowRoot::UserAgentShadowRoot)
? nullptr : toShadowRoot(parent)->host(); |
| 274 if (!parent->isElementNode()) | 272 if (!parent->isElementNode()) |
| 275 return nullptr; | 273 return nullptr; |
| 276 return toElement(parent); | 274 return toElement(parent); |
| 277 } | 275 } |
| 278 | 276 |
| 279 template<typename SiblingTraversalStrategy> | 277 SelectorChecker::Match SelectorChecker::matchForPseudoShadow(const ContainerNode
* node, const SelectorCheckingContext& context, MatchResult* result) const |
| 280 SelectorChecker::Match SelectorChecker::matchForPseudoShadow(const ContainerNode
* node, const SelectorCheckingContext& context, const SiblingTraversalStrategy&
siblingTraversalStrategy, MatchResult* result) const | |
| 281 { | 278 { |
| 282 if (!isOpenShadowRoot(node)) | 279 if (!isOpenShadowRoot(node)) |
| 283 return SelectorFailsCompletely; | 280 return SelectorFailsCompletely; |
| 284 return match(context, siblingTraversalStrategy, result); | 281 return match(context, result); |
| 285 } | 282 } |
| 286 | 283 |
| 287 template<typename SiblingTraversalStrategy> | 284 SelectorChecker::Match SelectorChecker::matchForRelation(const SelectorCheckingC
ontext& context, MatchResult* result) const |
| 288 SelectorChecker::Match SelectorChecker::matchForRelation(const SelectorCheckingC
ontext& context, const SiblingTraversalStrategy& siblingTraversalStrategy, Match
Result* result) const | |
| 289 { | 285 { |
| 290 SelectorCheckingContext nextContext = prepareNextContextForRelation(context)
; | 286 SelectorCheckingContext nextContext = prepareNextContextForRelation(context)
; |
| 291 nextContext.previousElement = context.element; | 287 nextContext.previousElement = context.element; |
| 292 | 288 |
| 293 CSSSelector::Relation relation = context.selector->relation(); | 289 CSSSelector::Relation relation = context.selector->relation(); |
| 294 | 290 |
| 295 // Disable :visited matching when we see the first link or try to match anyt
hing else than an ancestors. | 291 // Disable :visited matching when we see the first link or try to match anyt
hing else than an ancestors. |
| 296 if (!context.isSubSelector && (context.element->isLink() || (relation != CSS
Selector::Descendant && relation != CSSSelector::Child))) | 292 if (!context.isSubSelector && (context.element->isLink() || (relation != CSS
Selector::Descendant && relation != CSSSelector::Child))) |
| 297 nextContext.visitedMatchType = VisitedMatchDisabled; | 293 nextContext.visitedMatchType = VisitedMatchDisabled; |
| 298 | 294 |
| 299 nextContext.pseudoId = NOPSEUDO; | 295 nextContext.pseudoId = NOPSEUDO; |
| 300 | 296 |
| 301 switch (relation) { | 297 switch (relation) { |
| 302 case CSSSelector::Descendant: | 298 case CSSSelector::Descendant: |
| 303 if (context.selector->relationIsAffectedByPseudoContent()) { | 299 if (context.selector->relationIsAffectedByPseudoContent()) { |
| 304 for (Element* element = context.element; element; element = element-
>parentElement()) { | 300 for (Element* element = context.element; element; element = element-
>parentElement()) { |
| 305 if (matchForShadowDistributed(element, siblingTraversalStrategy,
nextContext, result) == SelectorMatches) | 301 if (matchForShadowDistributed(element, nextContext, result) == S
electorMatches) |
| 306 return SelectorMatches; | 302 return SelectorMatches; |
| 307 } | 303 } |
| 308 return SelectorFailsCompletely; | 304 return SelectorFailsCompletely; |
| 309 } | 305 } |
| 310 nextContext.isSubSelector = false; | 306 nextContext.isSubSelector = false; |
| 311 nextContext.elementStyle = 0; | 307 nextContext.elementStyle = 0; |
| 312 | 308 |
| 313 if (selectorMatchesShadowRoot(nextContext.selector)) | 309 if (selectorMatchesShadowRoot(nextContext.selector)) |
| 314 return matchForPseudoShadow(context.element->containingShadowRoot(),
nextContext, siblingTraversalStrategy, result); | 310 return matchForPseudoShadow(context.element->containingShadowRoot(),
nextContext, result); |
| 315 | 311 |
| 316 for (nextContext.element = parentElement(context); nextContext.element;
nextContext.element = parentElement(nextContext)) { | 312 for (nextContext.element = parentElement(context); nextContext.element;
nextContext.element = parentElement(nextContext)) { |
| 317 Match match = this->match(nextContext, siblingTraversalStrategy, res
ult); | 313 Match match = this->match(nextContext, result); |
| 318 if (match == SelectorMatches || match == SelectorFailsCompletely) | 314 if (match == SelectorMatches || match == SelectorFailsCompletely) |
| 319 return match; | 315 return match; |
| 320 if (nextSelectorExceedsScope(nextContext)) | 316 if (nextSelectorExceedsScope(nextContext)) |
| 321 return SelectorFailsCompletely; | 317 return SelectorFailsCompletely; |
| 322 } | 318 } |
| 323 return SelectorFailsCompletely; | 319 return SelectorFailsCompletely; |
| 324 case CSSSelector::Child: | 320 case CSSSelector::Child: |
| 325 { | 321 { |
| 326 if (context.selector->relationIsAffectedByPseudoContent()) | 322 if (context.selector->relationIsAffectedByPseudoContent()) |
| 327 return matchForShadowDistributed(context.element, siblingTravers
alStrategy, nextContext, result); | 323 return matchForShadowDistributed(context.element, nextContext, r
esult); |
| 328 | 324 |
| 329 nextContext.isSubSelector = false; | 325 nextContext.isSubSelector = false; |
| 330 nextContext.elementStyle = 0; | 326 nextContext.elementStyle = 0; |
| 331 | 327 |
| 332 if (selectorMatchesShadowRoot(nextContext.selector)) | 328 if (selectorMatchesShadowRoot(nextContext.selector)) |
| 333 return matchForPseudoShadow(context.element->parentNode(), nextC
ontext, siblingTraversalStrategy, result); | 329 return matchForPseudoShadow(context.element->parentNode(), nextC
ontext, result); |
| 334 | 330 |
| 335 nextContext.element = parentElement(context); | 331 nextContext.element = parentElement(context); |
| 336 if (!nextContext.element) | 332 if (!nextContext.element) |
| 337 return SelectorFailsCompletely; | 333 return SelectorFailsCompletely; |
| 338 return match(nextContext, siblingTraversalStrategy, result); | 334 return match(nextContext, result); |
| 339 } | 335 } |
| 340 case CSSSelector::DirectAdjacent: | 336 case CSSSelector::DirectAdjacent: |
| 341 // Shadow roots can't have sibling elements | 337 // Shadow roots can't have sibling elements |
| 342 if (selectorMatchesShadowRoot(nextContext.selector)) | 338 if (selectorMatchesShadowRoot(nextContext.selector)) |
| 343 return SelectorFailsCompletely; | 339 return SelectorFailsCompletely; |
| 344 | 340 |
| 345 if (m_mode == ResolvingStyle) { | 341 if (m_mode == ResolvingStyle) { |
| 346 if (ContainerNode* parent = context.element->parentElementOrShadowRo
ot()) | 342 if (ContainerNode* parent = context.element->parentElementOrShadowRo
ot()) |
| 347 parent->setChildrenAffectedByDirectAdjacentRules(); | 343 parent->setChildrenAffectedByDirectAdjacentRules(); |
| 348 } | 344 } |
| 349 nextContext.element = ElementTraversal::previousSibling(*context.element
); | 345 nextContext.element = ElementTraversal::previousSibling(*context.element
); |
| 350 if (!nextContext.element) | 346 if (!nextContext.element) |
| 351 return SelectorFailsAllSiblings; | 347 return SelectorFailsAllSiblings; |
| 352 nextContext.isSubSelector = false; | 348 nextContext.isSubSelector = false; |
| 353 nextContext.elementStyle = 0; | 349 nextContext.elementStyle = 0; |
| 354 return match(nextContext, siblingTraversalStrategy, result); | 350 return match(nextContext, result); |
| 355 | 351 |
| 356 case CSSSelector::IndirectAdjacent: | 352 case CSSSelector::IndirectAdjacent: |
| 357 // Shadow roots can't have sibling elements | 353 // Shadow roots can't have sibling elements |
| 358 if (selectorMatchesShadowRoot(nextContext.selector)) | 354 if (selectorMatchesShadowRoot(nextContext.selector)) |
| 359 return SelectorFailsCompletely; | 355 return SelectorFailsCompletely; |
| 360 | 356 |
| 361 if (m_mode == ResolvingStyle) { | 357 if (m_mode == ResolvingStyle) { |
| 362 if (ContainerNode* parent = context.element->parentElementOrShadowRo
ot()) | 358 if (ContainerNode* parent = context.element->parentElementOrShadowRo
ot()) |
| 363 parent->setChildrenAffectedByIndirectAdjacentRules(); | 359 parent->setChildrenAffectedByIndirectAdjacentRules(); |
| 364 } | 360 } |
| 365 nextContext.element = ElementTraversal::previousSibling(*context.element
); | 361 nextContext.element = ElementTraversal::previousSibling(*context.element
); |
| 366 nextContext.isSubSelector = false; | 362 nextContext.isSubSelector = false; |
| 367 nextContext.elementStyle = 0; | 363 nextContext.elementStyle = 0; |
| 368 for (; nextContext.element; nextContext.element = ElementTraversal::prev
iousSibling(*nextContext.element)) { | 364 for (; nextContext.element; nextContext.element = ElementTraversal::prev
iousSibling(*nextContext.element)) { |
| 369 Match match = this->match(nextContext, siblingTraversalStrategy, res
ult); | 365 Match match = this->match(nextContext, result); |
| 370 if (match == SelectorMatches || match == SelectorFailsAllSiblings ||
match == SelectorFailsCompletely) | 366 if (match == SelectorMatches || match == SelectorFailsAllSiblings ||
match == SelectorFailsCompletely) |
| 371 return match; | 367 return match; |
| 372 }; | 368 }; |
| 373 return SelectorFailsAllSiblings; | 369 return SelectorFailsAllSiblings; |
| 374 | 370 |
| 375 case CSSSelector::ShadowPseudo: | 371 case CSSSelector::ShadowPseudo: |
| 376 { | 372 { |
| 377 // If we're in the same tree-scope as the scoping element, then foll
owing a shadow descendant combinator would escape that and thus the scope. | 373 // If we're in the same tree-scope as the scoping element, then foll
owing a shadow descendant combinator would escape that and thus the scope. |
| 378 if (context.scope && context.scope->shadowHost() && context.scope->s
hadowHost()->treeScope() == context.element->treeScope()) | 374 if (context.scope && context.scope->shadowHost() && context.scope->s
hadowHost()->treeScope() == context.element->treeScope()) |
| 379 return SelectorFailsCompletely; | 375 return SelectorFailsCompletely; |
| 380 | 376 |
| 381 Element* shadowHost = context.element->shadowHost(); | 377 Element* shadowHost = context.element->shadowHost(); |
| 382 if (!shadowHost) | 378 if (!shadowHost) |
| 383 return SelectorFailsCompletely; | 379 return SelectorFailsCompletely; |
| 384 nextContext.element = shadowHost; | 380 nextContext.element = shadowHost; |
| 385 nextContext.isSubSelector = false; | 381 nextContext.isSubSelector = false; |
| 386 nextContext.elementStyle = 0; | 382 nextContext.elementStyle = 0; |
| 387 return this->match(nextContext, siblingTraversalStrategy, result); | 383 return this->match(nextContext, result); |
| 388 } | 384 } |
| 389 | 385 |
| 390 case CSSSelector::ShadowDeep: | 386 case CSSSelector::ShadowDeep: |
| 391 { | 387 { |
| 392 if (context.selector->relationIsAffectedByPseudoContent()) { | 388 if (context.selector->relationIsAffectedByPseudoContent()) { |
| 393 for (Element* element = context.element; element; element = pare
ntOrShadowHostButDisallowEscapingUserAgentShadowTree(*element)) { | 389 for (Element* element = context.element; element; element = pare
ntOrShadowHostButDisallowEscapingUserAgentShadowTree(*element)) { |
| 394 if (matchForShadowDistributed(element, siblingTraversalStrat
egy, nextContext, result) == SelectorMatches) | 390 if (matchForShadowDistributed(element, nextContext, result)
== SelectorMatches) |
| 395 return SelectorMatches; | 391 return SelectorMatches; |
| 396 } | 392 } |
| 397 return SelectorFailsCompletely; | 393 return SelectorFailsCompletely; |
| 398 } | 394 } |
| 399 | 395 |
| 400 nextContext.isSubSelector = false; | 396 nextContext.isSubSelector = false; |
| 401 nextContext.elementStyle = 0; | 397 nextContext.elementStyle = 0; |
| 402 for (nextContext.element = parentOrShadowHostButDisallowEscapingUser
AgentShadowTree(*context.element); nextContext.element; nextContext.element = pa
rentOrShadowHostButDisallowEscapingUserAgentShadowTree(*nextContext.element)) { | 398 for (nextContext.element = parentOrShadowHostButDisallowEscapingUser
AgentShadowTree(*context.element); nextContext.element; nextContext.element = pa
rentOrShadowHostButDisallowEscapingUserAgentShadowTree(*nextContext.element)) { |
| 403 Match match = this->match(nextContext, siblingTraversalStrategy,
result); | 399 Match match = this->match(nextContext, result); |
| 404 if (match == SelectorMatches || match == SelectorFailsCompletely
) | 400 if (match == SelectorMatches || match == SelectorFailsCompletely
) |
| 405 return match; | 401 return match; |
| 406 if (nextSelectorExceedsScope(nextContext)) | 402 if (nextSelectorExceedsScope(nextContext)) |
| 407 return SelectorFailsCompletely; | 403 return SelectorFailsCompletely; |
| 408 } | 404 } |
| 409 return SelectorFailsCompletely; | 405 return SelectorFailsCompletely; |
| 410 } | 406 } |
| 411 | 407 |
| 412 case CSSSelector::SubSelector: | 408 case CSSSelector::SubSelector: |
| 413 ASSERT_NOT_REACHED(); | 409 ASSERT_NOT_REACHED(); |
| 414 } | 410 } |
| 415 | 411 |
| 416 ASSERT_NOT_REACHED(); | 412 ASSERT_NOT_REACHED(); |
| 417 return SelectorFailsCompletely; | 413 return SelectorFailsCompletely; |
| 418 } | 414 } |
| 419 | 415 |
| 420 template<typename SiblingTraversalStrategy> | 416 SelectorChecker::Match SelectorChecker::matchForShadowDistributed(const Element*
element, SelectorCheckingContext& nextContext, MatchResult* result) const |
| 421 SelectorChecker::Match SelectorChecker::matchForShadowDistributed(const Element*
element, const SiblingTraversalStrategy& siblingTraversalStrategy, SelectorChec
kingContext& nextContext, MatchResult* result) const | |
| 422 { | 417 { |
| 423 ASSERT(element); | 418 ASSERT(element); |
| 424 WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints; | 419 WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints; |
| 425 collectDestinationInsertionPoints(*element, insertionPoints); | 420 collectDestinationInsertionPoints(*element, insertionPoints); |
| 426 for (size_t i = 0; i < insertionPoints.size(); ++i) { | 421 for (size_t i = 0; i < insertionPoints.size(); ++i) { |
| 427 nextContext.element = insertionPoints[i]; | 422 nextContext.element = insertionPoints[i]; |
| 428 if (m_mode == SharingRules) | 423 if (m_mode == SharingRules) |
| 429 nextContext.scope = insertionPoints[i]->containingShadowRoot(); | 424 nextContext.scope = insertionPoints[i]->containingShadowRoot(); |
| 430 nextContext.isSubSelector = false; | 425 nextContext.isSubSelector = false; |
| 431 nextContext.elementStyle = 0; | 426 nextContext.elementStyle = 0; |
| 432 if (match(nextContext, siblingTraversalStrategy, result) == SelectorMatc
hes) | 427 if (match(nextContext, result) == SelectorMatches) |
| 433 return SelectorMatches; | 428 return SelectorMatches; |
| 434 } | 429 } |
| 435 return SelectorFailsLocally; | 430 return SelectorFailsLocally; |
| 436 } | 431 } |
| 437 | 432 |
| 438 template<typename CharType> | 433 template<typename CharType> |
| 439 static inline bool containsHTMLSpaceTemplate(const CharType* string, unsigned le
ngth) | 434 static inline bool containsHTMLSpaceTemplate(const CharType* string, unsigned le
ngth) |
| 440 { | 435 { |
| 441 for (unsigned i = 0; i < length; ++i) | 436 for (unsigned i = 0; i < length; ++i) |
| 442 if (isHTMLSpace<CharType>(string[i])) | 437 if (isHTMLSpace<CharType>(string[i])) |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 551 UseCounter::count(element.document(), UseCounter::CaseInsensitiveAtt
rSelectorMatch); | 546 UseCounter::count(element.document(), UseCounter::CaseInsensitiveAtt
rSelectorMatch); |
| 552 return true; | 547 return true; |
| 553 } | 548 } |
| 554 if (selectorAttr.namespaceURI() != starAtom) | 549 if (selectorAttr.namespaceURI() != starAtom) |
| 555 return false; | 550 return false; |
| 556 } | 551 } |
| 557 | 552 |
| 558 return false; | 553 return false; |
| 559 } | 554 } |
| 560 | 555 |
| 561 template<typename SiblingTraversalStrategy> | 556 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, unsigned*
specificity) const |
| 562 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
lingTraversalStrategy& siblingTraversalStrategy, unsigned* specificity) const | |
| 563 { | 557 { |
| 564 ASSERT(context.element); | 558 ASSERT(context.element); |
| 565 Element& element = *context.element; | 559 Element& element = *context.element; |
| 566 ASSERT(context.selector); | 560 ASSERT(context.selector); |
| 567 const CSSSelector& selector = *context.selector; | 561 const CSSSelector& selector = *context.selector; |
| 568 | 562 |
| 569 // Only :host and :host-context() should match the host: http://drafts.csswg
.org/css-scoping/#host-element | 563 // Only :host and :host-context() should match the host: http://drafts.csswg
.org/css-scoping/#host-element |
| 570 if (context.scope && context.scope->shadowHost() == element && (!selector.is
HostPseudoClass() | 564 if (context.scope && context.scope->shadowHost() == element && (!selector.is
HostPseudoClass() |
| 571 && !context.treatShadowHostAsNormalScope | 565 && !context.treatShadowHostAsNormalScope |
| 572 && selector.match() != CSSSelector::PseudoElement)) | 566 && selector.match() != CSSSelector::PseudoElement)) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 584 case CSSSelector::AttributeExact: | 578 case CSSSelector::AttributeExact: |
| 585 case CSSSelector::AttributeSet: | 579 case CSSSelector::AttributeSet: |
| 586 case CSSSelector::AttributeHyphen: | 580 case CSSSelector::AttributeHyphen: |
| 587 case CSSSelector::AttributeList: | 581 case CSSSelector::AttributeList: |
| 588 case CSSSelector::AttributeContain: | 582 case CSSSelector::AttributeContain: |
| 589 case CSSSelector::AttributeBegin: | 583 case CSSSelector::AttributeBegin: |
| 590 case CSSSelector::AttributeEnd: | 584 case CSSSelector::AttributeEnd: |
| 591 return anyAttributeMatches(element, selector.match(), selector); | 585 return anyAttributeMatches(element, selector.match(), selector); |
| 592 | 586 |
| 593 case CSSSelector::PseudoClass: | 587 case CSSSelector::PseudoClass: |
| 594 return checkPseudoClass(context, siblingTraversalStrategy, specificity); | 588 return checkPseudoClass(context, specificity); |
| 595 case CSSSelector::PseudoElement: | 589 case CSSSelector::PseudoElement: |
| 596 return checkPseudoElement(context, siblingTraversalStrategy); | 590 return checkPseudoElement(context); |
| 597 | 591 |
| 598 case CSSSelector::PagePseudoClass: | 592 case CSSSelector::PagePseudoClass: |
| 599 // FIXME: what? | 593 // FIXME: what? |
| 600 return true; | 594 return true; |
| 601 case CSSSelector::Unknown: | 595 case CSSSelector::Unknown: |
| 602 // FIXME: what? | 596 // FIXME: what? |
| 603 return true; | 597 return true; |
| 604 } | 598 } |
| 605 ASSERT_NOT_REACHED(); | 599 ASSERT_NOT_REACHED(); |
| 606 return true; | 600 return true; |
| 607 } | 601 } |
| 608 | 602 |
| 609 template<typename SiblingTraversalStrategy> | 603 bool SelectorChecker::checkPseudoClass(const SelectorCheckingContext& context, u
nsigned* specificity) const |
| 610 bool SelectorChecker::checkPseudoClass(const SelectorCheckingContext& context, c
onst SiblingTraversalStrategy& siblingTraversalStrategy, unsigned* specificity)
const | |
| 611 { | 604 { |
| 612 Element& element = *context.element; | 605 Element& element = *context.element; |
| 613 const CSSSelector& selector = *context.selector; | 606 const CSSSelector& selector = *context.selector; |
| 614 | 607 |
| 615 // Handle :not up front. | 608 // Handle :not up front. |
| 616 if (selector.pseudoType() == CSSSelector::PseudoNot) { | 609 if (selector.pseudoType() == CSSSelector::PseudoNot) { |
| 617 SelectorCheckingContext subContext(context); | 610 SelectorCheckingContext subContext(context); |
| 618 subContext.isSubSelector = true; | 611 subContext.isSubSelector = true; |
| 619 ASSERT(selector.selectorList()); | 612 ASSERT(selector.selectorList()); |
| 620 for (subContext.selector = selector.selectorList()->first(); subContext.
selector; subContext.selector = subContext.selector->tagHistory()) { | 613 for (subContext.selector = selector.selectorList()->first(); subContext.
selector; subContext.selector = subContext.selector->tagHistory()) { |
| 621 // :not cannot nest. I don't really know why this is a | 614 // :not cannot nest. I don't really know why this is a |
| 622 // restriction in CSS3, but it is, so let's honor it. | 615 // restriction in CSS3, but it is, so let's honor it. |
| 623 // the parser enforces that this never occurs | 616 // the parser enforces that this never occurs |
| 624 ASSERT(subContext.selector->pseudoType() != CSSSelector::PseudoNot); | 617 ASSERT(subContext.selector->pseudoType() != CSSSelector::PseudoNot); |
| 625 // We select between :visited and :link when applying. We don't know
which one applied (or not) yet. | 618 // We select between :visited and :link when applying. We don't know
which one applied (or not) yet. |
| 626 if (subContext.selector->pseudoType() == CSSSelector::PseudoVisited
|| (subContext.selector->pseudoType() == CSSSelector::PseudoLink && subContext.v
isitedMatchType == VisitedMatchEnabled)) | 619 if (subContext.selector->pseudoType() == CSSSelector::PseudoVisited
|| (subContext.selector->pseudoType() == CSSSelector::PseudoLink && subContext.v
isitedMatchType == VisitedMatchEnabled)) |
| 627 return true; | 620 return true; |
| 628 // context.scope is not available if m_mode == SharingRules. | 621 // context.scope is not available if m_mode == SharingRules. |
| 629 // We cannot determine whether :host or :scope matches a given eleme
nt or not. | 622 // We cannot determine whether :host or :scope matches a given eleme
nt or not. |
| 630 if (m_mode == SharingRules && (subContext.selector->isHostPseudoClas
s() || subContext.selector->pseudoType() == CSSSelector::PseudoScope)) | 623 if (m_mode == SharingRules && (subContext.selector->isHostPseudoClas
s() || subContext.selector->pseudoType() == CSSSelector::PseudoScope)) |
| 631 return true; | 624 return true; |
| 632 if (!checkOne(subContext, siblingTraversalStrategy)) | 625 if (!checkOne(subContext)) |
| 633 return true; | 626 return true; |
| 634 } | 627 } |
| 635 return false; | 628 return false; |
| 636 } | 629 } |
| 637 | 630 |
| 638 if (context.hasScrollbarPseudo) { | 631 if (context.hasScrollbarPseudo) { |
| 639 // CSS scrollbars match a specific subset of pseudo classes, and they ha
ve specialized rules for each | 632 // CSS scrollbars match a specific subset of pseudo classes, and they ha
ve specialized rules for each |
| 640 // (since there are no elements involved). | 633 // (since there are no elements involved). |
| 641 return checkScrollbarPseudoClass(context, &element.document(), selector)
; | 634 return checkScrollbarPseudoClass(context, &element.document(), selector)
; |
| 642 } | 635 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 674 element.mutableComputedStyle()->setEmptyState(result); | 667 element.mutableComputedStyle()->setEmptyState(result); |
| 675 } | 668 } |
| 676 return result; | 669 return result; |
| 677 } | 670 } |
| 678 case CSSSelector::PseudoFirstChild: | 671 case CSSSelector::PseudoFirstChild: |
| 679 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { | 672 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { |
| 680 if (m_mode == ResolvingStyle) { | 673 if (m_mode == ResolvingStyle) { |
| 681 parent->setChildrenAffectedByFirstChildRules(); | 674 parent->setChildrenAffectedByFirstChildRules(); |
| 682 element.setAffectedByFirstChildRules(); | 675 element.setAffectedByFirstChildRules(); |
| 683 } | 676 } |
| 684 return siblingTraversalStrategy.isFirstChild(element); | 677 return DOMSiblingTraversalStrategy::isFirstChild(element); |
| 685 } | 678 } |
| 686 break; | 679 break; |
| 687 case CSSSelector::PseudoFirstOfType: | 680 case CSSSelector::PseudoFirstOfType: |
| 688 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { | 681 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { |
| 689 if (m_mode == ResolvingStyle) | 682 if (m_mode == ResolvingStyle) |
| 690 parent->setChildrenAffectedByForwardPositionalRules(); | 683 parent->setChildrenAffectedByForwardPositionalRules(); |
| 691 return siblingTraversalStrategy.isFirstOfType(element, element.tagQN
ame()); | 684 return DOMSiblingTraversalStrategy::isFirstOfType(element, element.t
agQName()); |
| 692 } | 685 } |
| 693 break; | 686 break; |
| 694 case CSSSelector::PseudoLastChild: | 687 case CSSSelector::PseudoLastChild: |
| 695 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { | 688 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { |
| 696 if (m_mode == ResolvingStyle) { | 689 if (m_mode == ResolvingStyle) { |
| 697 parent->setChildrenAffectedByLastChildRules(); | 690 parent->setChildrenAffectedByLastChildRules(); |
| 698 element.setAffectedByLastChildRules(); | 691 element.setAffectedByLastChildRules(); |
| 699 } | 692 } |
| 700 if (!parent->isFinishedParsingChildren()) | 693 if (!parent->isFinishedParsingChildren()) |
| 701 return false; | 694 return false; |
| 702 return siblingTraversalStrategy.isLastChild(element); | 695 return DOMSiblingTraversalStrategy::isLastChild(element); |
| 703 } | 696 } |
| 704 break; | 697 break; |
| 705 case CSSSelector::PseudoLastOfType: | 698 case CSSSelector::PseudoLastOfType: |
| 706 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { | 699 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { |
| 707 if (m_mode == ResolvingStyle) | 700 if (m_mode == ResolvingStyle) |
| 708 parent->setChildrenAffectedByBackwardPositionalRules(); | 701 parent->setChildrenAffectedByBackwardPositionalRules(); |
| 709 if (!parent->isFinishedParsingChildren()) | 702 if (!parent->isFinishedParsingChildren()) |
| 710 return false; | 703 return false; |
| 711 return siblingTraversalStrategy.isLastOfType(element, element.tagQNa
me()); | 704 return DOMSiblingTraversalStrategy::isLastOfType(element, element.ta
gQName()); |
| 712 } | 705 } |
| 713 break; | 706 break; |
| 714 case CSSSelector::PseudoOnlyChild: | 707 case CSSSelector::PseudoOnlyChild: |
| 715 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { | 708 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { |
| 716 if (m_mode == ResolvingStyle) { | 709 if (m_mode == ResolvingStyle) { |
| 717 parent->setChildrenAffectedByFirstChildRules(); | 710 parent->setChildrenAffectedByFirstChildRules(); |
| 718 parent->setChildrenAffectedByLastChildRules(); | 711 parent->setChildrenAffectedByLastChildRules(); |
| 719 element.setAffectedByFirstChildRules(); | 712 element.setAffectedByFirstChildRules(); |
| 720 element.setAffectedByLastChildRules(); | 713 element.setAffectedByLastChildRules(); |
| 721 } | 714 } |
| 722 if (!parent->isFinishedParsingChildren()) | 715 if (!parent->isFinishedParsingChildren()) |
| 723 return false; | 716 return false; |
| 724 return siblingTraversalStrategy.isFirstChild(element) && siblingTrav
ersalStrategy.isLastChild(element); | 717 return DOMSiblingTraversalStrategy::isFirstChild(element) && DOMSibl
ingTraversalStrategy::isLastChild(element); |
| 725 } | 718 } |
| 726 break; | 719 break; |
| 727 case CSSSelector::PseudoOnlyOfType: | 720 case CSSSelector::PseudoOnlyOfType: |
| 728 // FIXME: This selector is very slow. | 721 // FIXME: This selector is very slow. |
| 729 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { | 722 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { |
| 730 if (m_mode == ResolvingStyle) { | 723 if (m_mode == ResolvingStyle) { |
| 731 parent->setChildrenAffectedByForwardPositionalRules(); | 724 parent->setChildrenAffectedByForwardPositionalRules(); |
| 732 parent->setChildrenAffectedByBackwardPositionalRules(); | 725 parent->setChildrenAffectedByBackwardPositionalRules(); |
| 733 } | 726 } |
| 734 if (!parent->isFinishedParsingChildren()) | 727 if (!parent->isFinishedParsingChildren()) |
| 735 return false; | 728 return false; |
| 736 return siblingTraversalStrategy.isFirstOfType(element, element.tagQN
ame()) && siblingTraversalStrategy.isLastOfType(element, element.tagQName()); | 729 return DOMSiblingTraversalStrategy::isFirstOfType(element, element.t
agQName()) && DOMSiblingTraversalStrategy::isLastOfType(element, element.tagQNam
e()); |
| 737 } | 730 } |
| 738 break; | 731 break; |
| 739 case CSSSelector::PseudoNthChild: | 732 case CSSSelector::PseudoNthChild: |
| 740 if (!selector.parseNth()) | 733 if (!selector.parseNth()) |
| 741 break; | 734 break; |
| 742 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { | 735 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { |
| 743 if (m_mode == ResolvingStyle) | 736 if (m_mode == ResolvingStyle) |
| 744 parent->setChildrenAffectedByForwardPositionalRules(); | 737 parent->setChildrenAffectedByForwardPositionalRules(); |
| 745 return selector.matchNth(1 + siblingTraversalStrategy.countElementsB
efore(element)); | 738 return selector.matchNth(1 + DOMSiblingTraversalStrategy::countEleme
ntsBefore(element)); |
| 746 } | 739 } |
| 747 break; | 740 break; |
| 748 case CSSSelector::PseudoNthOfType: | 741 case CSSSelector::PseudoNthOfType: |
| 749 if (!selector.parseNth()) | 742 if (!selector.parseNth()) |
| 750 break; | 743 break; |
| 751 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { | 744 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { |
| 752 if (m_mode == ResolvingStyle) | 745 if (m_mode == ResolvingStyle) |
| 753 parent->setChildrenAffectedByForwardPositionalRules(); | 746 parent->setChildrenAffectedByForwardPositionalRules(); |
| 754 return selector.matchNth(1 + siblingTraversalStrategy.countElementsO
fTypeBefore(element, element.tagQName())); | 747 return selector.matchNth(1 + DOMSiblingTraversalStrategy::countEleme
ntsOfTypeBefore(element, element.tagQName())); |
| 755 } | 748 } |
| 756 break; | 749 break; |
| 757 case CSSSelector::PseudoNthLastChild: | 750 case CSSSelector::PseudoNthLastChild: |
| 758 if (!selector.parseNth()) | 751 if (!selector.parseNth()) |
| 759 break; | 752 break; |
| 760 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { | 753 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { |
| 761 if (m_mode == ResolvingStyle) | 754 if (m_mode == ResolvingStyle) |
| 762 parent->setChildrenAffectedByBackwardPositionalRules(); | 755 parent->setChildrenAffectedByBackwardPositionalRules(); |
| 763 if (!parent->isFinishedParsingChildren()) | 756 if (!parent->isFinishedParsingChildren()) |
| 764 return false; | 757 return false; |
| 765 return selector.matchNth(1 + siblingTraversalStrategy.countElementsA
fter(element)); | 758 return selector.matchNth(1 + DOMSiblingTraversalStrategy::countEleme
ntsAfter(element)); |
| 766 } | 759 } |
| 767 break; | 760 break; |
| 768 case CSSSelector::PseudoNthLastOfType: | 761 case CSSSelector::PseudoNthLastOfType: |
| 769 if (!selector.parseNth()) | 762 if (!selector.parseNth()) |
| 770 break; | 763 break; |
| 771 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { | 764 if (ContainerNode* parent = element.parentElementOrDocumentFragment()) { |
| 772 if (m_mode == ResolvingStyle) | 765 if (m_mode == ResolvingStyle) |
| 773 parent->setChildrenAffectedByBackwardPositionalRules(); | 766 parent->setChildrenAffectedByBackwardPositionalRules(); |
| 774 if (!parent->isFinishedParsingChildren()) | 767 if (!parent->isFinishedParsingChildren()) |
| 775 return false; | 768 return false; |
| 776 return selector.matchNth(1 + siblingTraversalStrategy.countElementsO
fTypeAfter(element, element.tagQName())); | 769 return selector.matchNth(1 + DOMSiblingTraversalStrategy::countEleme
ntsOfTypeAfter(element, element.tagQName())); |
| 777 } | 770 } |
| 778 break; | 771 break; |
| 779 case CSSSelector::PseudoTarget: | 772 case CSSSelector::PseudoTarget: |
| 780 return element == element.document().cssTarget(); | 773 return element == element.document().cssTarget(); |
| 781 case CSSSelector::PseudoAny: | 774 case CSSSelector::PseudoAny: |
| 782 { | 775 { |
| 783 SelectorCheckingContext subContext(context); | 776 SelectorCheckingContext subContext(context); |
| 784 subContext.isSubSelector = true; | 777 subContext.isSubSelector = true; |
| 785 ASSERT(selector.selectorList()); | 778 ASSERT(selector.selectorList()); |
| 786 for (subContext.selector = selector.selectorList()->first(); subCont
ext.selector; subContext.selector = CSSSelectorList::next(*subContext.selector))
{ | 779 for (subContext.selector = selector.selectorList()->first(); subCont
ext.selector; subContext.selector = CSSSelectorList::next(*subContext.selector))
{ |
| 787 if (match(subContext, siblingTraversalStrategy) == SelectorMatch
es) | 780 if (match(subContext) == SelectorMatches) |
| 788 return true; | 781 return true; |
| 789 } | 782 } |
| 790 } | 783 } |
| 791 break; | 784 break; |
| 792 case CSSSelector::PseudoAutofill: | 785 case CSSSelector::PseudoAutofill: |
| 793 return element.isFormControlElement() && toHTMLFormControlElement(elemen
t).isAutofilled(); | 786 return element.isFormControlElement() && toHTMLFormControlElement(elemen
t).isAutofilled(); |
| 794 case CSSSelector::PseudoAnyLink: | 787 case CSSSelector::PseudoAnyLink: |
| 795 case CSSSelector::PseudoLink: | 788 case CSSSelector::PseudoLink: |
| 796 return element.isLink(); | 789 return element.isLink(); |
| 797 case CSSSelector::PseudoVisited: | 790 case CSSSelector::PseudoVisited: |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 930 case CSSSelector::PseudoScope: | 923 case CSSSelector::PseudoScope: |
| 931 if (m_mode == SharingRules) | 924 if (m_mode == SharingRules) |
| 932 return true; | 925 return true; |
| 933 if (context.scope) | 926 if (context.scope) |
| 934 return context.scope == element; | 927 return context.scope == element; |
| 935 return element == element.document().documentElement(); | 928 return element == element.document().documentElement(); |
| 936 case CSSSelector::PseudoUnresolved: | 929 case CSSSelector::PseudoUnresolved: |
| 937 return element.isUnresolvedCustomElement(); | 930 return element.isUnresolvedCustomElement(); |
| 938 case CSSSelector::PseudoHost: | 931 case CSSSelector::PseudoHost: |
| 939 case CSSSelector::PseudoHostContext: | 932 case CSSSelector::PseudoHostContext: |
| 940 return checkPseudoHost(context, siblingTraversalStrategy, specificity); | 933 return checkPseudoHost(context, specificity); |
| 941 case CSSSelector::PseudoSpatialNavigationFocus: | 934 case CSSSelector::PseudoSpatialNavigationFocus: |
| 942 return context.isUARule && matchesSpatialNavigationFocusPseudoClass(elem
ent); | 935 return context.isUARule && matchesSpatialNavigationFocusPseudoClass(elem
ent); |
| 943 case CSSSelector::PseudoListBox: | 936 case CSSSelector::PseudoListBox: |
| 944 return context.isUARule && matchesListBoxPseudoClass(element); | 937 return context.isUARule && matchesListBoxPseudoClass(element); |
| 945 case CSSSelector::PseudoHorizontal: | 938 case CSSSelector::PseudoHorizontal: |
| 946 case CSSSelector::PseudoVertical: | 939 case CSSSelector::PseudoVertical: |
| 947 case CSSSelector::PseudoDecrement: | 940 case CSSSelector::PseudoDecrement: |
| 948 case CSSSelector::PseudoIncrement: | 941 case CSSSelector::PseudoIncrement: |
| 949 case CSSSelector::PseudoStart: | 942 case CSSSelector::PseudoStart: |
| 950 case CSSSelector::PseudoEnd: | 943 case CSSSelector::PseudoEnd: |
| 951 case CSSSelector::PseudoDoubleButton: | 944 case CSSSelector::PseudoDoubleButton: |
| 952 case CSSSelector::PseudoSingleButton: | 945 case CSSSelector::PseudoSingleButton: |
| 953 case CSSSelector::PseudoNoButton: | 946 case CSSSelector::PseudoNoButton: |
| 954 case CSSSelector::PseudoCornerPresent: | 947 case CSSSelector::PseudoCornerPresent: |
| 955 case CSSSelector::PseudoWindowInactive: | 948 case CSSSelector::PseudoWindowInactive: |
| 956 return false; | 949 return false; |
| 957 case CSSSelector::PseudoUnknown: | 950 case CSSSelector::PseudoUnknown: |
| 958 case CSSSelector::PseudoNotParsed: | 951 case CSSSelector::PseudoNotParsed: |
| 959 default: | 952 default: |
| 960 ASSERT_NOT_REACHED(); | 953 ASSERT_NOT_REACHED(); |
| 961 break; | 954 break; |
| 962 } | 955 } |
| 963 return false; | 956 return false; |
| 964 } | 957 } |
| 965 | 958 |
| 966 template<typename SiblingTraversalStrategy> | 959 bool SelectorChecker::checkPseudoElement(const SelectorCheckingContext& context)
const |
| 967 bool SelectorChecker::checkPseudoElement(const SelectorCheckingContext& context,
const SiblingTraversalStrategy& siblingTraversalStrategy) const | |
| 968 { | 960 { |
| 969 const CSSSelector& selector = *context.selector; | 961 const CSSSelector& selector = *context.selector; |
| 970 | 962 |
| 971 if (selector.pseudoType() == CSSSelector::PseudoCue) { | 963 if (selector.pseudoType() == CSSSelector::PseudoCue) { |
| 972 SelectorCheckingContext subContext(context); | 964 SelectorCheckingContext subContext(context); |
| 973 subContext.isSubSelector = true; | 965 subContext.isSubSelector = true; |
| 974 subContext.scopeContainsLastMatchedElement = false; | 966 subContext.scopeContainsLastMatchedElement = false; |
| 975 subContext.treatShadowHostAsNormalScope = false; | 967 subContext.treatShadowHostAsNormalScope = false; |
| 976 | 968 |
| 977 const CSSSelector* contextSelector = context.selector; | 969 const CSSSelector* contextSelector = context.selector; |
| 978 ASSERT(contextSelector); | 970 ASSERT(contextSelector); |
| 979 for (subContext.selector = contextSelector->selectorList()->first(); sub
Context.selector; subContext.selector = CSSSelectorList::next(*subContext.select
or)) { | 971 for (subContext.selector = contextSelector->selectorList()->first(); sub
Context.selector; subContext.selector = CSSSelectorList::next(*subContext.select
or)) { |
| 980 if (match(subContext, siblingTraversalStrategy) == SelectorMatches) | 972 if (match(subContext) == SelectorMatches) |
| 981 return true; | 973 return true; |
| 982 } | 974 } |
| 983 return false; | 975 return false; |
| 984 } | 976 } |
| 985 | 977 |
| 986 // FIXME: this used to be a fallthrough condition. | 978 // FIXME: this used to be a fallthrough condition. |
| 987 return true; | 979 return true; |
| 988 } | 980 } |
| 989 | 981 |
| 990 template<typename SiblingTraversalStrategy> | 982 bool SelectorChecker::checkPseudoHost(const SelectorCheckingContext& context, un
signed* specificity) const |
| 991 bool SelectorChecker::checkPseudoHost(const SelectorCheckingContext& context, co
nst SiblingTraversalStrategy& siblingTraversalStrategy, unsigned* specificity) c
onst | |
| 992 { | 983 { |
| 993 const CSSSelector& selector = *context.selector; | 984 const CSSSelector& selector = *context.selector; |
| 994 Element& element = *context.element; | 985 Element& element = *context.element; |
| 995 | 986 |
| 996 if (m_mode == SharingRules) | 987 if (m_mode == SharingRules) |
| 997 return true; | 988 return true; |
| 998 // :host only matches a shadow host when :host is in a shadow tree of the sh
adow host. | 989 // :host only matches a shadow host when :host is in a shadow tree of the sh
adow host. |
| 999 if (!context.scope) | 990 if (!context.scope) |
| 1000 return false; | 991 return false; |
| 1001 const ContainerNode* shadowHost = context.scope->shadowHost(); | 992 const ContainerNode* shadowHost = context.scope->shadowHost(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1016 // If one of simple selectors matches an element, returns SelectorMatches. J
ust "OR". | 1007 // If one of simple selectors matches an element, returns SelectorMatches. J
ust "OR". |
| 1017 for (subContext.selector = selector.selectorList()->first(); subContext.sele
ctor; subContext.selector = CSSSelectorList::next(*subContext.selector)) { | 1008 for (subContext.selector = selector.selectorList()->first(); subContext.sele
ctor; subContext.selector = CSSSelectorList::next(*subContext.selector)) { |
| 1018 subContext.treatShadowHostAsNormalScope = true; | 1009 subContext.treatShadowHostAsNormalScope = true; |
| 1019 subContext.scope = context.scope; | 1010 subContext.scope = context.scope; |
| 1020 // Use ComposedTreeTraversal to traverse a composed ancestor list of a g
iven element. | 1011 // Use ComposedTreeTraversal to traverse a composed ancestor list of a g
iven element. |
| 1021 Element* nextElement = &element; | 1012 Element* nextElement = &element; |
| 1022 SelectorCheckingContext hostContext(subContext); | 1013 SelectorCheckingContext hostContext(subContext); |
| 1023 do { | 1014 do { |
| 1024 MatchResult subResult; | 1015 MatchResult subResult; |
| 1025 hostContext.element = nextElement; | 1016 hostContext.element = nextElement; |
| 1026 if (match(hostContext, siblingTraversalStrategy, &subResult) == Sele
ctorMatches) { | 1017 if (match(hostContext, &subResult) == SelectorMatches) { |
| 1027 matched = true; | 1018 matched = true; |
| 1028 // Consider div:host(div:host(div:host(div:host...))). | 1019 // Consider div:host(div:host(div:host(div:host...))). |
| 1029 maxSpecificity = std::max(maxSpecificity, hostContext.selector->
specificity() + subResult.specificity); | 1020 maxSpecificity = std::max(maxSpecificity, hostContext.selector->
specificity() + subResult.specificity); |
| 1030 break; | 1021 break; |
| 1031 } | 1022 } |
| 1032 hostContext.scopeContainsLastMatchedElement = false; | 1023 hostContext.scopeContainsLastMatchedElement = false; |
| 1033 hostContext.treatShadowHostAsNormalScope = false; | 1024 hostContext.treatShadowHostAsNormalScope = false; |
| 1034 hostContext.scope = nullptr; | 1025 hostContext.scope = nullptr; |
| 1035 | 1026 |
| 1036 if (selector.pseudoType() == CSSSelector::PseudoHost) | 1027 if (selector.pseudoType() == CSSSelector::PseudoHost) |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1131 } | 1122 } |
| 1132 } | 1123 } |
| 1133 | 1124 |
| 1134 bool SelectorChecker::matchesFocusPseudoClass(const Element& element) | 1125 bool SelectorChecker::matchesFocusPseudoClass(const Element& element) |
| 1135 { | 1126 { |
| 1136 if (InspectorInstrumentation::forcePseudoState(const_cast<Element*>(&element
), CSSSelector::PseudoFocus)) | 1127 if (InspectorInstrumentation::forcePseudoState(const_cast<Element*>(&element
), CSSSelector::PseudoFocus)) |
| 1137 return true; | 1128 return true; |
| 1138 return element.focused() && isFrameFocused(element); | 1129 return element.focused() && isFrameFocused(element); |
| 1139 } | 1130 } |
| 1140 | 1131 |
| 1141 template | |
| 1142 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co
nst DOMSiblingTraversalStrategy&, MatchResult*) const; | |
| 1143 | |
| 1144 template | |
| 1145 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co
nst ShadowDOMSiblingTraversalStrategy&, MatchResult*) const; | |
| 1146 | |
| 1147 } | 1132 } |
| OLD | NEW |