11e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)/*
21e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * Copyright (C) 2013 Google Inc. All rights reserved.
31e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) *
41e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without
51e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * modification, are permitted provided that the following conditions are
61e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * met:
71e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) *
81e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) *     * Redistributions of source code must retain the above copyright
91e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * notice, this list of conditions and the following disclaimer.
101e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) *     * Redistributions in binary form must reproduce the above
111e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
121e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * in the documentation and/or other materials provided with the
131e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * distribution.
141e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) *     * Neither the name of Google Inc. nor the names of its
151e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * contributors may be used to endorse or promote products derived from
161e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * this software without specific prior written permission.
171e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) *
181e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
191e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
201e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
211e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
221e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
231e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
241e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
251e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
261e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
271e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
281e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
291e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) */
301e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
311e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "config.h"
321e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "core/dom/CSSSelectorWatch.h"
331e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
3409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)#include "core/css/parser/BisonCSSParser.h"
351e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "core/css/CSSSelectorList.h"
361e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "core/css/StylePropertySet.h"
371e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "core/dom/Document.h"
381e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "core/dom/ExecutionContext.h"
39d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#include "core/frame/LocalFrame.h"
401e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "core/loader/FrameLoaderClient.h"
411e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "core/rendering/style/StyleRareNonInheritedData.h"
421e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
431e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)namespace WebCore {
441e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
451e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)// The address of this string is important; its value is just documentation.
461e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)static const char kSupplementName[] = "CSSSelectorWatch";
471e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
481e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)CSSSelectorWatch::CSSSelectorWatch(Document& document)
491e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    : m_document(document)
501e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    , m_callbackSelectorChangeTimer(this, &CSSSelectorWatch::callbackSelectorChangeTimerFired)
511e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    , m_timerExpirations(0)
521e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){
531e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)}
541e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
551e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)CSSSelectorWatch& CSSSelectorWatch::from(Document& document)
561e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){
57d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    CSSSelectorWatch* watch = static_cast<CSSSelectorWatch*>(DocumentSupplement::from(document, kSupplementName));
581e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    if (!watch) {
591e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        watch = new CSSSelectorWatch(document);
60f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu        DocumentSupplement::provideTo(document, kSupplementName, adoptPtrWillBeNoop(watch));
611e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    }
621e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    return *watch;
631e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)}
641e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
651e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)void CSSSelectorWatch::callbackSelectorChangeTimerFired(Timer<CSSSelectorWatch>*)
661e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){
671e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // Should be ensured by updateSelectorMatches():
681e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    ASSERT(!m_addedSelectors.isEmpty() || !m_removedSelectors.isEmpty());
691e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
701e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    if (m_timerExpirations < 1) {
711e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        m_timerExpirations++;
72d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        m_callbackSelectorChangeTimer.startOneShot(0, FROM_HERE);
731e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        return;
741e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    }
751e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    if (m_document.frame()) {
761e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        Vector<String> addedSelectors;
771e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        Vector<String> removedSelectors;
781e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        copyToVector(m_addedSelectors, addedSelectors);
791e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        copyToVector(m_removedSelectors, removedSelectors);
80f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)        m_document.frame()->loader().client()->selectorMatchChanged(addedSelectors, removedSelectors);
811e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    }
821e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    m_addedSelectors.clear();
831e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    m_removedSelectors.clear();
841e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    m_timerExpirations = 0;
851e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)}
861e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
871e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)void CSSSelectorWatch::updateSelectorMatches(const Vector<String>& removedSelectors, const Vector<String>& addedSelectors)
881e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){
891e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    bool shouldUpdateTimer = false;
901e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
911e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    for (unsigned i = 0; i < removedSelectors.size(); ++i) {
921e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        const String& selector = removedSelectors[i];
9351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        if (!m_matchingCallbackSelectors.remove(selector))
941e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)            continue;
9551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
9651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        // Count reached 0.
9751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        shouldUpdateTimer = true;
9851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        if (m_addedSelectors.contains(selector))
9951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            m_addedSelectors.remove(selector);
10051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        else
10151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            m_removedSelectors.add(selector);
1021e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    }
1031e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
1041e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    for (unsigned i = 0; i < addedSelectors.size(); ++i) {
1051e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        const String& selector = addedSelectors[i];
10651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        HashCountedSet<String>::AddResult result = m_matchingCallbackSelectors.add(selector);
10751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        if (!result.isNewEntry)
1081e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)            continue;
1091e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
11051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        shouldUpdateTimer = true;
1111e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        if (m_removedSelectors.contains(selector))
1121e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)            m_removedSelectors.remove(selector);
1131e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        else
1141e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)            m_addedSelectors.add(selector);
1151e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    }
1161e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
1171e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    if (!shouldUpdateTimer)
1181e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        return;
1191e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
1201e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    if (m_removedSelectors.isEmpty() && m_addedSelectors.isEmpty()) {
1211e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        if (m_callbackSelectorChangeTimer.isActive()) {
1221e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)            m_timerExpirations = 0;
1231e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)            m_callbackSelectorChangeTimer.stop();
1241e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        }
1251e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    } else {
1261e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        m_timerExpirations = 0;
1271e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        if (!m_callbackSelectorChangeTimer.isActive())
128d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            m_callbackSelectorChangeTimer.startOneShot(0, FROM_HERE);
1291e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    }
1301e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)}
1311e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
1321e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)static bool allCompound(const CSSSelectorList& selectorList)
1331e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){
13409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    for (const CSSSelector* selector = selectorList.first(); selector; selector = selectorList.next(*selector)) {
1351e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        if (!selector->isCompound())
1361e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)            return false;
1371e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    }
1381e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    return true;
1391e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)}
1401e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
1411e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)void CSSSelectorWatch::watchCSSSelectors(const Vector<String>& selectors)
1421e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){
1431e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    m_watchedCallbackSelectors.clear();
14409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    BisonCSSParser parser(CSSParserContext(UASheetMode, 0));
1451e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
1461e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    const CSSProperty callbackProperty(CSSPropertyInternalCallback, CSSPrimitiveValue::createIdentifier(CSSValueInternalPresence));
1471e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    const RefPtr<StylePropertySet> callbackPropertySet = ImmutableStylePropertySet::create(&callbackProperty, 1, UASheetMode);
1481e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
1491e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    CSSSelectorList selectorList;
1501e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    for (unsigned i = 0; i < selectors.size(); ++i) {
1511e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        parser.parseSelector(selectors[i], selectorList);
1521e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        if (!selectorList.isValid())
1531e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)            continue;
1541e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
1551e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        // Only accept Compound Selectors, since they're cheaper to match.
1561e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        if (!allCompound(selectorList))
1571e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)            continue;
1581e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
159d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        RefPtrWillBeRawPtr<StyleRule> rule = StyleRule::create();
1601e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        rule->wrapperAdoptSelectorList(selectorList);
1611e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        rule->setProperties(callbackPropertySet);
1621e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        m_watchedCallbackSelectors.append(rule.release());
1631e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    }
1641e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    m_document.changedSelectorWatch();
1651e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)}
1661e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
167f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liuvoid CSSSelectorWatch::trace(Visitor* visitor)
168f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu{
169f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    visitor->trace(m_watchedCallbackSelectors);
170323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    DocumentSupplement::trace(visitor);
171f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu}
172f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu
1731e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)} // namespace WebCore
174