1 /* 2 * Copyright (C) 2008 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 32 namespace WebCore { 33 34 static CSSSelector* const freedSelectorArrayMarker = reinterpret_cast<CSSSelector*>(0xbbadbeef); 35 36 CSSSelectorList::~CSSSelectorList() 37 { 38 deleteSelectors(); 39 } 40 41 void CSSSelectorList::adopt(CSSSelectorList& list) 42 { 43 deleteSelectors(); 44 m_selectorArray = list.m_selectorArray; 45 list.m_selectorArray = 0; 46 } 47 48 void CSSSelectorList::adoptSelectorVector(Vector<OwnPtr<CSSParserSelector> >& selectorVector) 49 { 50 deleteSelectors(); 51 const size_t vectorSize = selectorVector.size(); 52 size_t flattenedSize = 0; 53 for (size_t i = 0; i < vectorSize; ++i) { 54 for (CSSParserSelector* selector = selectorVector[i].get(); selector; selector = selector->tagHistory()) 55 ++flattenedSize; 56 } 57 ASSERT(flattenedSize); 58 if (flattenedSize == 1) { 59 m_selectorArray = selectorVector[0]->releaseSelector().leakPtr(); 60 m_selectorArray->setLastInSelectorList(); 61 ASSERT(m_selectorArray->isLastInTagHistory()); 62 selectorVector.shrink(0); 63 return; 64 } 65 m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * flattenedSize)); 66 size_t arrayIndex = 0; 67 for (size_t i = 0; i < vectorSize; ++i) { 68 CSSParserSelector* current = selectorVector[i].get(); 69 while (current) { 70 OwnPtr<CSSSelector> selector = current->releaseSelector(); 71 current = current->tagHistory(); 72 move(selector.release(), &m_selectorArray[arrayIndex]); 73 ASSERT(!m_selectorArray[arrayIndex].isLastInSelectorList()); 74 if (current) 75 m_selectorArray[arrayIndex].setNotLastInTagHistory(); 76 ++arrayIndex; 77 } 78 ASSERT(m_selectorArray[arrayIndex - 1].isLastInTagHistory()); 79 } 80 ASSERT(flattenedSize == arrayIndex); 81 m_selectorArray[arrayIndex - 1].setLastInSelectorList(); 82 selectorVector.shrink(0); 83 } 84 85 void CSSSelectorList::deleteSelectors() 86 { 87 if (!m_selectorArray) 88 return; 89 90 // FIXME: Remove once http://webkit.org/b/56124 is fixed. 91 if (m_selectorArray == freedSelectorArrayMarker) 92 CRASH(); 93 94 // We had two cases in adoptSelectVector. The fast case of a 1 element 95 // vector took the CSSSelector directly, which was allocated with new. 96 // The second case we allocated a new fastMalloc buffer, which should be 97 // freed with fastFree, and the destructors called manually. 98 CSSSelector* s = m_selectorArray; 99 bool done = s->isLastInSelectorList(); 100 if (done) 101 delete s; 102 else { 103 while (1) { 104 s->~CSSSelector(); 105 if (done) 106 break; 107 ++s; 108 done = s->isLastInSelectorList(); 109 } 110 fastFree(m_selectorArray); 111 } 112 113 m_selectorArray = freedSelectorArrayMarker; 114 } 115 116 117 template <typename Functor> 118 static bool forEachTagSelector(Functor& functor, CSSSelector* selector) 119 { 120 ASSERT(selector); 121 122 do { 123 if (functor(selector)) 124 return true; 125 if (CSSSelectorList* selectorList = selector->selectorList()) { 126 for (CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) { 127 if (forEachTagSelector(functor, subSelector)) 128 return true; 129 } 130 } 131 } while ((selector = selector->tagHistory())); 132 133 return false; 134 } 135 136 template <typename Functor> 137 static bool forEachSelector(Functor& functor, const CSSSelectorList* selectorList) 138 { 139 for (CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(selector)) { 140 if (forEachTagSelector(functor, selector)) 141 return true; 142 } 143 144 return false; 145 } 146 147 class SelectorNeedsNamespaceResolutionFunctor { 148 public: 149 bool operator()(CSSSelector* selector) 150 { 151 if (selector->hasTag() && selector->tag().prefix() != nullAtom && selector->tag().prefix() != starAtom) 152 return true; 153 if (selector->hasAttribute() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom) 154 return true; 155 return false; 156 } 157 }; 158 159 bool CSSSelectorList::selectorsNeedNamespaceResolution() 160 { 161 SelectorNeedsNamespaceResolutionFunctor functor; 162 return forEachSelector(functor, this); 163 } 164 165 class SelectorHasUnknownPseudoElementFunctor { 166 public: 167 bool operator()(CSSSelector* selector) 168 { 169 return selector->isUnknownPseudoElement(); 170 } 171 }; 172 173 bool CSSSelectorList::hasUnknownPseudoElements() const 174 { 175 SelectorHasUnknownPseudoElementFunctor functor; 176 return forEachSelector(functor, this); 177 } 178 179 180 181 } // namespace WebCore 182