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     for (CSSSelector* s = m_selectorArray; !s->isLastInSelectorList(); ++s)
    103         s->~CSSSelector();
    104     fastFree(m_selectorArray);
    105 }
    106 
    107 String CSSSelectorList::selectorsText() const
    108 {
    109     StringBuilder result;
    110 
    111     for (const CSSSelector* s = first(); s; s = next(s)) {
    112         if (s != first())
    113             result.append(", ");
    114         result.append(s->selectorText());
    115     }
    116 
    117     return result.toString();
    118 }
    119 
    120 template <typename Functor>
    121 static bool forEachTagSelector(Functor& functor, const CSSSelector* selector)
    122 {
    123     ASSERT(selector);
    124 
    125     do {
    126         if (functor(selector))
    127             return true;
    128         if (const CSSSelectorList* selectorList = selector->selectorList()) {
    129             for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
    130                 if (forEachTagSelector(functor, subSelector))
    131                     return true;
    132             }
    133         }
    134     } while ((selector = selector->tagHistory()));
    135 
    136     return false;
    137 }
    138 
    139 template <typename Functor>
    140 static bool forEachSelector(Functor& functor, const CSSSelectorList* selectorList)
    141 {
    142     for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(selector)) {
    143         if (forEachTagSelector(functor, selector))
    144             return true;
    145     }
    146 
    147     return false;
    148 }
    149 
    150 class SelectorNeedsNamespaceResolutionFunctor {
    151 public:
    152     bool operator()(const CSSSelector* selector)
    153     {
    154         if (selector->m_match == CSSSelector::Tag && selector->tagQName().prefix() != nullAtom && selector->tagQName().prefix() != starAtom)
    155             return true;
    156         if (selector->isAttributeSelector() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom)
    157             return true;
    158         return false;
    159     }
    160 };
    161 
    162 bool CSSSelectorList::selectorsNeedNamespaceResolution()
    163 {
    164     SelectorNeedsNamespaceResolutionFunctor functor;
    165     return forEachSelector(functor, this);
    166 }
    167 
    168 class SelectorHasInvalidSelectorFunctor {
    169 public:
    170     bool operator()(const CSSSelector* selector)
    171     {
    172         return selector->isUnknownPseudoElement() || selector->isCustomPseudoElement();
    173     }
    174 };
    175 
    176 bool CSSSelectorList::hasInvalidSelector() const
    177 {
    178     SelectorHasInvalidSelectorFunctor functor;
    179     return forEachSelector(functor, this);
    180 }
    181 
    182 class SelectorHasShadowDistributed {
    183 public:
    184     bool operator()(const CSSSelector* selector)
    185     {
    186         return selector->relationIsAffectedByPseudoContent();
    187     }
    188 };
    189 
    190 bool CSSSelectorList::hasShadowDistributedAt(size_t index) const
    191 {
    192     SelectorHasShadowDistributed functor;
    193     return forEachTagSelector(functor, selectorAt(index));
    194 }
    195 
    196 } // namespace WebCore
    197