1635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project/*
2635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Copyright (C) 2008 Apple Inc. All rights reserved.
38f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian * Copyright (C) 2009 Google Inc. All rights reserved.
4635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *
5635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Redistribution and use in source and binary forms, with or without
6635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * modification, are permitted provided that the following conditions
7635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * are met:
8635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
9635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
10635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
11635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
12635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *    documentation and/or other materials provided with the distribution.
13635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *
14635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project */
26635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
27635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "config.h"
28635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "CSSSelectorList.h"
29635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include "CSSParserValues.h"
312fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
32635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectnamespace WebCore {
33635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
3481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochstatic CSSSelector* const freedSelectorArrayMarker = reinterpret_cast<CSSSelector*>(0xbbadbeef);
3581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
36635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectCSSSelectorList::~CSSSelectorList()
37635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
38635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    deleteSelectors();
39635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
40635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
41635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid CSSSelectorList::adopt(CSSSelectorList& list)
42635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
43635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    deleteSelectors();
44635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_selectorArray = list.m_selectorArray;
45635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    list.m_selectorArray = 0;
46635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
47635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
482fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockvoid CSSSelectorList::adoptSelectorVector(Vector<OwnPtr<CSSParserSelector> >& selectorVector)
49635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
50635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    deleteSelectors();
512fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    const size_t vectorSize = selectorVector.size();
522fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    size_t flattenedSize = 0;
532fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    for (size_t i = 0; i < vectorSize; ++i) {
542fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        for (CSSParserSelector* selector = selectorVector[i].get(); selector; selector = selector->tagHistory())
552fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            ++flattenedSize;
562fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
572fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    ASSERT(flattenedSize);
582fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (flattenedSize == 1) {
592fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        m_selectorArray = selectorVector[0]->releaseSelector().leakPtr();
60635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_selectorArray->setLastInSelectorList();
612fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        ASSERT(m_selectorArray->isLastInTagHistory());
62635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        selectorVector.shrink(0);
63635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return;
64635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
652fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * flattenedSize));
662fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    size_t arrayIndex = 0;
672fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    for (size_t i = 0; i < vectorSize; ++i) {
682fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        CSSParserSelector* current = selectorVector[i].get();
692fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        while (current) {
702fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            OwnPtr<CSSSelector> selector = current->releaseSelector();
712fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            current = current->tagHistory();
722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            move(selector.release(), &m_selectorArray[arrayIndex]);
732fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            ASSERT(!m_selectorArray[arrayIndex].isLastInSelectorList());
742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            if (current)
752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                m_selectorArray[arrayIndex].setNotLastInTagHistory();
762fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            ++arrayIndex;
772fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        }
782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        ASSERT(m_selectorArray[arrayIndex - 1].isLastInTagHistory());
79635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
802fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    ASSERT(flattenedSize == arrayIndex);
812fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    m_selectorArray[arrayIndex - 1].setLastInSelectorList();
82635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    selectorVector.shrink(0);
83635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
84635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
85635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid CSSSelectorList::deleteSelectors()
86635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
87635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!m_selectorArray)
88635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return;
898f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
902bde8e466a4451c7319e3a072d118917957d6554Steve Block    // FIXME: Remove once http://webkit.org/b/56124 is fixed.
9181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (m_selectorArray == freedSelectorArrayMarker)
9281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        CRASH();
9381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
948f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    // We had two cases in adoptSelectVector. The fast case of a 1 element
958f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    // vector took the CSSSelector directly, which was allocated with new.
968f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    // The second case we allocated a new fastMalloc buffer, which should be
978f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    // freed with fastFree, and the destructors called manually.
98635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CSSSelector* s = m_selectorArray;
998f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    bool done = s->isLastInSelectorList();
1008f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    if (done)
1018f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        delete s;
1028f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    else {
1038f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        while (1) {
1048f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            s->~CSSSelector();
1058f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            if (done)
1068f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                break;
1078f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            ++s;
1088f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            done = s->isLastInSelectorList();
1098f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        }
1108f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        fastFree(m_selectorArray);
111635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
11281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
11381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    m_selectorArray = freedSelectorArrayMarker;
114635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
115635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
116231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
117231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blocktemplate <typename Functor>
118231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic bool forEachTagSelector(Functor& functor, CSSSelector* selector)
119231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
120231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    ASSERT(selector);
121231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
122231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    do {
123231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (functor(selector))
124231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return true;
1252bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (CSSSelectorList* selectorList = selector->selectorList()) {
1262bde8e466a4451c7319e3a072d118917957d6554Steve Block            for (CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
1272bde8e466a4451c7319e3a072d118917957d6554Steve Block                if (forEachTagSelector(functor, subSelector))
1282bde8e466a4451c7319e3a072d118917957d6554Steve Block                    return true;
1292bde8e466a4451c7319e3a072d118917957d6554Steve Block            }
130231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        }
131231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    } while ((selector = selector->tagHistory()));
132231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
133231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return false;
134231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
135231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
136231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blocktemplate <typename Functor>
137231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic bool forEachSelector(Functor& functor, const CSSSelectorList* selectorList)
138231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
139231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    for (CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(selector)) {
140231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (forEachTagSelector(functor, selector))
141231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return true;
142231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
143231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
144231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return false;
145231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
146231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
147231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockclass SelectorNeedsNamespaceResolutionFunctor {
148231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockpublic:
149231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    bool operator()(CSSSelector* selector)
150231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    {
1512fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if (selector->hasTag() && selector->tag().prefix() != nullAtom && selector->tag().prefix() != starAtom)
152231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return true;
153231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (selector->hasAttribute() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom)
154231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return true;
155231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return false;
156231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
157231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block};
158231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
159231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockbool CSSSelectorList::selectorsNeedNamespaceResolution()
160231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
161231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    SelectorNeedsNamespaceResolutionFunctor functor;
162231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return forEachSelector(functor, this);
163635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
164231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
16565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochclass SelectorHasUnknownPseudoElementFunctor {
16665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochpublic:
16765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    bool operator()(CSSSelector* selector)
16865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    {
16965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        return selector->isUnknownPseudoElement();
17065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    }
17165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch};
17265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
17365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochbool CSSSelectorList::hasUnknownPseudoElements() const
17465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
17565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    SelectorHasUnknownPseudoElementFunctor functor;
17665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    return forEachSelector(functor, this);
17765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
17865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
17965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
18065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
181231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} // namespace WebCore
182