1 /* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Neither the name of Google Inc. nor the names of its 11 * contributors may be used to endorse or promote products derived from 12 * this software without specific prior written permission. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 #include "core/html/HTMLContentElement.h" 29 30 #include "core/HTMLNames.h" 31 #include "core/css/SelectorChecker.h" 32 #include "core/css/SiblingTraversalStrategies.h" 33 #include "core/css/parser/CSSParser.h" 34 #include "core/dom/QualifiedName.h" 35 #include "core/dom/shadow/ElementShadow.h" 36 #include "core/dom/shadow/ShadowRoot.h" 37 #include "platform/RuntimeEnabledFeatures.h" 38 39 namespace blink { 40 41 using namespace HTMLNames; 42 43 inline HTMLContentElement::HTMLContentElement(Document& document) 44 : InsertionPoint(contentTag, document) 45 , m_shouldParseSelect(false) 46 , m_isValidSelector(true) 47 { 48 } 49 50 DEFINE_NODE_FACTORY(HTMLContentElement) 51 52 HTMLContentElement::~HTMLContentElement() 53 { 54 } 55 56 void HTMLContentElement::parseSelect() 57 { 58 ASSERT(m_shouldParseSelect); 59 60 CSSParser parser(CSSParserContext(document(), 0)); 61 parser.parseSelector(m_select, m_selectorList); 62 m_shouldParseSelect = false; 63 m_isValidSelector = validateSelect(); 64 if (!m_isValidSelector) { 65 CSSSelectorList emptyList; 66 m_selectorList.adopt(emptyList); 67 } 68 } 69 70 void HTMLContentElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 71 { 72 if (name == selectAttr) { 73 if (ShadowRoot* root = containingShadowRoot()) 74 root->owner()->willAffectSelector(); 75 m_shouldParseSelect = true; 76 m_select = value; 77 } else { 78 InsertionPoint::parseAttribute(name, value); 79 } 80 } 81 82 static inline bool includesDisallowedPseudoClass(const CSSSelector& selector) 83 { 84 if (selector.pseudoType() == CSSSelector::PseudoNot) { 85 const CSSSelector* subSelector = selector.selectorList()->first(); 86 return subSelector->match() == CSSSelector::PseudoClass; 87 } 88 return selector.match() == CSSSelector::PseudoClass; 89 } 90 91 bool HTMLContentElement::validateSelect() const 92 { 93 ASSERT(!m_shouldParseSelect); 94 95 if (m_select.isNull() || m_select.isEmpty()) 96 return true; 97 98 if (!m_selectorList.isValid()) 99 return false; 100 101 bool allowAnyPseudoClasses = RuntimeEnabledFeatures::pseudoClassesInMatchingCriteriaInAuthorShadowTreesEnabled() || (containingShadowRoot() && containingShadowRoot()->type() == ShadowRoot::UserAgentShadowRoot); 102 103 for (const CSSSelector* selector = m_selectorList.first(); selector; selector = m_selectorList.next(*selector)) { 104 if (!selector->isCompound()) 105 return false; 106 if (allowAnyPseudoClasses) 107 continue; 108 for (const CSSSelector* subSelector = selector; subSelector; subSelector = subSelector->tagHistory()) { 109 if (includesDisallowedPseudoClass(*subSelector)) 110 return false; 111 } 112 } 113 return true; 114 } 115 116 static inline bool checkOneSelector(const CSSSelector& selector, const WillBeHeapVector<RawPtrWillBeMember<Node>, 32>& siblings, int nth) 117 { 118 Element* element = toElement(siblings[nth]); 119 SelectorChecker selectorChecker(element->document(), SelectorChecker::CollectingCSSRules); 120 SelectorChecker::SelectorCheckingContext context(selector, element, SelectorChecker::VisitedMatchEnabled); 121 ShadowDOMSiblingTraversalStrategy strategy(siblings, nth); 122 return selectorChecker.match(context, strategy) == SelectorChecker::SelectorMatches; 123 } 124 125 bool HTMLContentElement::matchSelector(const WillBeHeapVector<RawPtrWillBeMember<Node>, 32>& siblings, int nth) const 126 { 127 for (const CSSSelector* selector = selectorList().first(); selector; selector = CSSSelectorList::next(*selector)) { 128 if (checkOneSelector(*selector, siblings, nth)) 129 return true; 130 } 131 return false; 132 } 133 134 } 135