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 |