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