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 "HTMLContentElement.h" 29 30#include "CSSParser.h" 31#include "ContentDistributor.h" 32#include "HTMLNames.h" 33#include "QualifiedName.h" 34#include "RuntimeEnabledFeatures.h" 35#include "ShadowRoot.h" 36#include <wtf/StdLibExtras.h> 37 38namespace WebCore { 39 40using HTMLNames::selectAttr; 41 42#if ENABLE(SHADOW_DOM) 43 44const QualifiedName& HTMLContentElement::contentTagName(Document*) 45{ 46 if (!RuntimeEnabledFeatures::shadowDOMEnabled()) 47 return HTMLNames::webkitShadowContentTag; 48 return HTMLNames::contentTag; 49} 50 51PassRefPtr<HTMLContentElement> HTMLContentElement::create(Document* document) 52{ 53 return adoptRef(new HTMLContentElement(contentTagName(document), document)); 54} 55 56PassRefPtr<HTMLContentElement> HTMLContentElement::create(const QualifiedName& tagName, Document* document) 57{ 58 return adoptRef(new HTMLContentElement(tagName, document)); 59} 60 61HTMLContentElement::HTMLContentElement(const QualifiedName& name, Document* document) 62 : InsertionPoint(name, document) 63 , m_shouldParseSelectorList(false) 64 , m_isValidSelector(true) 65{ 66} 67 68HTMLContentElement::~HTMLContentElement() 69{ 70} 71 72InsertionPoint::MatchType HTMLContentElement::matchTypeFor(Node*) 73{ 74 if (select().isNull() || select().isEmpty()) 75 return AlwaysMatches; 76 if (!isSelectValid()) 77 return NeverMatches; 78 return HasToMatchSelector; 79} 80 81const AtomicString& HTMLContentElement::select() const 82{ 83 return getAttribute(selectAttr); 84} 85 86bool HTMLContentElement::isSelectValid() 87{ 88 ensureSelectParsed(); 89 return m_isValidSelector; 90} 91 92void HTMLContentElement::ensureSelectParsed() 93{ 94 if (!m_shouldParseSelectorList) 95 return; 96 97 CSSParser parser(document()); 98 parser.parseSelector(select(), m_selectorList); 99 m_shouldParseSelectorList = false; 100 m_isValidSelector = validateSelect(); 101 if (!m_isValidSelector) 102 m_selectorList = CSSSelectorList(); 103} 104 105void HTMLContentElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 106{ 107 if (name == selectAttr) { 108 if (ShadowRoot* root = containingShadowRoot()) 109 root->owner()->willAffectSelector(); 110 m_shouldParseSelectorList = true; 111 } else 112 InsertionPoint::parseAttribute(name, value); 113} 114 115static bool validateSubSelector(const CSSSelector* selector) 116{ 117 switch (selector->m_match) { 118 case CSSSelector::Tag: 119 case CSSSelector::Id: 120 case CSSSelector::Class: 121 case CSSSelector::Exact: 122 case CSSSelector::Set: 123 case CSSSelector::List: 124 case CSSSelector::Hyphen: 125 case CSSSelector::Contain: 126 case CSSSelector::Begin: 127 case CSSSelector::End: 128 return true; 129 case CSSSelector::PseudoElement: 130 return false; 131 case CSSSelector::PagePseudoClass: 132 case CSSSelector::PseudoClass: 133 break; 134 } 135 136 switch (selector->pseudoType()) { 137 case CSSSelector::PseudoEmpty: 138 case CSSSelector::PseudoLink: 139 case CSSSelector::PseudoVisited: 140 case CSSSelector::PseudoTarget: 141 case CSSSelector::PseudoEnabled: 142 case CSSSelector::PseudoDisabled: 143 case CSSSelector::PseudoChecked: 144 case CSSSelector::PseudoIndeterminate: 145 case CSSSelector::PseudoNthChild: 146 case CSSSelector::PseudoNthLastChild: 147 case CSSSelector::PseudoNthOfType: 148 case CSSSelector::PseudoNthLastOfType: 149 case CSSSelector::PseudoFirstChild: 150 case CSSSelector::PseudoLastChild: 151 case CSSSelector::PseudoFirstOfType: 152 case CSSSelector::PseudoLastOfType: 153 case CSSSelector::PseudoOnlyOfType: 154 return true; 155 default: 156 return false; 157 } 158} 159 160static bool validateSelector(const CSSSelector* selector) 161{ 162 ASSERT(selector); 163 164 if (!validateSubSelector(selector)) 165 return false; 166 167 const CSSSelector* prevSubSelector = selector; 168 const CSSSelector* subSelector = selector->tagHistory(); 169 170 while (subSelector) { 171 if (prevSubSelector->relation() != CSSSelector::SubSelector) 172 return false; 173 if (!validateSubSelector(subSelector)) 174 return false; 175 176 prevSubSelector = subSelector; 177 subSelector = subSelector->tagHistory(); 178 } 179 180 return true; 181} 182 183bool HTMLContentElement::validateSelect() const 184{ 185 ASSERT(!m_shouldParseSelectorList); 186 187 if (select().isNull() || select().isEmpty()) 188 return true; 189 190 if (!m_selectorList.isValid()) 191 return false; 192 193 for (const CSSSelector* selector = m_selectorList.first(); selector; selector = m_selectorList.next(selector)) { 194 if (!validateSelector(selector)) 195 return false; 196 } 197 198 return true; 199} 200 201#endif // if ENABLE(SHADOW_DOM) 202 203} 204 205