Home | History | Annotate | Download | only in shadow
      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/shadow/HTMLContentElement.h"
     29 
     30 #include "HTMLNames.h"
     31 #include "core/css/CSSParser.h"
     32 #include "core/css/SelectorChecker.h"
     33 #include "core/css/SiblingTraversalStrategies.h"
     34 #include "core/dom/QualifiedName.h"
     35 #include "core/dom/shadow/ElementShadow.h"
     36 #include "core/dom/shadow/ShadowRoot.h"
     37 
     38 namespace WebCore {
     39 
     40 using namespace HTMLNames;
     41 
     42 PassRefPtr<HTMLContentElement> HTMLContentElement::create(Document& document)
     43 {
     44     return adoptRef(new HTMLContentElement(document));
     45 }
     46 
     47 HTMLContentElement::HTMLContentElement(Document& document)
     48     : InsertionPoint(contentTag, document)
     49     , m_shouldParseSelect(false)
     50     , m_isValidSelector(true)
     51 {
     52     ScriptWrappable::init(this);
     53 }
     54 
     55 HTMLContentElement::~HTMLContentElement()
     56 {
     57 }
     58 
     59 void HTMLContentElement::parseSelect()
     60 {
     61     ASSERT(m_shouldParseSelect);
     62 
     63     CSSParser parser(document());
     64     parser.parseSelector(m_select, m_selectorList);
     65     m_shouldParseSelect = false;
     66     m_isValidSelector = validateSelect();
     67     if (!m_isValidSelector) {
     68         CSSSelectorList emptyList;
     69         m_selectorList.adopt(emptyList);
     70     }
     71 }
     72 
     73 void HTMLContentElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
     74 {
     75     if (name == selectAttr) {
     76         if (ShadowRoot* root = containingShadowRoot())
     77             root->owner()->willAffectSelector();
     78         m_shouldParseSelect = true;
     79         m_select = value;
     80     } else
     81         InsertionPoint::parseAttribute(name, value);
     82 }
     83 
     84 bool HTMLContentElement::validateSelect() const
     85 {
     86     ASSERT(!m_shouldParseSelect);
     87 
     88     if (m_select.isNull() || m_select.isEmpty())
     89         return true;
     90 
     91     if (!m_selectorList.isValid())
     92         return false;
     93 
     94     for (const CSSSelector* selector = m_selectorList.first(); selector; selector = m_selectorList.next(selector)) {
     95         if (!selector->isCompound())
     96             return false;
     97     }
     98 
     99     return true;
    100 }
    101 
    102 static inline bool checkOneSelector(const CSSSelector* selector, const Vector<Node*, 32>& siblings, int nth)
    103 {
    104     Element* element = toElement(siblings[nth]);
    105     SelectorChecker selectorChecker(element->document(), SelectorChecker::CollectingCSSRules);
    106     SelectorChecker::SelectorCheckingContext context(selector, element, SelectorChecker::VisitedMatchEnabled);
    107     ShadowDOMSiblingTraversalStrategy strategy(siblings, nth);
    108     return selectorChecker.match(context, strategy) == SelectorChecker::SelectorMatches;
    109 }
    110 
    111 bool HTMLContentElement::matchSelector(const Vector<Node*, 32>& siblings, int nth) const
    112 {
    113     for (const CSSSelector* selector = selectorList().first(); selector; selector = CSSSelectorList::next(selector)) {
    114         if (checkOneSelector(selector, siblings, nth))
    115             return true;
    116     }
    117     return false;
    118 }
    119 
    120 }
    121