Home | History | Annotate | Download | only in html
      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