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     ASSERT(selector);
    128 
    129     do {
    130         if (functor(selector))
    131             return true;
    132         if (const CSSSelectorList* selectorList = selector->selectorList()) {
    133             for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
    134                 if (forEachTagSelector(functor, subSelector))
    135                     return true;
    136             }
    137         }
    138     } while ((selector = selector->tagHistory()));
    139 
    140     return false;
    141 }
    142 
    143 template <typename Functor>
    144 static bool forEachSelector(Functor& functor, const CSSSelectorList* selectorList)
    145 {
    146     for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(selector)) {
    147         if (forEachTagSelector(functor, selector))
    148             return true;
    149     }
    150 
    151     return false;
    152 }
    153 
    154 class SelectorNeedsNamespaceResolutionFunctor {
    155 public:
    156     bool operator()(const CSSSelector* selector)
    157     {
    158         if (selector->m_match == CSSSelector::Tag && selector->tagQName().prefix() != nullAtom && selector->tagQName().prefix() != starAtom)
    159             return true;
    160         if (selector->isAttributeSelector() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom)
    161             return true;
    162         return false;
    163     }
    164 };
    165 
    166 bool CSSSelectorList::selectorsNeedNamespaceResolution()
    167 {
    168     SelectorNeedsNamespaceResolutionFunctor functor;
    169     return forEachSelector(functor, this);
    170 }
    171 
    172 class SelectorHasShadowDistributed {
    173 public:
    174     bool operator()(const CSSSelector* selector)
    175     {
    176         return selector->relationIsAffectedByPseudoContent();
    177     }
    178 };
    179 
    180 bool CSSSelectorList::hasShadowDistributedAt(size_t index) const
    181 {
    182     SelectorHasShadowDistributed functor;
    183     return forEachTagSelector(functor, selectorAt(index));
    184 }
    185 
    186 class SelectorHasCombinatorCrossingTreeBoundary {
    187 public:
    188     bool operator()(const CSSSelector* selector)
    189     {
    190         return selector->relation() == CSSSelector::ChildTree || selector->relation() == CSSSelector::DescendantTree;
    191     }
    192 };
    193 
    194 bool CSSSelectorList::hasCombinatorCrossingTreeBoundaryAt(size_t index) const
    195 {
    196     SelectorHasCombinatorCrossingTreeBoundary functor;
    197     return forEachTagSelector(functor, selectorAt(index));
    198 }
    199 
    200 } // namespace WebCore
    201