Changeset 99992 in webkit


Ignore:
Timestamp:
Nov 11, 2011 10:56:02 AM (13 years ago)
Author:
adamk@chromium.org
Message:

[MutationObservers] Support attributeFilter for attribute mutations
https://bugs.webkit.org/show_bug.cgi?id=70860

Patch by Rafael Weinstein <rafaelw@chromium.org> on 2011-11-11
Reviewed by Dimitri Glazkov.

Source/WebCore:

This patch adds an attributeFilter to the MutationObserverRegistration and
adds support for only observing attributes whose name are in the provided
filter set (array of strings).

Test: fast/mutation/observe-attributes.html.

  • bindings/js/JSWebKitMutationObserverCustom.cpp:

(WebCore::JSWebKitMutationObserver::observe):

  • bindings/v8/OptionsObject.cpp:

(WebCore::OptionsObject::get):

  • bindings/v8/OptionsObject.h:
  • bindings/v8/custom/V8WebKitMutationObserverCustom.cpp:

(WebCore::V8WebKitMutationObserver::observeCallback):

  • dom/Element.cpp:

(WebCore::enqueueAttributesMutationRecord):

  • dom/MutationObserverRegistration.cpp:

(WebCore::MutationObserverRegistration::resetObservation):
(WebCore::MutationObserverRegistration::shouldReceiveMutationFrom):
(WebCore::MutationObserverRegistration::caseInsensitiveAttributeFilter):

  • dom/MutationObserverRegistration.h:
  • dom/Node.cpp:

(WebCore::Node::collectMatchingObserversForMutation):
(WebCore::Node::getRegisteredMutationObserversOfType):

  • dom/Node.h:
  • dom/WebKitMutationObserver.cpp:

(WebCore::WebKitMutationObserver::observe):

  • dom/WebKitMutationObserver.h:

LayoutTests:

  • fast/mutation/observe-attributes-expected.txt:
  • fast/mutation/observe-attributes.html:
