Home | History | Annotate | Download | only in css
      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