1/* 2 * Copyright (C) 2008, 2012, 2013, 2014 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(const CSSSelectorList& other) 36{ 37 unsigned otherComponentCount = other.componentCount(); 38 ASSERT_WITH_SECURITY_IMPLICATION(otherComponentCount); 39 40 m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * otherComponentCount)); 41 for (unsigned i = 0; i < otherComponentCount; ++i) 42 new (NotNull, &m_selectorArray[i]) CSSSelector(other.m_selectorArray[i]); 43} 44 45CSSSelectorList::CSSSelectorList(CSSSelectorList&& other) 46 : m_selectorArray(other.m_selectorArray) 47{ 48 ASSERT_WITH_SECURITY_IMPLICATION(componentCount()); 49 other.m_selectorArray = nullptr; 50} 51 52void CSSSelectorList::adoptSelectorVector(Vector<std::unique_ptr<CSSParserSelector>>& selectorVector) 53{ 54 ASSERT_WITH_SECURITY_IMPLICATION(!selectorVector.isEmpty()); 55 56 deleteSelectors(); 57 size_t flattenedSize = 0; 58 for (size_t i = 0; i < selectorVector.size(); ++i) { 59 for (CSSParserSelector* selector = selectorVector[i].get(); selector; selector = selector->tagHistory()) 60 ++flattenedSize; 61 } 62 ASSERT(flattenedSize); 63 m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * flattenedSize)); 64 size_t arrayIndex = 0; 65 for (size_t i = 0; i < selectorVector.size(); ++i) { 66 CSSParserSelector* current = selectorVector[i].get(); 67 while (current) { 68 { 69 // Move item from the parser selector vector into m_selectorArray without invoking destructor (Ugh.) 70 CSSSelector* currentSelector = current->releaseSelector().release(); 71 memcpy(&m_selectorArray[arrayIndex], currentSelector, sizeof(CSSSelector)); 72 73 // Free the underlying memory without invoking the destructor. 74 operator delete (currentSelector); 75 } 76 current = current->tagHistory(); 77 ASSERT(!m_selectorArray[arrayIndex].isLastInSelectorList()); 78 if (current) 79 m_selectorArray[arrayIndex].setNotLastInTagHistory(); 80 ++arrayIndex; 81 } 82 ASSERT(m_selectorArray[arrayIndex - 1].isLastInTagHistory()); 83 } 84 ASSERT(flattenedSize == arrayIndex); 85 m_selectorArray[arrayIndex - 1].setLastInSelectorList(); 86 selectorVector.clear(); 87} 88 89unsigned CSSSelectorList::componentCount() const 90{ 91 if (!m_selectorArray) 92 return 0; 93 CSSSelector* current = m_selectorArray; 94 while (!current->isLastInSelectorList()) 95 ++current; 96 return (current - m_selectorArray) + 1; 97} 98 99CSSSelectorList& CSSSelectorList::operator=(CSSSelectorList&& other) 100{ 101 deleteSelectors(); 102 m_selectorArray = other.m_selectorArray; 103 other.m_selectorArray = nullptr; 104 105 ASSERT_WITH_SECURITY_IMPLICATION(componentCount()); 106 return *this; 107} 108 109void CSSSelectorList::deleteSelectors() 110{ 111 if (!m_selectorArray) 112 return; 113 114 for (CSSSelector* s = m_selectorArray; ; ++s) { 115 s->~CSSSelector(); 116 if (s->isLastInSelectorList()) 117 break; 118 } 119 fastFree(m_selectorArray); 120} 121 122String CSSSelectorList::selectorsText() const 123{ 124 StringBuilder result; 125 126 for (const CSSSelector* s = first(); s; s = next(s)) { 127 if (s != first()) 128 result.append(", "); 129 result.append(s->selectorText()); 130 } 131 132 return result.toString(); 133} 134 135template <typename Functor> 136static bool forEachTagSelector(Functor& functor, const CSSSelector* selector) 137{ 138 ASSERT(selector); 139 140 do { 141 if (functor(selector)) 142 return true; 143 if (const CSSSelectorList* selectorList = selector->selectorList()) { 144 for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) { 145 if (forEachTagSelector(functor, subSelector)) 146 return true; 147 } 148 } 149 } while ((selector = selector->tagHistory())); 150 151 return false; 152} 153 154template <typename Functor> 155static bool forEachSelector(Functor& functor, const CSSSelectorList* selectorList) 156{ 157 for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(selector)) { 158 if (forEachTagSelector(functor, selector)) 159 return true; 160 } 161 162 return false; 163} 164 165class SelectorNeedsNamespaceResolutionFunctor { 166public: 167 bool operator()(const CSSSelector* selector) 168 { 169 if (selector->m_match == CSSSelector::Tag && selector->tagQName().prefix() != nullAtom && selector->tagQName().prefix() != starAtom) 170 return true; 171 if (selector->isAttributeSelector() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom) 172 return true; 173 return false; 174 } 175}; 176 177bool CSSSelectorList::selectorsNeedNamespaceResolution() 178{ 179 SelectorNeedsNamespaceResolutionFunctor functor; 180 return forEachSelector(functor, this); 181} 182 183class SelectorHasInvalidSelectorFunctor { 184public: 185 bool operator()(const CSSSelector* selector) 186 { 187 return selector->isUnknownPseudoElement() || selector->isCustomPseudoElement(); 188 } 189}; 190 191bool CSSSelectorList::hasInvalidSelector() const 192{ 193 SelectorHasInvalidSelectorFunctor functor; 194 return forEachSelector(functor, this); 195} 196 197} // namespace WebCore 198