Location:
trunk
Files:
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r99990 r99992  
     12011-11-11  Rafael Weinstein  <rafaelw@chromium.org>
     2
     3        [MutationObservers] Support attributeFilter for attribute mutations
     4        https://bugs.webkit.org/show_bug.cgi?id=70860
     5
     6        Reviewed by Dimitri Glazkov.
     7
     8        * fast/mutation/observe-attributes-expected.txt:
     9        * fast/mutation/observe-attributes.html:
     10
    1112011-11-11  Sadrul Habib Chowdhury  <sadrul@chromium.org>
    212
  • trunk/LayoutTests/fast/mutation/observe-attributes-expected.txt

    r98791 r99992  
    9393PASS mutations[1].oldValue is "foo"
    9494
     95Testing that attributeFilter works as expected and ignores case with HTML elements.
     96...only foo, bar & boom should be received.
     97PASS mutations.length is 3
     98PASS mutations[0].type is "attributes"
     99PASS mutations[0].attributeName is "foo"
     100PASS mutations[0].attributeNamespace is null
     101PASS mutations[1].type is "attributes"
     102PASS mutations[1].attributeName is "bar"
     103PASS mutations[1].attributeNamespace is null
     104PASS mutations[2].type is "attributes"
     105PASS mutations[2].attributeName is "boom"
     106PASS mutations[2].attributeNamespace is null
     107
     108Testing the behavior of attributeFilter when the same observer observes at multiple nodes in a subtree with different filter options.
     109...only foo, bar & bat should be received.
     110PASS mutations.length is 3
     111PASS mutations[0].type is "attributes"
     112PASS mutations[0].attributeName is "foo"
     113PASS mutations[0].attributeNamespace is null
     114PASS mutations[1].type is "attributes"
     115PASS mutations[1].attributeName is "bar"
     116PASS mutations[1].attributeNamespace is null
     117PASS mutations[2].type is "attributes"
     118PASS mutations[2].attributeName is "bat"
     119PASS mutations[2].attributeNamespace is null
     120...bar, bat & baz should all be received.
     121PASS mutations.length is 3
     122PASS mutations[0].type is "attributes"
     123PASS mutations[0].attributeName is "bar"
     124PASS mutations[0].attributeNamespace is null
     125PASS mutations[1].type is "attributes"
     126PASS mutations[1].attributeName is "bat"
     127PASS mutations[1].attributeNamespace is null
     128PASS mutations[2].type is "attributes"
     129PASS mutations[2].attributeName is "baz"
     130PASS mutations[2].attributeNamespace is null
     131
     132Testing that attributeFilter respects case with non-HTML elements.
     133...pathLength should be received.
     134PASS mutations.length is 1
     135PASS mutations[0].type is "attributes"
     136PASS mutations[0].attributeName is "pathLength"
     137PASS mutations[0].attributeNamespace is "http://www.w3.org/2000/svg"
     138
     139Testing that attributeFilter respects case with non-HTML elements.
     140...only ID, id, booM, pathLength should be received.
     141PASS mutations.length is 4
     142PASS mutations[0].type is "attributes"
     143PASS mutations[0].attributeName is "ID"
     144PASS mutations[0].attributeNamespace is null
     145PASS mutations[1].type is "attributes"
     146PASS mutations[1].attributeName is "id"
     147PASS mutations[1].attributeNamespace is null
     148PASS mutations[2].type is "attributes"
     149PASS mutations[2].attributeName is "booM"
     150PASS mutations[2].attributeNamespace is null
     151PASS mutations[3].type is "attributes"
     152PASS mutations[3].attributeName is "pathLength"
     153PASS mutations[3].attributeNamespace is "http://www.w3.org/2000/svg"
     154
    95155PASS successfullyParsed is true
    96156
  • trunk/LayoutTests/fast/mutation/observe-attributes.html

    r98791 r99992  
    108108    function start() {
    109109        debug('Testing that re-observing the same node with the same observer has the effect of resetting the options.');
    110    
     110
    111111                calls = 0;
    112112        mutations = null;
     
    428428        shouldBe('mutations[1].attributeName', '"id"');
    429429        shouldBe('mutations[1].oldValue', '"foo"');
     430        observer.disconnect();
     431        debug('');
     432        runNextTest();
     433    }
     434
     435    start();
     436}
     437
     438function testAttributeFilter() {
     439    var div, path;
     440    var observer;
     441
     442    function start() {
     443        debug('Testing that attributeFilter works as expected and ignores case with HTML elements.');
     444
     445        mutations = null;
     446        observer = new WebKitMutationObserver(function(m) {
     447            mutations = m;
     448        });
     449
     450        div = document.createElement('div');
     451        observer.observe(div, { attributes: true, attributeFilter: ['foo', 'bar', 'booM'] });
     452        div.setAttribute('foo', 'foo');
     453        div.setAttribute('bar', 'bar');
     454        div.setAttribute('baz', 'baz');
     455        div.setAttribute('BOOm', 'boom');
     456
     457        setTimeout(finish, 0);
     458    }
     459
     460    function finish() {
     461        debug('...only foo, bar & boom should be received.');
     462
     463        shouldBe('mutations.length', '3');
     464        shouldBe('mutations[0].type', '"attributes"');
     465        shouldBe('mutations[0].attributeName', '"foo"');
     466        shouldBe('mutations[0].attributeNamespace', 'null');
     467        shouldBe('mutations[1].type', '"attributes"');
     468        shouldBe('mutations[1].attributeName', '"bar"');
     469        shouldBe('mutations[1].attributeNamespace', 'null');
     470        shouldBe('mutations[2].type', '"attributes"');
     471        shouldBe('mutations[2].attributeName', '"boom"');
     472        shouldBe('mutations[2].attributeNamespace', 'null');
     473        observer.disconnect();
     474        debug('');
     475        runNextTest();
     476    }
     477
     478    start();
     479}
     480
     481function testAttributeFilterSubtree() {
     482    var div, div2, div3;
     483    var observer;
     484
     485    function start() {
     486        debug('Testing the behavior of attributeFilter when the same observer observes at multiple nodes in a subtree with different filter options.');
     487
     488        mutations = null;
     489        observer = new WebKitMutationObserver(function(m) {
     490            mutations = m;
     491        });
     492
     493        div = document.createElement('div');
     494        div2 = div.appendChild(document.createElement('div'));
     495        div3 = div2.appendChild(document.createElement('div'));
     496
     497        observer.observe(div, { attributes: true, subtree: true, attributeFilter: ['foo', 'bar'] });
     498        observer.observe(div2, { attributes: true, subtree: true, attributeFilter: ['bar', 'bat'] });
     499
     500        div3.setAttribute('foo', 'foo');
     501        div3.setAttribute('bar', 'bar');
     502        div3.setAttribute('bat', 'bat');
     503        div3.setAttribute('baz', 'baz');
     504
     505        setTimeout(checkAndObserveAll, 0);
     506    }
     507
     508    function checkAndObserveAll() {
     509        debug('...only foo, bar & bat should be received.');
     510
     511        shouldBe('mutations.length', '3');
     512        shouldBe('mutations[0].type', '"attributes"');
     513        shouldBe('mutations[0].attributeName', '"foo"');
     514        shouldBe('mutations[0].attributeNamespace', 'null');
     515        shouldBe('mutations[1].type', '"attributes"');
     516        shouldBe('mutations[1].attributeName', '"bar"');
     517        shouldBe('mutations[1].attributeNamespace', 'null');
     518        shouldBe('mutations[2].type', '"attributes"');
     519        shouldBe('mutations[2].attributeName', '"bat"');
     520        shouldBe('mutations[2].attributeNamespace', 'null');
     521
     522        observer.observe(div2, { attributes: true, subtree: true });
     523        div3.setAttribute('bar', 'bar');
     524        div3.setAttribute('bat', 'bat');
     525        div3.setAttribute('baz', 'baz');
     526
     527        setTimeout(finish, 0);
     528    }
     529
     530    function finish() {
     531        debug('...bar, bat & baz should all be received.');
     532
     533        shouldBe('mutations.length', '3');
     534        shouldBe('mutations[0].type', '"attributes"');
     535        shouldBe('mutations[0].attributeName', '"bar"');
     536        shouldBe('mutations[0].attributeNamespace', 'null');
     537        shouldBe('mutations[1].type', '"attributes"');
     538        shouldBe('mutations[1].attributeName', '"bat"');
     539        shouldBe('mutations[1].attributeNamespace', 'null');
     540        shouldBe('mutations[2].type', '"attributes"');
     541        shouldBe('mutations[2].attributeName', '"baz"');
     542        shouldBe('mutations[2].attributeNamespace', 'null');
     543
     544        observer.disconnect();
     545        debug('');
     546        runNextTest();
     547    }
     548
     549    start();
     550}
     551
     552function testAttributeFilterNonHTMLElement() {
     553    var path;
     554    var observer;
     555
     556    function start() {
     557        debug('Testing that attributeFilter respects case with non-HTML elements.');
     558
     559        mutations = null;
     560        observer = new WebKitMutationObserver(function(m) {
     561            mutations = m;
     562        });
     563
     564        path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
     565        observer.observe(path, { attributes: true, attributeFilter: ['pathLength'] });
     566        path.setAttributeNS('http://www.w3.org/2000/svg', 'pathLength', '200');
     567        path.setAttributeNS('http://www.w3.org/2000/svg', 'pathlength', '200');
     568
     569        setTimeout(finish, 0);
     570    }
     571
     572    function finish() {
     573        debug('...pathLength should be received.');
     574
     575        shouldBe('mutations.length', '1');
     576        shouldBe('mutations[0].type', '"attributes"');
     577        shouldBe('mutations[0].attributeName', '"pathLength"');
     578        shouldBe('mutations[0].attributeNamespace', '"http://www.w3.org/2000/svg"');
     579        observer.disconnect();
     580        debug('');
     581        runNextTest();
     582    }
     583
     584    start();
     585}
     586
     587function testAttributeFilterNonHTMLDocument() {
     588    var svgDoc, div, path;
     589    var observer;
     590
     591    function start() {
     592        debug('Testing that attributeFilter respects case with non-HTML elements.');
     593
     594        svgDoc = document.implementation.createDocument('http://www.w3.org/2000/svg', 'svg', 'svg');
     595        mutations = null;
     596        observer = new WebKitMutationObserver(function(m) {
     597            mutations = m;
     598        });
     599
     600        div = svgDoc.createElement('div');
     601        observer.observe(div, { attributes: true, attributeFilter: ['ID', 'id', 'booM'] });
     602        div.setAttribute('ID', 'ID');
     603        div.setAttribute('id', 'id');
     604        div.setAttribute('baz', 'baz');
     605        div.setAttribute('booM', 'boom');
     606        div.setAttribute('BOOm', 'boom');
     607
     608        path = svgDoc.createElementNS('http://www.w3.org/2000/svg', 'path');
     609        observer.observe(path, { attributes: true, attributeFilter: ['pathLength'] });
     610        path.setAttributeNS('http://www.w3.org/2000/svg', 'pathLength', '200');
     611        path.setAttributeNS('http://www.w3.org/2000/svg', 'pathlength', '200');
     612
     613        setTimeout(finish, 0);
     614    }
     615
     616    function finish() {
     617        debug('...only ID, id, booM, pathLength should be received.');
     618
     619        shouldBe('mutations.length', '4');
     620        shouldBe('mutations[0].type', '"attributes"');
     621        shouldBe('mutations[0].attributeName', '"ID"');
     622        shouldBe('mutations[0].attributeNamespace', 'null');
     623        shouldBe('mutations[1].type', '"attributes"');
     624        shouldBe('mutations[1].attributeName', '"id"');
     625        shouldBe('mutations[1].attributeNamespace', 'null');
     626        shouldBe('mutations[2].type', '"attributes"');
     627        shouldBe('mutations[2].attributeName', '"booM"');
     628        shouldBe('mutations[2].attributeNamespace', 'null');
     629        shouldBe('mutations[3].type', '"attributes"');
     630        shouldBe('mutations[3].attributeName', '"pathLength"');
     631        shouldBe('mutations[3].attributeNamespace', '"http://www.w3.org/2000/svg"');
     632
    430633        observer.disconnect();
    431634        debug('');
     
    447650    testOldValueAsRequested,
    448651    testOldValueUnionMultipleObservations,
    449     testIDLAttribute
     652    testIDLAttribute,
     653    testAttributeFilter,
     654    testAttributeFilterSubtree,
     655    testAttributeFilterNonHTMLElement,
     656    testAttributeFilterNonHTMLDocument
    450657];
    451658var testIndex = 0;
  • trunk/LayoutTests/fast/mutation/observe-exceptions-expected.txt

    r99611 r99992  
    1515PASS observer.observe(document.body, {childList: true, attributeOldValue: true}) threw exception Error: SYNTAX_ERR: DOM Exception 12.
    1616PASS observer.observe(document.body, {attributes: true, characterDataOldValue: true}) threw exception Error: SYNTAX_ERR: DOM Exception 12.
     17PASS observer.observe(document.body, {characterData: true, attributeFilter: ["id"]}) threw exception Error: SYNTAX_ERR: DOM Exception 12.
    1718PASS successfullyParsed is true
    1819
  • trunk/LayoutTests/fast/mutation/observe-exceptions.html

    r99611 r99992  
    2424    shouldThrow('observer.observe(document.body, {childList: true, attributeOldValue: true})');
    2525    shouldThrow('observer.observe(document.body, {attributes: true, characterDataOldValue: true})');
    26     // FIXME: Uncomment the below when attributeFilter is supported.
    27     //shouldThrow('observer.observe(document.body, {characterData: true, attributeFilter: ["id"]})');
     26    shouldThrow('observer.observe(document.body, {characterData: true, attributeFilter: ["id"]})');
    2827}
    2928
  • trunk/Source/WebCore/ChangeLog

    r99988 r99992  
     12011-11-11  Rafael Weinstein  <rafaelw@chromium.org>
     2
     3        [MutationObservers] Support attributeFilter for attribute mutations
     4        https://bugs.webkit.org/show_bug.cgi?id=70860
     5
     6        Reviewed by Dimitri Glazkov.
     7
     8        This patch adds an attributeFilter to the MutationObserverRegistration and
     9        adds support for only observing attributes whose name are in the provided
     10        filter set (array of strings).
     11
     12        Test: fast/mutation/observe-attributes.html.
     13
     14        * bindings/js/JSWebKitMutationObserverCustom.cpp:
     15        (WebCore::JSWebKitMutationObserver::observe):
     16        * bindings/v8/OptionsObject.cpp:
     17        (WebCore::OptionsObject::get):
     18        * bindings/v8/OptionsObject.h:
     19        * bindings/v8/custom/V8WebKitMutationObserverCustom.cpp:
     20        (WebCore::V8WebKitMutationObserver::observeCallback):
     21        * dom/Element.cpp:
     22        (WebCore::enqueueAttributesMutationRecord):
     23        * dom/MutationObserverRegistration.cpp:
     24        (WebCore::MutationObserverRegistration::resetObservation):
     25        (WebCore::MutationObserverRegistration::shouldReceiveMutationFrom):
     26        (WebCore::MutationObserverRegistration::caseInsensitiveAttributeFilter):
     27        * dom/MutationObserverRegistration.h:
     28        * dom/Node.cpp:
     29        (WebCore::Node::collectMatchingObserversForMutation):
     30        (WebCore::Node::getRegisteredMutationObserversOfType):
     31        * dom/Node.h:
     32        * dom/WebKitMutationObserver.cpp:
     33        (WebCore::WebKitMutationObserver::observe):
     34        * dom/WebKitMutationObserver.h:
     35
    1362011-11-11  Vsevolod Vlasov  <vsevik@chromium.org>
    237
  • trunk/Source/WebCore/bindings/js/JSWebKitMutationObserverCustom.cpp

    r99611 r99992  
    7979    JSDictionary dictionary(exec, optionsObject);
    8080    MutationObserverOptions options = 0;
     81    // FIXME: Add support for parsing of the attributeFilter option.
    8182    bool option;
    8283    if (dictionary.tryGetProperty("childList", option) && option)
  • trunk/Source/WebCore/bindings/v8/OptionsObject.cpp

    r99261 r99992  
    216216}
    217217
     218bool OptionsObject::get(const String& key, HashSet<AtomicString>& value) const
     219{
     220    v8::Local<v8::Value> v8Value;
     221    if (!getKey(key, v8Value))
     222        return false;
     223
     224    // FIXME: Support array-like objects
     225    if (!v8Value->IsArray())
     226        return false;
     227
     228    v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value);
     229    for (size_t i = 0; i < v8Array->Length(); ++i) {
     230        v8::Local<v8::Value> indexedValue = v8Array->Get(v8::Integer::New(i));
     231        value.add(v8ValueToWebCoreString(indexedValue));
     232    }
     233
     234    return true;
     235}
     236
    218237bool OptionsObject::getWithUndefinedOrNullCheck(const String& key, String& value) const
    219238{
  • trunk/Source/WebCore/bindings/v8/OptionsObject.h

    r99261 r99992  
    3131#include "ScriptValue.h"
    3232#include <v8.h>
     33#include <wtf/HashSet.h>
     34#include <wtf/text/AtomicString.h>
    3335
    3436namespace WebCore {
     
    6264    bool get(const String&, RefPtr<TrackBase>&) const;
    6365#endif
     66    bool get(const String&, HashSet<AtomicString>&) const;
    6467
    6568    bool getWithUndefinedOrNullCheck(const String&, String&) const;
  • trunk/Source/WebCore/bindings/v8/custom/V8WebKitMutationObserverCustom.cpp

    r99611 r99992  
    4444#include "V8Proxy.h"
    4545#include "V8Utilities.h"
     46#include "WebKitMutationObserver.h"
     47
     48#include <wtf/HashSet.h>
     49#include <wtf/text/AtomicString.h>
    4650
    4751namespace WebCore {
     
    9094    OptionsObject optionsObject(args[1]);
    9195    unsigned options = 0;
     96    HashSet<AtomicString> attributeFilter;
    9297    bool option;
    9398    if (optionsObject.get("childList", option) && option)
     
    95100    if (optionsObject.get("attributes", option) && option)
    96101        options |= WebKitMutationObserver::Attributes;
     102    if (optionsObject.get("attributeFilter", attributeFilter))
     103        options |= WebKitMutationObserver::AttributeFilter;
    97104    if (optionsObject.get("characterData", option) && option)
    98105        options |= WebKitMutationObserver::CharacterData;
     
    105112
    106113    ExceptionCode ec = 0;
    107     imp->observe(target, options, ec);
     114    imp->observe(target, options, attributeFilter, ec);
    108115    if (ec)
    109116        V8Proxy::setDOMException(ec);
  • trunk/Source/WebCore/dom/Element.cpp

    r99778 r99992  
    635635{
    636636    HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions> observers;
    637     element->getRegisteredMutationObserversOfType(observers, WebKitMutationObserver::Attributes);
     637    element->getRegisteredMutationObserversOfType(observers, WebKitMutationObserver::Attributes, name.localName());
    638638    if (observers.isEmpty())
    639639        return;
  • trunk/Source/WebCore/dom/MutationObserverRegistration.cpp

    r99338 r99992  
    5959}
    6060
    61 void MutationObserverRegistration::resetObservation(MutationObserverOptions options)
     61void MutationObserverRegistration::resetObservation(MutationObserverOptions options, const HashSet<AtomicString>& attributeFilter)
    6262{
    6363    clearTransientRegistrations();
    6464    m_options = options;
     65    m_attributeFilter = attributeFilter;
     66    m_caseInsensitiveAttributeFilter.clear();
    6567}
    6668
    6769void MutationObserverRegistration::observedSubtreeNodeWillDetach(PassRefPtr<Node> node)
    6870{
    69     if (!(m_options & WebKitMutationObserver::Subtree))
     71    if (!isSubtree())
    7072        return;
    7173
     
    103105}
    104106
    105 bool MutationObserverRegistration::shouldReceiveMutationFrom(Node* node, WebKitMutationObserver::MutationType type)
     107bool MutationObserverRegistration::shouldReceiveMutationFrom(Node* node, WebKitMutationObserver::MutationType type, const AtomicString& attributeName)
    106108{
    107109    if (!(m_options & type))
    108110        return false;
    109111
    110     if (m_registrationNode != node && !(m_options & WebKitMutationObserver::Subtree))
     112    if (m_registrationNode != node && !isSubtree())
    111113        return false;
    112114
    113     return true;
     115    if (type != WebKitMutationObserver::Attributes || !(m_options & WebKitMutationObserver::AttributeFilter))
     116        return true;
     117
     118    if (m_attributeFilter.contains(attributeName))
     119        return true;
     120
     121    if (node->document()->isHTMLDocument() && node->isHTMLElement())
     122        return caseInsensitiveAttributeFilter().contains(attributeName);
     123
     124    return false;
     125}
     126
     127const HashSet<AtomicString>& MutationObserverRegistration::caseInsensitiveAttributeFilter()
     128{
     129    if (m_caseInsensitiveAttributeFilter)
     130        return *m_caseInsensitiveAttributeFilter;
     131
     132    m_caseInsensitiveAttributeFilter = adoptPtr(new HashSet<AtomicString>());
     133    for (HashSet<AtomicString>::const_iterator iter = m_attributeFilter.begin(); iter != m_attributeFilter.end(); ++iter) {
     134        AtomicString attributeNameLower = iter->lower();
     135        if ((*iter) != attributeNameLower)
     136             m_caseInsensitiveAttributeFilter->add(attributeNameLower);
     137    }
     138
     139    return *m_caseInsensitiveAttributeFilter;
    114140}
    115141
  • trunk/Source/WebCore/dom/MutationObserverRegistration.h

    r99593 r99992  
    4848    ~MutationObserverRegistration();
    4949
    50     void resetObservation(MutationObserverOptions);
     50    void resetObservation(MutationObserverOptions, const HashSet<AtomicString>& attributeFilter);
    5151    void observedSubtreeNodeWillDetach(PassRefPtr<Node>);
    5252    void clearTransientRegistrations();
    5353    void unregister();
    5454
    55     bool shouldReceiveMutationFrom(Node*, WebKitMutationObserver::MutationType);
    56     bool isSubtree() const { return m_options & WebKitMutationObserver::Subtree; }
     55    bool shouldReceiveMutationFrom(Node*, WebKitMutationObserver::MutationType, const AtomicString& attributeName);
     56    bool inline isSubtree() const { return m_options & WebKitMutationObserver::Subtree; }
    5757
    5858    WebKitMutationObserver* observer() { return m_observer.get(); }
     
    6363    MutationObserverRegistration(PassRefPtr<WebKitMutationObserver>, Node*);
    6464
     65    const HashSet<AtomicString>& caseInsensitiveAttributeFilter();
     66
    6567    RefPtr<WebKitMutationObserver> m_observer;
    6668    Node* m_registrationNode;
     
    7072
    7173    MutationObserverOptions m_options;
     74    HashSet<AtomicString> m_attributeFilter;
     75    OwnPtr<HashSet<AtomicString> > m_caseInsensitiveAttributeFilter;
    7276};
    7377
  • trunk/Source/WebCore/dom/Node.cpp

    r99593 r99992  
    27222722}
    27232723
    2724 void Node::collectMatchingObserversForMutation(HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>& observers, Node* fromNode, WebKitMutationObserver::MutationType type)
     2724void Node::collectMatchingObserversForMutation(HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>& observers, Node* fromNode, WebKitMutationObserver::MutationType type, const AtomicString& attributeName)
    27252725{
    27262726    if (Vector<OwnPtr<MutationObserverRegistration> >* registry = fromNode->mutationObserverRegistry()) {
     
    27282728        for (size_t i = 0; i < size; ++i) {
    27292729            MutationObserverRegistration* registration = registry->at(i).get();
    2730             if (registration->shouldReceiveMutationFrom(this, type)) {
     2730            if (registration->shouldReceiveMutationFrom(this, type, attributeName)) {
    27312731                MutationRecordDeliveryOptions deliveryOptions = registration->deliveryOptions();
    27322732                pair<HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>::iterator, bool> result = observers.add(registration->observer(), deliveryOptions);
     
    27412741        for (HashSet<MutationObserverRegistration*>::iterator iter = transientRegistry->begin(); iter != transientRegistry->end(); ++iter) {
    27422742            MutationObserverRegistration* registration = *iter;
    2743             if (registration->shouldReceiveMutationFrom(this, type)) {
     2743            if (registration->shouldReceiveMutationFrom(this, type, attributeName)) {
    27442744                MutationRecordDeliveryOptions deliveryOptions = registration->deliveryOptions();
    27452745                pair<HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>::iterator, bool> result = observers.add(registration->observer(), deliveryOptions);
     
    27512751}
    27522752
    2753 void Node::getRegisteredMutationObserversOfType(HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>& observers, WebKitMutationObserver::MutationType type)
    2754 {
    2755     collectMatchingObserversForMutation(observers, this, type);
     2753void Node::getRegisteredMutationObserversOfType(HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>& observers, WebKitMutationObserver::MutationType type, const AtomicString& attributeName)
     2754{
     2755    collectMatchingObserversForMutation(observers, this, type, attributeName);
    27562756
    27572757    if (!document()->hasSubtreeMutationObserverOfType(type))
     
    27592759
    27602760    for (Node* node = parentNode(); node; node = node->parentNode())
    2761         collectMatchingObserversForMutation(observers, node, type);
     2761        collectMatchingObserversForMutation(observers, node, type, attributeName);
    27622762}
    27632763
  • trunk/Source/WebCore/dom/Node.h

    r99484 r99992  
    590590
    591591#if ENABLE(MUTATION_OBSERVERS)
    592     void getRegisteredMutationObserversOfType(HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>&, WebKitMutationObserver::MutationType);
     592    void getRegisteredMutationObserversOfType(HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>&, WebKitMutationObserver::MutationType, const AtomicString& attributeName = nullAtom);
    593593    MutationObserverRegistration* registerMutationObserver(PassRefPtr<WebKitMutationObserver>);
    594594    void unregisterMutationObserver(MutationObserverRegistration*);
     
    724724    Vector<OwnPtr<MutationObserverRegistration> >* mutationObserverRegistry();
    725725    HashSet<MutationObserverRegistration*>* transientMutationObserverRegistry();
    726     void collectMatchingObserversForMutation(HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>&, Node* fromNode, WebKitMutationObserver::MutationType);
     726    void collectMatchingObserversForMutation(HashMap<WebKitMutationObserver*, MutationRecordDeliveryOptions>&, Node* fromNode, WebKitMutationObserver::MutationType, const AtomicString& attributeName);
    727727#endif
    728728
  • trunk/Source/WebCore/dom/WebKitMutationObserver.cpp

    r99611 r99992  
    6464    return (options & (Attributes | CharacterData | ChildList))
    6565        && ((options & Attributes) || !(options & AttributeOldValue))
    66         // FIXME: Uncomment the line below once attributeFilter is supported.
    67         // && ((options & Attributes) || !(options & AttributeFilter))
     66        && ((options & Attributes) || !(options & AttributeFilter))
    6867        && ((options & CharacterData) || !(options & CharacterDataOldValue));
    6968}
    7069
    71 void WebKitMutationObserver::observe(Node* node, MutationObserverOptions options, ExceptionCode& ec)
     70void WebKitMutationObserver::observe(Node* node, MutationObserverOptions options, const HashSet<AtomicString>& attributeFilter, ExceptionCode& ec)
    7271{
    7372    if (!node) {
     
    8382
    8483    MutationObserverRegistration* registration = node->registerMutationObserver(this);
    85     registration->resetObservation(options);
     84    registration->resetObservation(options, attributeFilter);
    8685
    8786    if (registration->isSubtree())
  • trunk/Source/WebCore/dom/WebKitMutationObserver.h

    r99645 r99992  
    7878    ~WebKitMutationObserver();
    7979
    80     void observe(Node*, MutationObserverOptions, ExceptionCode&);
     80    void observe(Node*, MutationObserverOptions, const HashSet<AtomicString>& attributeFilter, ExceptionCode&);
    8181    void disconnect();
    8282    void observationStarted(MutationObserverRegistration*);
Note: See TracChangeset for help on using the changeset viewer.