1/* 2 * Copyright (C) 2008, 2012, 2013 Apple Inc. All rights reserved. 3 * Copyright (C) 2009 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * 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 "CSSSelectorList.h" 29 30#include "CSSParserValues.h" 31#include <wtf/text/StringBuilder.h> 32 33namespace WebCore { 34 35CSSSelectorList::~CSSSelectorList() 36{ 37 deleteSelectors(); 38} 39 40CSSSelectorList::CSSSelectorList(const CSSSelectorList& other) 41{ 42 unsigned otherComponentCount = other.componentCount(); 43 ASSERT_WITH_SECURITY_IMPLICATION(otherComponentCount); 44 m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * otherComponentCount)); 45 for (unsigned i = 0; i < otherComponentCount; ++i) 46 new (NotNull, &m_selectorArray[i]) CSSSelector(other.m_selectorArray[i]); 47} 48 49void CSSSelectorList::adopt(CSSSelectorList& list) 50{ 51 deleteSelectors(); 52 m_selectorArray = list.m_selectorArray; 53 list.m_selectorArray = 0; 54} 55 56void CSSSelectorList::adoptSelectorVector(Vector<OwnPtr<CSSParserSelector> >& selectorVector) 57{ 58 ASSERT_WITH_SECURITY_IMPLICATION(!selectorVector.isEmpty()); 59 60 deleteSelectors(); 61 size_t flattenedSize = 0; 62 for (size_t i = 0; i < selectorVector.size(); ++i) { 63 for (CSSParserSelector* selector = selectorVector[i].get(); selector; selector = selector->tagHistory()) 64 ++flattenedSize; 65 } 66 ASSERT(flattenedSize); 67 m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * flattenedSize)); 68 size_t arrayIndex = 0; 69 for (size_t i = 0; i < selectorVector.size(); ++i) { 70 CSSParserSelector* current = selectorVector[i].get(); 71 while (current) { 72 { 73 // Move item from the parser selector vector into m_selectorArray without invoking destructor (Ugh.) 74 CSSSelector* currentSelector = current->releaseSelector().leakPtr(); 75 memcpy(&m_selectorArray[arrayIndex], currentSelector, sizeof(CSSSelector)); 76 fastDeleteSkippingDestructor(currentSelector); 77 } 78 current = current->tagHistory(); 79 ASSERT(!m_selectorArray[arrayIndex].isLastInSelectorList()); 80 if (current) 81 m_selectorArray[arrayIndex].setNotLastInTagHistory(); 82 ++arrayIndex; 83 } 84 ASSERT(m_selectorArray[arrayIndex - 1].isLastInTagHistory()); 85 } 86 ASSERT(flattenedSize == arrayIndex); 87 m_selectorArray[arrayIndex - 1].setLastInSelectorList(); 88 selectorVector.clear(); 89} 90 91unsigned CSSSelectorList::componentCount() const 92{ 93 if (!m_selectorArray) 94 return 0; 95 CSSSelector* current = m_selectorArray; 96 while (!current->isLastInSelectorList()) 97 ++current; 98 return (current - m_selectorArray) + 1; 99} 100 101void CSSSelectorList::deleteSelectors() 102{ 103 if (!m_selectorArray) 104 return; 105 106 for (CSSSelector* s = m_selectorArray; ; ++s) { 107 s->~CSSSelector(); 108 if (s->isLastInSelectorList()) 109 break; 110 } 111 fastFree(m_selectorArray); 112} 113 114String CSSSelectorList::selectorsText() const 115{ 116 StringBuilder result; 117 118 for (const CSSSelector* s = first(); s; s = next(s)) { 119 if (s != first()) 120 result.append(", "); 121 result.append(s->selectorText()); 122 } 123 124 return result.toString(); 125} 126 127template <typename Functor> 128static bool forEachTagSelector(Functor& functor, const CSSSelector* selector) 129{ 130 ASSERT(selector); 131 132 do { 133 if (functor(selector)) 134 return true; 135 if (const CSSSelectorList* selectorList = selector->selectorList()) { 136 for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) { 137 if (forEachTagSelector(functor, subSelector)) 138 return true; 139 } 140 } 141 } while ((selector = selector->tagHistory())); 142 143 return false; 144} 145 146template <typename Functor> 147static bool forEachSelector(Functor& functor, const CSSSelectorList* selectorList) 148{ 149 for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(selector)) { 150 if (forEachTagSelector(functor, selector)) 151 return true; 152 } 153 154 return false; 155} 156 157class SelectorNeedsNamespaceResolutionFunctor { 158public: 159 bool operator()(const CSSSelector* selector) 160 { 161 if (selector->m_match == CSSSelector::Tag && selector->tagQName().prefix() != nullAtom && selector->tagQName().prefix() != starAtom) 162 return true; 163 if (selector->isAttributeSelector() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom) 164 return true; 165 return false; 166 } 167}; 168 169bool CSSSelectorList::selectorsNeedNamespaceResolution() 170{ 171 SelectorNeedsNamespaceResolutionFunctor functor; 172 return forEachSelector(functor, this); 173} 174 175class SelectorHasInvalidSelectorFunctor { 176public: 177 bool operator()(const CSSSelector* selector) 178 { 179 return selector->isUnknownPseudoElement() || selector->isCustomPseudoElement(); 180 } 181}; 182 183bool CSSSelectorList::hasInvalidSelector() const 184{ 185 SelectorHasInvalidSelectorFunctor functor; 186 return forEachSelector(functor, this); 187} 188 189} // namespace WebCore 190