| 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 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 break; | 373 break; |
| 374 case CSSSelector::PseudoClass: | 374 case CSSSelector::PseudoClass: |
| 375 case CSSSelector::PseudoElement: | 375 case CSSSelector::PseudoElement: |
| 376 default: | 376 default: |
| 377 break; | 377 break; |
| 378 } | 378 } |
| 379 | 379 |
| 380 return true; | 380 return true; |
| 381 } | 381 } |
| 382 | 382 |
| 383 static bool anyAttributeMatches(Element* element, CSSSelector::Match match, cons
t QualifiedName& selectorAttr, const AtomicString& selectorValue, bool caseSensi
tive) | 383 static bool anyAttributeMatches(Element& element, CSSSelector::Match match, cons
t QualifiedName& selectorAttr, const AtomicString& selectorValue, bool caseSensi
tive) |
| 384 { | 384 { |
| 385 ASSERT(element->hasAttributesWithoutUpdate()); | 385 ASSERT(element.hasAttributesWithoutUpdate()); |
| 386 for (size_t i = 0; i < element->attributeCount(); ++i) { | 386 for (size_t i = 0; i < element.attributeCount(); ++i) { |
| 387 const Attribute* attributeItem = element->attributeItem(i); | 387 const Attribute* attributeItem = element.attributeItem(i); |
| 388 | 388 |
| 389 if (!attributeItem->matches(selectorAttr)) | 389 if (!attributeItem->matches(selectorAttr)) |
| 390 continue; | 390 continue; |
| 391 | 391 |
| 392 if (attributeValueMatches(attributeItem, match, selectorValue, caseSensi
tive)) | 392 if (attributeValueMatches(attributeItem, match, selectorValue, caseSensi
tive)) |
| 393 return true; | 393 return true; |
| 394 } | 394 } |
| 395 | 395 |
| 396 return false; | 396 return false; |
| 397 } | 397 } |
| 398 | 398 |
| 399 template<typename SiblingTraversalStrategy> | 399 template<typename SiblingTraversalStrategy> |
| 400 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
lingTraversalStrategy& siblingTraversalStrategy) const | 400 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
lingTraversalStrategy& siblingTraversalStrategy) const |
| 401 { | 401 { |
| 402 Element* const & element = context.element; | 402 ASSERT(context.element); |
| 403 Element& element = *context.element; |
| 403 const CSSSelector* const & selector = context.selector; | 404 const CSSSelector* const & selector = context.selector; |
| 404 ASSERT(element); | |
| 405 ASSERT(selector); | 405 ASSERT(selector); |
| 406 bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.b
ehaviorAtBoundary, context.scope); | 406 bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.b
ehaviorAtBoundary, context.scope); |
| 407 | 407 |
| 408 if (selector->m_match == CSSSelector::Tag) | 408 if (selector->m_match == CSSSelector::Tag) |
| 409 return SelectorChecker::tagMatches(element, selector->tagQName(), elemen
tIsHostInItsShadowTree ? MatchingHostInItsShadowTree : MatchingElement); | 409 return SelectorChecker::tagMatches(element, selector->tagQName(), elemen
tIsHostInItsShadowTree ? MatchingHostInItsShadowTree : MatchingElement); |
| 410 | 410 |
| 411 if (selector->m_match == CSSSelector::Class) | 411 if (selector->m_match == CSSSelector::Class) |
| 412 return element->hasClass() && element->classNames().contains(selector->v
alue()) && !elementIsHostInItsShadowTree; | 412 return element.hasClass() && element.classNames().contains(selector->val
ue()) && !elementIsHostInItsShadowTree; |
| 413 | 413 |
| 414 if (selector->m_match == CSSSelector::Id) | 414 if (selector->m_match == CSSSelector::Id) |
| 415 return element->hasID() && element->idForStyleResolution() == selector->
value() && !elementIsHostInItsShadowTree; | 415 return element.hasID() && element.idForStyleResolution() == selector->va
lue() && !elementIsHostInItsShadowTree; |
| 416 | 416 |
| 417 if (selector->isAttributeSelector()) { | 417 if (selector->isAttributeSelector()) { |
| 418 const QualifiedName& attr = selector->attribute(); | 418 const QualifiedName& attr = selector->attribute(); |
| 419 | 419 |
| 420 if (!element->hasAttributes() || elementIsHostInItsShadowTree) | 420 if (!element.hasAttributes() || elementIsHostInItsShadowTree) |
| 421 return false; | 421 return false; |
| 422 | 422 |
| 423 bool caseSensitive = !m_documentIsHTML || HTMLDocument::isCaseSensitiveA
ttribute(attr); | 423 bool caseSensitive = !m_documentIsHTML || HTMLDocument::isCaseSensitiveA
ttribute(attr); |
| 424 | 424 |
| 425 if (!anyAttributeMatches(element, static_cast<CSSSelector::Match>(select
or->m_match), attr, selector->value(), caseSensitive)) | 425 if (!anyAttributeMatches(element, static_cast<CSSSelector::Match>(select
or->m_match), attr, selector->value(), caseSensitive)) |
| 426 return false; | 426 return false; |
| 427 } | 427 } |
| 428 | 428 |
| 429 if (selector->m_match == CSSSelector::PseudoClass) { | 429 if (selector->m_match == CSSSelector::PseudoClass) { |
| 430 // Handle :not up front. | 430 // Handle :not up front. |
| 431 if (selector->pseudoType() == CSSSelector::PseudoNot) { | 431 if (selector->pseudoType() == CSSSelector::PseudoNot) { |
| 432 SelectorCheckingContext subContext(context); | 432 SelectorCheckingContext subContext(context); |
| 433 subContext.isSubSelector = true; | 433 subContext.isSubSelector = true; |
| 434 ASSERT(selector->selectorList()); | 434 ASSERT(selector->selectorList()); |
| 435 for (subContext.selector = selector->selectorList()->first(); subCon
text.selector; subContext.selector = subContext.selector->tagHistory()) { | 435 for (subContext.selector = selector->selectorList()->first(); subCon
text.selector; subContext.selector = subContext.selector->tagHistory()) { |
| 436 // :not cannot nest. I don't really know why this is a | 436 // :not cannot nest. I don't really know why this is a |
| 437 // restriction in CSS3, but it is, so let's honor it. | 437 // restriction in CSS3, but it is, so let's honor it. |
| 438 // the parser enforces that this never occurs | 438 // the parser enforces that this never occurs |
| 439 ASSERT(subContext.selector->pseudoType() != CSSSelector::PseudoN
ot); | 439 ASSERT(subContext.selector->pseudoType() != CSSSelector::PseudoN
ot); |
| 440 // We select between :visited and :link when applying. We don't
know which one applied (or not) yet. | 440 // We select between :visited and :link when applying. We don't
know which one applied (or not) yet. |
| 441 if (subContext.selector->pseudoType() == CSSSelector::PseudoVisi
ted || (subContext.selector->pseudoType() == CSSSelector::PseudoLink && subConte
xt.visitedMatchType == VisitedMatchEnabled)) | 441 if (subContext.selector->pseudoType() == CSSSelector::PseudoVisi
ted || (subContext.selector->pseudoType() == CSSSelector::PseudoLink && subConte
xt.visitedMatchType == VisitedMatchEnabled)) |
| 442 return true; | 442 return true; |
| 443 if (!checkOne(subContext, DOMSiblingTraversalStrategy())) | 443 if (!checkOne(subContext, DOMSiblingTraversalStrategy())) |
| 444 return true; | 444 return true; |
| 445 } | 445 } |
| 446 } else if (context.hasScrollbarPseudo) { | 446 } else if (context.hasScrollbarPseudo) { |
| 447 // CSS scrollbars match a specific subset of pseudo classes, and the
y have specialized rules for each | 447 // CSS scrollbars match a specific subset of pseudo classes, and the
y have specialized rules for each |
| 448 // (since there are no elements involved). | 448 // (since there are no elements involved). |
| 449 return checkScrollbarPseudoClass(context, &element->document(), sele
ctor); | 449 return checkScrollbarPseudoClass(context, &element.document(), selec
tor); |
| 450 } else if (context.hasSelectionPseudo) { | 450 } else if (context.hasSelectionPseudo) { |
| 451 if (selector->pseudoType() == CSSSelector::PseudoWindowInactive) | 451 if (selector->pseudoType() == CSSSelector::PseudoWindowInactive) |
| 452 return !element->document().page()->focusController().isActive()
; | 452 return !element.document().page()->focusController().isActive(); |
| 453 } | 453 } |
| 454 | 454 |
| 455 // Normal element pseudo class checking. | 455 // Normal element pseudo class checking. |
| 456 switch (selector->pseudoType()) { | 456 switch (selector->pseudoType()) { |
| 457 // Pseudo classes: | 457 // Pseudo classes: |
| 458 case CSSSelector::PseudoNot: | 458 case CSSSelector::PseudoNot: |
| 459 break; // Already handled up above. | 459 break; // Already handled up above. |
| 460 case CSSSelector::PseudoEmpty: | 460 case CSSSelector::PseudoEmpty: |
| 461 { | 461 { |
| 462 bool result = true; | 462 bool result = true; |
| 463 for (Node* n = element->firstChild(); n; n = n->nextSibling()) { | 463 for (Node* n = element.firstChild(); n; n = n->nextSibling()) { |
| 464 if (n->isElementNode()) { | 464 if (n->isElementNode()) { |
| 465 result = false; | 465 result = false; |
| 466 break; | 466 break; |
| 467 } | 467 } |
| 468 if (n->isTextNode()) { | 468 if (n->isTextNode()) { |
| 469 Text* textNode = toText(n); | 469 Text* textNode = toText(n); |
| 470 if (!textNode->data().isEmpty()) { | 470 if (!textNode->data().isEmpty()) { |
| 471 result = false; | 471 result = false; |
| 472 break; | 472 break; |
| 473 } | 473 } |
| 474 } | 474 } |
| 475 } | 475 } |
| 476 if (m_mode == ResolvingStyle) { | 476 if (m_mode == ResolvingStyle) { |
| 477 element->setStyleAffectedByEmpty(); | 477 element.setStyleAffectedByEmpty(); |
| 478 if (context.elementStyle) | 478 if (context.elementStyle) |
| 479 context.elementStyle->setEmptyState(result); | 479 context.elementStyle->setEmptyState(result); |
| 480 else if (element->renderStyle() && (element->document().styl
eEngine()->usesSiblingRules() || element->renderStyle()->unique())) | 480 else if (element.renderStyle() && (element.document().styleE
ngine()->usesSiblingRules() || element.renderStyle()->unique())) |
| 481 element->renderStyle()->setEmptyState(result); | 481 element.renderStyle()->setEmptyState(result); |
| 482 } | 482 } |
| 483 return result; | 483 return result; |
| 484 } | 484 } |
| 485 case CSSSelector::PseudoFirstChild: | 485 case CSSSelector::PseudoFirstChild: |
| 486 // first-child matches the first child that is an element | 486 // first-child matches the first child that is an element |
| 487 if (Element* parent = element->parentElement()) { | 487 if (Element* parent = element.parentElement()) { |
| 488 bool result = siblingTraversalStrategy.isFirstChild(element); | 488 bool result = siblingTraversalStrategy.isFirstChild(&element); |
| 489 if (m_mode == ResolvingStyle) { | 489 if (m_mode == ResolvingStyle) { |
| 490 RenderStyle* childStyle = context.elementStyle ? context.ele
mentStyle : element->renderStyle(); | 490 RenderStyle* childStyle = context.elementStyle ? context.ele
mentStyle : element.renderStyle(); |
| 491 parent->setChildrenAffectedByFirstChildRules(); | 491 parent->setChildrenAffectedByFirstChildRules(); |
| 492 if (result && childStyle) | 492 if (result && childStyle) |
| 493 childStyle->setFirstChildState(); | 493 childStyle->setFirstChildState(); |
| 494 } | 494 } |
| 495 return result; | 495 return result; |
| 496 } | 496 } |
| 497 break; | 497 break; |
| 498 case CSSSelector::PseudoFirstOfType: | 498 case CSSSelector::PseudoFirstOfType: |
| 499 // first-of-type matches the first element of its type | 499 // first-of-type matches the first element of its type |
| 500 if (Element* parent = element->parentElement()) { | 500 if (Element* parent = element.parentElement()) { |
| 501 bool result = siblingTraversalStrategy.isFirstOfType(element, el
ement->tagQName()); | 501 bool result = siblingTraversalStrategy.isFirstOfType(&element, e
lement.tagQName()); |
| 502 if (m_mode == ResolvingStyle) | 502 if (m_mode == ResolvingStyle) |
| 503 parent->setChildrenAffectedByForwardPositionalRules(); | 503 parent->setChildrenAffectedByForwardPositionalRules(); |
| 504 return result; | 504 return result; |
| 505 } | 505 } |
| 506 break; | 506 break; |
| 507 case CSSSelector::PseudoLastChild: | 507 case CSSSelector::PseudoLastChild: |
| 508 // last-child matches the last child that is an element | 508 // last-child matches the last child that is an element |
| 509 if (Element* parent = element->parentElement()) { | 509 if (Element* parent = element.parentElement()) { |
| 510 bool result = parent->isFinishedParsingChildren() && siblingTrav
ersalStrategy.isLastChild(element); | 510 bool result = parent->isFinishedParsingChildren() && siblingTrav
ersalStrategy.isLastChild(&element); |
| 511 if (m_mode == ResolvingStyle) { | 511 if (m_mode == ResolvingStyle) { |
| 512 RenderStyle* childStyle = context.elementStyle ? context.ele
mentStyle : element->renderStyle(); | 512 RenderStyle* childStyle = context.elementStyle ? context.ele
mentStyle : element.renderStyle(); |
| 513 parent->setChildrenAffectedByLastChildRules(); | 513 parent->setChildrenAffectedByLastChildRules(); |
| 514 if (result && childStyle) | 514 if (result && childStyle) |
| 515 childStyle->setLastChildState(); | 515 childStyle->setLastChildState(); |
| 516 } | 516 } |
| 517 return result; | 517 return result; |
| 518 } | 518 } |
| 519 break; | 519 break; |
| 520 case CSSSelector::PseudoLastOfType: | 520 case CSSSelector::PseudoLastOfType: |
| 521 // last-of-type matches the last element of its type | 521 // last-of-type matches the last element of its type |
| 522 if (Element* parent = element->parentElement()) { | 522 if (Element* parent = element.parentElement()) { |
| 523 if (m_mode == ResolvingStyle) | 523 if (m_mode == ResolvingStyle) |
| 524 parent->setChildrenAffectedByBackwardPositionalRules(); | 524 parent->setChildrenAffectedByBackwardPositionalRules(); |
| 525 if (!parent->isFinishedParsingChildren()) | 525 if (!parent->isFinishedParsingChildren()) |
| 526 return false; | 526 return false; |
| 527 return siblingTraversalStrategy.isLastOfType(element, element->t
agQName()); | 527 return siblingTraversalStrategy.isLastOfType(&element, element.t
agQName()); |
| 528 } | 528 } |
| 529 break; | 529 break; |
| 530 case CSSSelector::PseudoOnlyChild: | 530 case CSSSelector::PseudoOnlyChild: |
| 531 if (Element* parent = element->parentElement()) { | 531 if (Element* parent = element.parentElement()) { |
| 532 bool firstChild = siblingTraversalStrategy.isFirstChild(element)
; | 532 bool firstChild = siblingTraversalStrategy.isFirstChild(&element
); |
| 533 bool onlyChild = firstChild && parent->isFinishedParsingChildren
() && siblingTraversalStrategy.isLastChild(element); | 533 bool onlyChild = firstChild && parent->isFinishedParsingChildren
() && siblingTraversalStrategy.isLastChild(&element); |
| 534 if (m_mode == ResolvingStyle) { | 534 if (m_mode == ResolvingStyle) { |
| 535 RenderStyle* childStyle = context.elementStyle ? context.ele
mentStyle : element->renderStyle(); | 535 RenderStyle* childStyle = context.elementStyle ? context.ele
mentStyle : element.renderStyle(); |
| 536 parent->setChildrenAffectedByFirstChildRules(); | 536 parent->setChildrenAffectedByFirstChildRules(); |
| 537 parent->setChildrenAffectedByLastChildRules(); | 537 parent->setChildrenAffectedByLastChildRules(); |
| 538 if (firstChild && childStyle) | 538 if (firstChild && childStyle) |
| 539 childStyle->setFirstChildState(); | 539 childStyle->setFirstChildState(); |
| 540 if (onlyChild && childStyle) | 540 if (onlyChild && childStyle) |
| 541 childStyle->setLastChildState(); | 541 childStyle->setLastChildState(); |
| 542 } | 542 } |
| 543 return onlyChild; | 543 return onlyChild; |
| 544 } | 544 } |
| 545 break; | 545 break; |
| 546 case CSSSelector::PseudoOnlyOfType: | 546 case CSSSelector::PseudoOnlyOfType: |
| 547 // FIXME: This selector is very slow. | 547 // FIXME: This selector is very slow. |
| 548 if (Element* parent = element->parentElement()) { | 548 if (Element* parent = element.parentElement()) { |
| 549 if (m_mode == ResolvingStyle) { | 549 if (m_mode == ResolvingStyle) { |
| 550 parent->setChildrenAffectedByForwardPositionalRules(); | 550 parent->setChildrenAffectedByForwardPositionalRules(); |
| 551 parent->setChildrenAffectedByBackwardPositionalRules(); | 551 parent->setChildrenAffectedByBackwardPositionalRules(); |
| 552 } | 552 } |
| 553 if (!parent->isFinishedParsingChildren()) | 553 if (!parent->isFinishedParsingChildren()) |
| 554 return false; | 554 return false; |
| 555 return siblingTraversalStrategy.isFirstOfType(element, element->
tagQName()) && siblingTraversalStrategy.isLastOfType(element, element->tagQName(
)); | 555 return siblingTraversalStrategy.isFirstOfType(&element, element.
tagQName()) && siblingTraversalStrategy.isLastOfType(&element, element.tagQName(
)); |
| 556 } | 556 } |
| 557 break; | 557 break; |
| 558 case CSSSelector::PseudoNthChild: | 558 case CSSSelector::PseudoNthChild: |
| 559 if (!selector->parseNth()) | 559 if (!selector->parseNth()) |
| 560 break; | 560 break; |
| 561 if (Element* parent = element->parentElement()) { | 561 if (Element* parent = element.parentElement()) { |
| 562 int count = 1 + siblingTraversalStrategy.countElementsBefore(ele
ment); | 562 int count = 1 + siblingTraversalStrategy.countElementsBefore(&el
ement); |
| 563 if (m_mode == ResolvingStyle) { | 563 if (m_mode == ResolvingStyle) { |
| 564 RenderStyle* childStyle = context.elementStyle ? context.ele
mentStyle : element->renderStyle(); | 564 RenderStyle* childStyle = context.elementStyle ? context.ele
mentStyle : element.renderStyle(); |
| 565 element->setChildIndex(count); | 565 element.setChildIndex(count); |
| 566 if (childStyle) | 566 if (childStyle) |
| 567 childStyle->setUnique(); | 567 childStyle->setUnique(); |
| 568 parent->setChildrenAffectedByForwardPositionalRules(); | 568 parent->setChildrenAffectedByForwardPositionalRules(); |
| 569 } | 569 } |
| 570 | 570 |
| 571 if (selector->matchNth(count)) | 571 if (selector->matchNth(count)) |
| 572 return true; | 572 return true; |
| 573 } | 573 } |
| 574 break; | 574 break; |
| 575 case CSSSelector::PseudoNthOfType: | 575 case CSSSelector::PseudoNthOfType: |
| 576 if (!selector->parseNth()) | 576 if (!selector->parseNth()) |
| 577 break; | 577 break; |
| 578 if (Element* parent = element->parentElement()) { | 578 if (Element* parent = element.parentElement()) { |
| 579 int count = 1 + siblingTraversalStrategy.countElementsOfTypeBefo
re(element, element->tagQName()); | 579 int count = 1 + siblingTraversalStrategy.countElementsOfTypeBefo
re(&element, element.tagQName()); |
| 580 if (m_mode == ResolvingStyle) | 580 if (m_mode == ResolvingStyle) |
| 581 parent->setChildrenAffectedByForwardPositionalRules(); | 581 parent->setChildrenAffectedByForwardPositionalRules(); |
| 582 | 582 |
| 583 if (selector->matchNth(count)) | 583 if (selector->matchNth(count)) |
| 584 return true; | 584 return true; |
| 585 } | 585 } |
| 586 break; | 586 break; |
| 587 case CSSSelector::PseudoNthLastChild: | 587 case CSSSelector::PseudoNthLastChild: |
| 588 if (!selector->parseNth()) | 588 if (!selector->parseNth()) |
| 589 break; | 589 break; |
| 590 if (Element* parent = element->parentElement()) { | 590 if (Element* parent = element.parentElement()) { |
| 591 if (m_mode == ResolvingStyle) | 591 if (m_mode == ResolvingStyle) |
| 592 parent->setChildrenAffectedByBackwardPositionalRules(); | 592 parent->setChildrenAffectedByBackwardPositionalRules(); |
| 593 if (!parent->isFinishedParsingChildren()) | 593 if (!parent->isFinishedParsingChildren()) |
| 594 return false; | 594 return false; |
| 595 int count = 1 + siblingTraversalStrategy.countElementsAfter(elem
ent); | 595 int count = 1 + siblingTraversalStrategy.countElementsAfter(&ele
ment); |
| 596 if (selector->matchNth(count)) | 596 if (selector->matchNth(count)) |
| 597 return true; | 597 return true; |
| 598 } | 598 } |
| 599 break; | 599 break; |
| 600 case CSSSelector::PseudoNthLastOfType: | 600 case CSSSelector::PseudoNthLastOfType: |
| 601 if (!selector->parseNth()) | 601 if (!selector->parseNth()) |
| 602 break; | 602 break; |
| 603 if (Element* parent = element->parentElement()) { | 603 if (Element* parent = element.parentElement()) { |
| 604 if (m_mode == ResolvingStyle) | 604 if (m_mode == ResolvingStyle) |
| 605 parent->setChildrenAffectedByBackwardPositionalRules(); | 605 parent->setChildrenAffectedByBackwardPositionalRules(); |
| 606 if (!parent->isFinishedParsingChildren()) | 606 if (!parent->isFinishedParsingChildren()) |
| 607 return false; | 607 return false; |
| 608 | 608 |
| 609 int count = 1 + siblingTraversalStrategy.countElementsOfTypeAfte
r(element, element->tagQName()); | 609 int count = 1 + siblingTraversalStrategy.countElementsOfTypeAfte
r(&element, element.tagQName()); |
| 610 if (selector->matchNth(count)) | 610 if (selector->matchNth(count)) |
| 611 return true; | 611 return true; |
| 612 } | 612 } |
| 613 break; | 613 break; |
| 614 case CSSSelector::PseudoTarget: | 614 case CSSSelector::PseudoTarget: |
| 615 if (element == element->document().cssTarget()) | 615 if (element == element.document().cssTarget()) |
| 616 return true; | 616 return true; |
| 617 break; | 617 break; |
| 618 case CSSSelector::PseudoAny: | 618 case CSSSelector::PseudoAny: |
| 619 { | 619 { |
| 620 SelectorCheckingContext subContext(context); | 620 SelectorCheckingContext subContext(context); |
| 621 subContext.isSubSelector = true; | 621 subContext.isSubSelector = true; |
| 622 PseudoId ignoreDynamicPseudo = NOPSEUDO; | 622 PseudoId ignoreDynamicPseudo = NOPSEUDO; |
| 623 ASSERT(selector->selectorList()); | 623 ASSERT(selector->selectorList()); |
| 624 for (subContext.selector = selector->selectorList()->first(); su
bContext.selector; subContext.selector = CSSSelectorList::next(subContext.select
or)) { | 624 for (subContext.selector = selector->selectorList()->first(); su
bContext.selector; subContext.selector = CSSSelectorList::next(subContext.select
or)) { |
| 625 if (match(subContext, ignoreDynamicPseudo, siblingTraversalS
trategy) == SelectorMatches) | 625 if (match(subContext, ignoreDynamicPseudo, siblingTraversalS
trategy) == SelectorMatches) |
| 626 return true; | 626 return true; |
| 627 } | 627 } |
| 628 } | 628 } |
| 629 break; | 629 break; |
| 630 case CSSSelector::PseudoAutofill: | 630 case CSSSelector::PseudoAutofill: |
| 631 if (!element || !element->isFormControlElement()) | 631 if (!element.isFormControlElement()) |
| 632 break; | 632 break; |
| 633 return toHTMLFormControlElement(element)->isAutofilled(); | 633 return toHTMLFormControlElement(element).isAutofilled(); |
| 634 case CSSSelector::PseudoAnyLink: | 634 case CSSSelector::PseudoAnyLink: |
| 635 case CSSSelector::PseudoLink: | 635 case CSSSelector::PseudoLink: |
| 636 // :visited and :link matches are separated later when applying the
style. Here both classes match all links... | 636 // :visited and :link matches are separated later when applying the
style. Here both classes match all links... |
| 637 return element->isLink(); | 637 return element.isLink(); |
| 638 case CSSSelector::PseudoVisited: | 638 case CSSSelector::PseudoVisited: |
| 639 // ...except if :visited matching is disabled for ancestor/sibling m
atching. | 639 // ...except if :visited matching is disabled for ancestor/sibling m
atching. |
| 640 return element->isLink() && context.visitedMatchType == VisitedMatch
Enabled; | 640 return element.isLink() && context.visitedMatchType == VisitedMatchE
nabled; |
| 641 case CSSSelector::PseudoDrag: | 641 case CSSSelector::PseudoDrag: |
| 642 if (m_mode == ResolvingStyle) { | 642 if (m_mode == ResolvingStyle) { |
| 643 if (context.elementStyle) | 643 if (context.elementStyle) |
| 644 context.elementStyle->setAffectedByDrag(); | 644 context.elementStyle->setAffectedByDrag(); |
| 645 else | 645 else |
| 646 element->setChildrenAffectedByDrag(true); | 646 element.setChildrenAffectedByDrag(true); |
| 647 } | 647 } |
| 648 if (element->renderer() && element->renderer()->isDragging()) | 648 if (element.renderer() && element.renderer()->isDragging()) |
| 649 return true; | 649 return true; |
| 650 break; | 650 break; |
| 651 case CSSSelector::PseudoFocus: | 651 case CSSSelector::PseudoFocus: |
| 652 return matchesFocusPseudoClass(element); | 652 return matchesFocusPseudoClass(element); |
| 653 case CSSSelector::PseudoHover: | 653 case CSSSelector::PseudoHover: |
| 654 // If we're in quirks mode, then hover should never match anchors wi
th no | 654 // If we're in quirks mode, then hover should never match anchors wi
th no |
| 655 // href and *:hover should not match anything. This is important for
sites like wsj.com. | 655 // href and *:hover should not match anything. This is important for
sites like wsj.com. |
| 656 if (m_strictParsing || context.isSubSelector || (selector->m_match =
= CSSSelector::Tag && selector->tagQName() != anyQName() && !isHTMLAnchorElement
(element)) || element->isLink()) { | 656 if (m_strictParsing || context.isSubSelector || (selector->m_match =
= CSSSelector::Tag && selector->tagQName() != anyQName() && !isHTMLAnchorElement
(element)) || element.isLink()) { |
| 657 if (m_mode == ResolvingStyle) { | 657 if (m_mode == ResolvingStyle) { |
| 658 if (context.elementStyle) | 658 if (context.elementStyle) |
| 659 context.elementStyle->setAffectedByHover(); | 659 context.elementStyle->setAffectedByHover(); |
| 660 else | 660 else |
| 661 element->setChildrenAffectedByHover(true); | 661 element.setChildrenAffectedByHover(true); |
| 662 } | 662 } |
| 663 if (element->hovered() || InspectorInstrumentation::forcePseudoS
tate(element, CSSSelector::PseudoHover)) | 663 if (element.hovered() || InspectorInstrumentation::forcePseudoSt
ate(&element, CSSSelector::PseudoHover)) |
| 664 return true; | 664 return true; |
| 665 } | 665 } |
| 666 break; | 666 break; |
| 667 case CSSSelector::PseudoActive: | 667 case CSSSelector::PseudoActive: |
| 668 // If we're in quirks mode, then :active should never match anchors
with no | 668 // If we're in quirks mode, then :active should never match anchors
with no |
| 669 // href and *:active should not match anything. | 669 // href and *:active should not match anything. |
| 670 if (m_strictParsing || context.isSubSelector || (selector->m_match =
= CSSSelector::Tag && selector->tagQName() != anyQName() && !isHTMLAnchorElement
(element)) || element->isLink()) { | 670 if (m_strictParsing || context.isSubSelector || (selector->m_match =
= CSSSelector::Tag && selector->tagQName() != anyQName() && !isHTMLAnchorElement
(element)) || element.isLink()) { |
| 671 if (m_mode == ResolvingStyle) { | 671 if (m_mode == ResolvingStyle) { |
| 672 if (context.elementStyle) | 672 if (context.elementStyle) |
| 673 context.elementStyle->setAffectedByActive(); | 673 context.elementStyle->setAffectedByActive(); |
| 674 else | 674 else |
| 675 element->setChildrenAffectedByActive(true); | 675 element.setChildrenAffectedByActive(true); |
| 676 } | 676 } |
| 677 if (element->active() || InspectorInstrumentation::forcePseudoSt
ate(element, CSSSelector::PseudoActive)) | 677 if (element.active() || InspectorInstrumentation::forcePseudoSta
te(&element, CSSSelector::PseudoActive)) |
| 678 return true; | 678 return true; |
| 679 } | 679 } |
| 680 break; | 680 break; |
| 681 case CSSSelector::PseudoEnabled: | 681 case CSSSelector::PseudoEnabled: |
| 682 if (element && (element->isFormControlElement() || element->hasTagNa
me(optionTag) || isHTMLOptGroupElement(element))) | 682 if (element.isFormControlElement() || element.hasTagName(optionTag)
|| isHTMLOptGroupElement(element)) |
| 683 return !element->isDisabledFormControl(); | 683 return !element.isDisabledFormControl(); |
| 684 break; | 684 break; |
| 685 case CSSSelector::PseudoFullPageMedia: | 685 case CSSSelector::PseudoFullPageMedia: |
| 686 return element && element->document().isMediaDocument(); | 686 return element.document().isMediaDocument(); |
| 687 break; | 687 break; |
| 688 case CSSSelector::PseudoDefault: | 688 case CSSSelector::PseudoDefault: |
| 689 return element && element->isDefaultButtonForForm(); | 689 return element.isDefaultButtonForForm(); |
| 690 case CSSSelector::PseudoDisabled: | 690 case CSSSelector::PseudoDisabled: |
| 691 if (element && (element->isFormControlElement() || element->hasTagNa
me(optionTag) || isHTMLOptGroupElement(element))) | 691 if (element.isFormControlElement() || element.hasTagName(optionTag)
|| isHTMLOptGroupElement(element)) |
| 692 return element->isDisabledFormControl(); | 692 return element.isDisabledFormControl(); |
| 693 break; | 693 break; |
| 694 case CSSSelector::PseudoReadOnly: | 694 case CSSSelector::PseudoReadOnly: |
| 695 return element && element->matchesReadOnlyPseudoClass(); | 695 return element.matchesReadOnlyPseudoClass(); |
| 696 case CSSSelector::PseudoReadWrite: | 696 case CSSSelector::PseudoReadWrite: |
| 697 return element && element->matchesReadWritePseudoClass(); | 697 return element.matchesReadWritePseudoClass(); |
| 698 case CSSSelector::PseudoOptional: | 698 case CSSSelector::PseudoOptional: |
| 699 return element && element->isOptionalFormControl(); | 699 return element.isOptionalFormControl(); |
| 700 case CSSSelector::PseudoRequired: | 700 case CSSSelector::PseudoRequired: |
| 701 return element && element->isRequiredFormControl(); | 701 return element.isRequiredFormControl(); |
| 702 case CSSSelector::PseudoValid: | 702 case CSSSelector::PseudoValid: |
| 703 if (!element) | 703 element.document().setContainsValidityStyleRules(); |
| 704 return false; | 704 return element.willValidate() && element.isValidFormControlElement()
; |
| 705 element->document().setContainsValidityStyleRules(); | |
| 706 return element->willValidate() && element->isValidFormControlElement
(); | |
| 707 case CSSSelector::PseudoInvalid: | 705 case CSSSelector::PseudoInvalid: |
| 708 if (!element) | 706 element.document().setContainsValidityStyleRules(); |
| 709 return false; | 707 return element.willValidate() && !element.isValidFormControlElement(
); |
| 710 element->document().setContainsValidityStyleRules(); | |
| 711 return element->willValidate() && !element->isValidFormControlElemen
t(); | |
| 712 case CSSSelector::PseudoChecked: | 708 case CSSSelector::PseudoChecked: |
| 713 { | 709 { |
| 714 if (!element) | 710 if (element.hasTagName(inputTag)) { |
| 715 break; | 711 HTMLInputElement& inputElement = toHTMLInputElement(element)
; |
| 716 if (element->hasTagName(inputTag)) { | |
| 717 HTMLInputElement* inputElement = toHTMLInputElement(element)
; | |
| 718 // Even though WinIE allows checked and indeterminate to | 712 // Even though WinIE allows checked and indeterminate to |
| 719 // co-exist, the CSS selector spec says that you can't be | 713 // co-exist, the CSS selector spec says that you can't be |
| 720 // both checked and indeterminate. We will behave like WinIE | 714 // both checked and indeterminate. We will behave like WinIE |
| 721 // behind the scenes and just obey the CSS spec here in the | 715 // behind the scenes and just obey the CSS spec here in the |
| 722 // test for matching the pseudo. | 716 // test for matching the pseudo. |
| 723 if (inputElement->shouldAppearChecked() && !inputElement->sh
ouldAppearIndeterminate()) | 717 if (inputElement.shouldAppearChecked() && !inputElement.shou
ldAppearIndeterminate()) |
| 724 return true; | 718 return true; |
| 725 } else if (element->hasTagName(optionTag) && toHTMLOptionElement
(element)->selected()) | 719 } else if (element.hasTagName(optionTag) && toHTMLOptionElement(
element).selected()) |
| 726 return true; | 720 return true; |
| 727 break; | 721 break; |
| 728 } | 722 } |
| 729 case CSSSelector::PseudoIndeterminate: | 723 case CSSSelector::PseudoIndeterminate: |
| 730 return element && element->shouldAppearIndeterminate(); | 724 return element.shouldAppearIndeterminate(); |
| 731 case CSSSelector::PseudoRoot: | 725 case CSSSelector::PseudoRoot: |
| 732 if (element == element->document().documentElement()) | 726 if (element == element.document().documentElement()) |
| 733 return true; | 727 return true; |
| 734 break; | 728 break; |
| 735 case CSSSelector::PseudoLang: | 729 case CSSSelector::PseudoLang: |
| 736 { | 730 { |
| 737 AtomicString value; | 731 AtomicString value; |
| 738 if (element->isWebVTTElement()) | 732 if (element.isWebVTTElement()) |
| 739 value = toWebVTTElement(element)->language(); | 733 value = toWebVTTElement(element).language(); |
| 740 else | 734 else |
| 741 value = element->computeInheritedLanguage(); | 735 value = element.computeInheritedLanguage(); |
| 742 const AtomicString& argument = selector->argument(); | 736 const AtomicString& argument = selector->argument(); |
| 743 if (value.isEmpty() || !value.startsWith(argument, false)) | 737 if (value.isEmpty() || !value.startsWith(argument, false)) |
| 744 break; | 738 break; |
| 745 if (value.length() != argument.length() && value[argument.length
()] != '-') | 739 if (value.length() != argument.length() && value[argument.length
()] != '-') |
| 746 break; | 740 break; |
| 747 return true; | 741 return true; |
| 748 } | 742 } |
| 749 case CSSSelector::PseudoFullScreen: | 743 case CSSSelector::PseudoFullScreen: |
| 750 // While a Document is in the fullscreen state, and the document's c
urrent fullscreen | 744 // While a Document is in the fullscreen state, and the document's c
urrent fullscreen |
| 751 // element is an element in the document, the 'full-screen' pseudocl
ass applies to | 745 // element is an element in the document, the 'full-screen' pseudocl
ass applies to |
| 752 // that element. Also, an <iframe>, <object> or <embed> element whos
e child browsing | 746 // that element. Also, an <iframe>, <object> or <embed> element whos
e child browsing |
| 753 // context's Document is in the fullscreen state has the 'full-scree
n' pseudoclass applied. | 747 // context's Document is in the fullscreen state has the 'full-scree
n' pseudoclass applied. |
| 754 if (element->isFrameElementBase() && element->containsFullScreenElem
ent()) | 748 if (element.isFrameElementBase() && element.containsFullScreenElemen
t()) |
| 755 return true; | 749 return true; |
| 756 if (FullscreenElementStack* fullscreen = FullscreenElementStack::fro
mIfExists(&element->document())) { | 750 if (FullscreenElementStack* fullscreen = FullscreenElementStack::fro
mIfExists(&element.document())) { |
| 757 if (!fullscreen->webkitIsFullScreen()) | 751 if (!fullscreen->webkitIsFullScreen()) |
| 758 return false; | 752 return false; |
| 759 return element == fullscreen->webkitCurrentFullScreenElement(); | 753 return element == fullscreen->webkitCurrentFullScreenElement(); |
| 760 } | 754 } |
| 761 return false; | 755 return false; |
| 762 case CSSSelector::PseudoFullScreenAncestor: | 756 case CSSSelector::PseudoFullScreenAncestor: |
| 763 return element->containsFullScreenElement(); | 757 return element.containsFullScreenElement(); |
| 764 case CSSSelector::PseudoFullScreenDocument: | 758 case CSSSelector::PseudoFullScreenDocument: |
| 765 // While a Document is in the fullscreen state, the 'full-screen-doc
ument' pseudoclass applies | 759 // While a Document is in the fullscreen state, the 'full-screen-doc
ument' pseudoclass applies |
| 766 // to all elements of that Document. | 760 // to all elements of that Document. |
| 767 if (!FullscreenElementStack::isFullScreen(&element->document())) | 761 if (!FullscreenElementStack::isFullScreen(&element.document())) |
| 768 return false; | 762 return false; |
| 769 return true; | 763 return true; |
| 770 case CSSSelector::PseudoSeamlessDocument: | 764 case CSSSelector::PseudoSeamlessDocument: |
| 771 // While a document is rendered in a seamless iframe, the 'seamless-
document' pseudoclass applies | 765 // While a document is rendered in a seamless iframe, the 'seamless-
document' pseudoclass applies |
| 772 // to all elements of that Document. | 766 // to all elements of that Document. |
| 773 return element->document().shouldDisplaySeamlesslyWithParent(); | 767 return element.document().shouldDisplaySeamlesslyWithParent(); |
| 774 case CSSSelector::PseudoInRange: | 768 case CSSSelector::PseudoInRange: |
| 775 if (!element) | 769 element.document().setContainsValidityStyleRules(); |
| 776 return false; | 770 return element.isInRange(); |
| 777 element->document().setContainsValidityStyleRules(); | |
| 778 return element->isInRange(); | |
| 779 case CSSSelector::PseudoOutOfRange: | 771 case CSSSelector::PseudoOutOfRange: |
| 780 if (!element) | 772 element.document().setContainsValidityStyleRules(); |
| 781 return false; | 773 return element.isOutOfRange(); |
| 782 element->document().setContainsValidityStyleRules(); | |
| 783 return element->isOutOfRange(); | |
| 784 case CSSSelector::PseudoFutureCue: | 774 case CSSSelector::PseudoFutureCue: |
| 785 return (element->isWebVTTElement() && !toWebVTTElement(element)->isP
astNode()); | 775 return (element.isWebVTTElement() && !toWebVTTElement(element).isPas
tNode()); |
| 786 case CSSSelector::PseudoPastCue: | 776 case CSSSelector::PseudoPastCue: |
| 787 return (element->isWebVTTElement() && toWebVTTElement(element)->isPa
stNode()); | 777 return (element.isWebVTTElement() && toWebVTTElement(element).isPast
Node()); |
| 788 | 778 |
| 789 case CSSSelector::PseudoScope: | 779 case CSSSelector::PseudoScope: |
| 790 { | 780 { |
| 791 const Node* contextualReferenceNode = !context.scope || (context
.behaviorAtBoundary & BoundaryBehaviorMask) == CrossesBoundary ? element->docume
nt().documentElement() : context.scope; | 781 const Node* contextualReferenceNode = !context.scope || (context
.behaviorAtBoundary & BoundaryBehaviorMask) == CrossesBoundary ? element.documen
t().documentElement() : context.scope; |
| 792 if (element == contextualReferenceNode) | 782 if (element == contextualReferenceNode) |
| 793 return true; | 783 return true; |
| 794 break; | 784 break; |
| 795 } | 785 } |
| 796 | 786 |
| 797 case CSSSelector::PseudoUnresolved: | 787 case CSSSelector::PseudoUnresolved: |
| 798 if (element->isUnresolvedCustomElement()) | 788 if (element.isUnresolvedCustomElement()) |
| 799 return true; | 789 return true; |
| 800 break; | 790 break; |
| 801 | 791 |
| 802 case CSSSelector::PseudoHost: | 792 case CSSSelector::PseudoHost: |
| 803 { | 793 { |
| 804 // :host only matches a shadow host when :host is in a shadow tr
ee of the shadow host. | 794 // :host only matches a shadow host when :host is in a shadow tr
ee of the shadow host. |
| 805 if (!context.scope || !(context.behaviorAtBoundary & ScopeIsShad
owHost) || context.scope != element) | 795 if (!context.scope || !(context.behaviorAtBoundary & ScopeIsShad
owHost) || context.scope != element) |
| 806 return false; | 796 return false; |
| 807 ASSERT(element->shadow()); | 797 ASSERT(element.shadow()); |
| 808 | 798 |
| 809 // For empty parameter case, i.e. just :host or :host(). | 799 // For empty parameter case, i.e. just :host or :host(). |
| 810 if (!selector->selectorList()) | 800 if (!selector->selectorList()) |
| 811 return true; | 801 return true; |
| 812 | 802 |
| 813 SelectorCheckingContext subContext(context); | 803 SelectorCheckingContext subContext(context); |
| 814 subContext.isSubSelector = true; | 804 subContext.isSubSelector = true; |
| 815 subContext.behaviorAtBoundary = CrossesBoundary; | 805 subContext.behaviorAtBoundary = CrossesBoundary; |
| 816 subContext.scope = 0; | 806 subContext.scope = 0; |
| 817 // Use NodeRenderingTraversal to traverse a composed ancestor li
st of a given element. | 807 // Use NodeRenderingTraversal to traverse a composed ancestor li
st of a given element. |
| 818 for (Element* nextElement = NodeRenderingTraversal::parentElemen
t(element); nextElement; nextElement = NodeRenderingTraversal::parentElement(nex
tElement)) { | 808 for (Element* nextElement = NodeRenderingTraversal::parentElemen
t(&element); nextElement; nextElement = NodeRenderingTraversal::parentElement(ne
xtElement)) { |
| 819 // If one of simple selectors matches an element, returns Se
lectorMatches. Just "OR". | 809 // If one of simple selectors matches an element, returns Se
lectorMatches. Just "OR". |
| 820 for (subContext.selector = selector->selectorList()->first()
; subContext.selector; subContext.selector = CSSSelectorList::next(subContext.se
lector)) { | 810 for (subContext.selector = selector->selectorList()->first()
; subContext.selector; subContext.selector = CSSSelectorList::next(subContext.se
lector)) { |
| 821 PseudoId ignoreDynamicPseudo = NOPSEUDO; | 811 PseudoId ignoreDynamicPseudo = NOPSEUDO; |
| 822 subContext.element = nextElement; | 812 subContext.element = nextElement; |
| 823 if (match(subContext, ignoreDynamicPseudo, siblingTraver
salStrategy) == SelectorMatches) | 813 if (match(subContext, ignoreDynamicPseudo, siblingTraver
salStrategy) == SelectorMatches) |
| 824 return true; | 814 return true; |
| 825 } | 815 } |
| 826 } | 816 } |
| 827 } | 817 } |
| 828 break; | 818 break; |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 980 if (relation == CSSSelector::SubSelector) | 970 if (relation == CSSSelector::SubSelector) |
| 981 continue; | 971 continue; |
| 982 if (relation != CSSSelector::Descendant && relation != CSSSelector::Chil
d) | 972 if (relation != CSSSelector::Descendant && relation != CSSSelector::Chil
d) |
| 983 return linkMatchType; | 973 return linkMatchType; |
| 984 if (linkMatchType != MatchAll) | 974 if (linkMatchType != MatchAll) |
| 985 return linkMatchType; | 975 return linkMatchType; |
| 986 } | 976 } |
| 987 return linkMatchType; | 977 return linkMatchType; |
| 988 } | 978 } |
| 989 | 979 |
| 990 bool SelectorChecker::isFrameFocused(const Element* element) | 980 bool SelectorChecker::isFrameFocused(const Element& element) |
| 991 { | 981 { |
| 992 return element->document().frame() && element->document().frame()->selection
().isFocusedAndActive(); | 982 return element.document().frame() && element.document().frame()->selection()
.isFocusedAndActive(); |
| 993 } | 983 } |
| 994 | 984 |
| 995 bool SelectorChecker::matchesFocusPseudoClass(const Element* element) | 985 bool SelectorChecker::matchesFocusPseudoClass(const Element& element) |
| 996 { | 986 { |
| 997 if (InspectorInstrumentation::forcePseudoState(const_cast<Element*>(element)
, CSSSelector::PseudoFocus)) | 987 if (InspectorInstrumentation::forcePseudoState(const_cast<Element*>(&element
), CSSSelector::PseudoFocus)) |
| 998 return true; | 988 return true; |
| 999 return element->focused() && isFrameFocused(element); | 989 return element.focused() && isFrameFocused(element); |
| 1000 } | 990 } |
| 1001 | 991 |
| 1002 template | 992 template |
| 1003 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, Ps
eudoId&, const DOMSiblingTraversalStrategy&) const; | 993 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, Ps
eudoId&, const DOMSiblingTraversalStrategy&) const; |
| 1004 | 994 |
| 1005 template | 995 template |
| 1006 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, Ps
eudoId&, const ShadowDOMSiblingTraversalStrategy&) const; | 996 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, Ps
eudoId&, const ShadowDOMSiblingTraversalStrategy&) const; |
| 1007 | 997 |
| 1008 } | 998 } |
| OLD | NEW |