Home | History | Annotate | Download | only in dom
      1 /*
      2  * Copyright (C) 2011 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "core/dom/MutationObserver.h"
     33 
     34 #include <algorithm>
     35 #include "bindings/v8/Dictionary.h"
     36 #include "bindings/v8/ExceptionState.h"
     37 #include "core/dom/Document.h"
     38 #include "core/dom/ExceptionCode.h"
     39 #include "core/dom/MutationCallback.h"
     40 #include "core/dom/MutationObserverRegistration.h"
     41 #include "core/dom/MutationRecord.h"
     42 #include "core/dom/Node.h"
     43 #include "wtf/HashSet.h"
     44 #include "wtf/MainThread.h"
     45 #include "wtf/Vector.h"
     46 
     47 namespace WebCore {
     48 
     49 static unsigned s_observerPriority = 0;
     50 
     51 struct MutationObserver::ObserverLessThan {
     52     bool operator()(const RefPtr<MutationObserver>& lhs, const RefPtr<MutationObserver>& rhs)
     53     {
     54         return lhs->m_priority < rhs->m_priority;
     55     }
     56 };
     57 
     58 PassRefPtr<MutationObserver> MutationObserver::create(PassRefPtr<MutationCallback> callback)
     59 {
     60     ASSERT(isMainThread());
     61     return adoptRef(new MutationObserver(callback));
     62 }
     63 
     64 MutationObserver::MutationObserver(PassRefPtr<MutationCallback> callback)
     65     : m_callback(callback)
     66     , m_priority(s_observerPriority++)
     67 {
     68     ScriptWrappable::init(this);
     69 }
     70 
     71 MutationObserver::~MutationObserver()
     72 {
     73     ASSERT(m_registrations.isEmpty());
     74 }
     75 
     76 bool MutationObserver::validateOptions(MutationObserverOptions options)
     77 {
     78     return (options & (Attributes | CharacterData | ChildList))
     79         && ((options & Attributes) || !(options & AttributeOldValue))
     80         && ((options & Attributes) || !(options & AttributeFilter))
     81         && ((options & CharacterData) || !(options & CharacterDataOldValue));
     82 }
     83 
     84 void MutationObserver::observe(Node* node, const Dictionary& optionsDictionary, ExceptionState& es)
     85 {
     86     if (!node) {
     87         es.throwDOMException(NotFoundError);
     88         return;
     89     }
     90 
     91     static const struct {
     92         const char* name;
     93         MutationObserverOptions value;
     94     } booleanOptions[] = {
     95         { "childList", ChildList },
     96         { "attributes", Attributes },
     97         { "characterData", CharacterData },
     98         { "subtree", Subtree },
     99         { "attributeOldValue", AttributeOldValue },
    100         { "characterDataOldValue", CharacterDataOldValue }
    101     };
    102     MutationObserverOptions options = 0;
    103     for (unsigned i = 0; i < sizeof(booleanOptions) / sizeof(booleanOptions[0]); ++i) {
    104         bool value = false;
    105         if (optionsDictionary.get(booleanOptions[i].name, value) && value)
    106             options |= booleanOptions[i].value;
    107     }
    108 
    109     HashSet<AtomicString> attributeFilter;
    110     if (optionsDictionary.get("attributeFilter", attributeFilter))
    111         options |= AttributeFilter;
    112 
    113     if (!validateOptions(options)) {
    114         es.throwDOMException(SyntaxError);
    115         return;
    116     }
    117 
    118     node->registerMutationObserver(this, options, attributeFilter);
    119 }
    120 
    121 Vector<RefPtr<MutationRecord> > MutationObserver::takeRecords()
    122 {
    123     Vector<RefPtr<MutationRecord> > records;
    124     records.swap(m_records);
    125     return records;
    126 }
    127 
    128 void MutationObserver::disconnect()
    129 {
    130     m_records.clear();
    131     HashSet<MutationObserverRegistration*> registrations(m_registrations);
    132     for (HashSet<MutationObserverRegistration*>::iterator iter = registrations.begin(); iter != registrations.end(); ++iter)
    133         (*iter)->unregister();
    134 }
    135 
    136 void MutationObserver::observationStarted(MutationObserverRegistration* registration)
    137 {
    138     ASSERT(!m_registrations.contains(registration));
    139     m_registrations.add(registration);
    140 }
    141 
    142 void MutationObserver::observationEnded(MutationObserverRegistration* registration)
    143 {
    144     ASSERT(m_registrations.contains(registration));
    145     m_registrations.remove(registration);
    146 }
    147 
    148 typedef HashSet<RefPtr<MutationObserver> > MutationObserverSet;
    149 
    150 static MutationObserverSet& activeMutationObservers()
    151 {
    152     DEFINE_STATIC_LOCAL(MutationObserverSet, activeObservers, ());
    153     return activeObservers;
    154 }
    155 
    156 static MutationObserverSet& suspendedMutationObservers()
    157 {
    158     DEFINE_STATIC_LOCAL(MutationObserverSet, suspendedObservers, ());
    159     return suspendedObservers;
    160 }
    161 
    162 void MutationObserver::enqueueMutationRecord(PassRefPtr<MutationRecord> mutation)
    163 {
    164     ASSERT(isMainThread());
    165     m_records.append(mutation);
    166     activeMutationObservers().add(this);
    167 }
    168 
    169 void MutationObserver::setHasTransientRegistration()
    170 {
    171     ASSERT(isMainThread());
    172     activeMutationObservers().add(this);
    173 }
    174 
    175 HashSet<Node*> MutationObserver::getObservedNodes() const
    176 {
    177     HashSet<Node*> observedNodes;
    178     for (HashSet<MutationObserverRegistration*>::const_iterator iter = m_registrations.begin(); iter != m_registrations.end(); ++iter)
    179         (*iter)->addRegistrationNodesToSet(observedNodes);
    180     return observedNodes;
    181 }
    182 
    183 bool MutationObserver::canDeliver()
    184 {
    185     return !m_callback->scriptExecutionContext()->activeDOMObjectsAreSuspended();
    186 }
    187 
    188 void MutationObserver::deliver()
    189 {
    190     ASSERT(canDeliver());
    191 
    192     // Calling clearTransientRegistrations() can modify m_registrations, so it's necessary
    193     // to make a copy of the transient registrations before operating on them.
    194     Vector<MutationObserverRegistration*, 1> transientRegistrations;
    195     for (HashSet<MutationObserverRegistration*>::iterator iter = m_registrations.begin(); iter != m_registrations.end(); ++iter) {
    196         if ((*iter)->hasTransientRegistrations())
    197             transientRegistrations.append(*iter);
    198     }
    199     for (size_t i = 0; i < transientRegistrations.size(); ++i)
    200         transientRegistrations[i]->clearTransientRegistrations();
    201 
    202     if (m_records.isEmpty())
    203         return;
    204 
    205     Vector<RefPtr<MutationRecord> > records;
    206     records.swap(m_records);
    207 
    208     m_callback->call(records, this);
    209 }
    210 
    211 void MutationObserver::deliverAllMutations()
    212 {
    213     ASSERT(isMainThread());
    214     static bool deliveryInProgress = false;
    215     if (deliveryInProgress)
    216         return;
    217     deliveryInProgress = true;
    218 
    219     if (!suspendedMutationObservers().isEmpty()) {
    220         Vector<RefPtr<MutationObserver> > suspended;
    221         copyToVector(suspendedMutationObservers(), suspended);
    222         for (size_t i = 0; i < suspended.size(); ++i) {
    223             if (!suspended[i]->canDeliver())
    224                 continue;
    225 
    226             suspendedMutationObservers().remove(suspended[i]);
    227             activeMutationObservers().add(suspended[i]);
    228         }
    229     }
    230 
    231     while (!activeMutationObservers().isEmpty()) {
    232         Vector<RefPtr<MutationObserver> > observers;
    233         copyToVector(activeMutationObservers(), observers);
    234         activeMutationObservers().clear();
    235         std::sort(observers.begin(), observers.end(), ObserverLessThan());
    236         for (size_t i = 0; i < observers.size(); ++i) {
    237             if (observers[i]->canDeliver())
    238                 observers[i]->deliver();
    239             else
    240                 suspendedMutationObservers().add(observers[i]);
    241         }
    242     }
    243 
    244     deliveryInProgress = false;
    245 }
    246 
    247 } // namespace WebCore
    248