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