Changeset 98791 in webkit
- Timestamp:
- Oct 28, 2011 6:31:04 PM (12 years ago)
- Location:
- trunk
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r98789 r98791 1 2011-10-28 Adam Klein <adamk@chromium.org> 2 3 [MutationObservers] Support attributeOldValue for attribute mutations 4 https://bugs.webkit.org/show_bug.cgi?id=70861 5 6 Reviewed by Ryosuke Niwa. 7 8 Added test cases for attributeOldValue to existing tests. 9 10 * fast/mutation/observe-attributes-expected.txt: 11 * fast/mutation/observe-attributes.html: 12 1 13 2011-10-28 Sheriff Bot <webkit.review.bot@gmail.com> 2 14 -
trunk/LayoutTests/fast/mutation/observe-attributes-expected.txt
r98121 r98791 59 59 PASS mutations[1].attributeName is "baz" 60 60 61 Testing basic oldValue delivery. 62 PASS mutations.length is 2 63 PASS mutations[0].type is "attributes" 64 PASS mutations[0].attributeName is "foo" 65 PASS mutations[0].oldValue is null 66 PASS mutations[1].type is "attributes" 67 PASS mutations[1].attributeName is "foo" 68 PASS mutations[1].oldValue is "bar" 69 70 Testing that oldValue is delivered as requested (or not). 71 PASS mutationsWithOldValue.length is 1 72 PASS mutationsWithOldValue[0].type is "attributes" 73 PASS mutationsWithOldValue[0].attributeName is "foo" 74 PASS mutationsWithOldValue[0].oldValue is "bar" 75 PASS mutations.length is 1 76 PASS mutations[0].type is "attributes" 77 PASS mutations[0].attributeName is "foo" 78 PASS mutations[0].oldValue is null 79 80 An observer with multiple observations will get attributeOldValue if any entries request it. 81 PASS mutations.length is 1 82 PASS mutations[0].type is "attributes" 83 PASS mutations[0].attributeName is "foo" 84 PASS mutations[0].oldValue is "bar" 85 86 Testing setting an attribute via reflected IDL attribute. 87 PASS mutations.length is 2 88 PASS mutations[0].type is "attributes" 89 PASS mutations[0].attributeName is "id" 90 PASS mutations[0].oldValue is null 91 PASS mutations[1].type is "attributes" 92 PASS mutations[1].attributeName is "id" 93 PASS mutations[1].oldValue is "foo" 94 61 95 PASS successfullyParsed is true 62 96 -
trunk/LayoutTests/fast/mutation/observe-attributes.html
r98407 r98791 11 11 12 12 window.jsTestIsAsync = true; 13 var mutations, mutations2 ;13 var mutations, mutations2, mutationsWithOldValue; 14 14 var calls; 15 15 … … 295 295 start(); 296 296 } 297 var tests = [testBasic, testWrongType, testMultipleRegistration, testMultipleObservers, testNamespaceURI, testPropertyAccess, testOrderingWrtDOMSubtreeModified]; 297 298 function testOldValue() { 299 var div; 300 var observer; 301 302 function start() { 303 debug('Testing basic oldValue delivery.'); 304 mutations = null; 305 div = document.createElement('div'); 306 observer = new WebKitMutationObserver(function(mutations) { 307 window.mutations = mutations; 308 }); 309 observer.observe(div, { attributes: true, attributeOldValue: true }); 310 div.setAttribute('foo', 'bar'); 311 div.setAttribute('foo', 'baz'); 312 setTimeout(finish, 0); 313 } 314 315 function finish() { 316 shouldBe('mutations.length', '2'); 317 shouldBe('mutations[0].type', '"attributes"'); 318 shouldBe('mutations[0].attributeName', '"foo"'); 319 shouldBe('mutations[0].oldValue', 'null'); 320 shouldBe('mutations[1].type', '"attributes"'); 321 shouldBe('mutations[1].attributeName', '"foo"'); 322 shouldBe('mutations[1].oldValue', '"bar"'); 323 observer.disconnect(); 324 debug(''); 325 runNextTest(); 326 } 327 328 start(); 329 } 330 331 function testOldValueAsRequested() { 332 var div; 333 var observerWithOldValue; 334 var observer; 335 336 function start() { 337 debug('Testing that oldValue is delivered as requested (or not).'); 338 mutationsWithOldValue = null; 339 mutations = null; 340 div = document.createElement('div'); 341 div.setAttribute('foo', 'bar'); 342 observerWithOldValue = new WebKitMutationObserver(function(mutations) { 343 window.mutationsWithOldValue = mutations; 344 }); 345 observer = new WebKitMutationObserver(function(mutations) { 346 window.mutations = mutations; 347 }); 348 observerWithOldValue.observe(div, { attributes: true, attributeOldValue: true }); 349 observer.observe(div, { attributes: true }); 350 div.setAttribute('foo', 'baz'); 351 setTimeout(finish, 0); 352 } 353 354 function finish() { 355 shouldBe('mutationsWithOldValue.length', '1'); 356 shouldBe('mutationsWithOldValue[0].type', '"attributes"'); 357 shouldBe('mutationsWithOldValue[0].attributeName', '"foo"'); 358 shouldBe('mutationsWithOldValue[0].oldValue', '"bar"'); 359 shouldBe('mutations.length', '1'); 360 shouldBe('mutations[0].type', '"attributes"'); 361 shouldBe('mutations[0].attributeName', '"foo"'); 362 shouldBe('mutations[0].oldValue', 'null'); 363 observerWithOldValue.disconnect(); 364 observer.disconnect(); 365 debug(''); 366 runNextTest(); 367 } 368 369 start(); 370 } 371 372 function testOldValueUnionMultipleObservations() { 373 var div; 374 var span; 375 var observer; 376 377 function start() { 378 debug('An observer with multiple observations will get attributeOldValue if any entries request it.'); 379 mutations = null; 380 div = document.createElement('div'); 381 span = div.appendChild(document.createElement('span')); 382 span.setAttribute('foo', 'bar'); 383 observer = new WebKitMutationObserver(function(mutations) { 384 window.mutations = mutations; 385 }); 386 observer.observe(div, { attributes: true, attributeOldValue: true, subtree: true }); 387 observer.observe(span, { attributes: true }); 388 span.setAttribute('foo', 'baz'); 389 setTimeout(finish, 0); 390 } 391 392 function finish() { 393 shouldBe('mutations.length', '1'); 394 shouldBe('mutations[0].type', '"attributes"'); 395 shouldBe('mutations[0].attributeName', '"foo"'); 396 shouldBe('mutations[0].oldValue', '"bar"'); 397 observer.disconnect(); 398 debug(''); 399 runNextTest(); 400 } 401 402 start(); 403 } 404 405 function testIDLAttribute() { 406 var div; 407 var observer; 408 409 function start() { 410 debug('Testing setting an attribute via reflected IDL attribute.'); 411 mutations = null; 412 div = document.createElement('div'); 413 observer = new WebKitMutationObserver(function(mutations) { 414 window.mutations = mutations; 415 }); 416 observer.observe(div, { attributes: true, attributeOldValue: true }); 417 div.id = 'foo'; 418 div.id = 'bar'; 419 setTimeout(finish, 0); 420 } 421 422 function finish() { 423 shouldBe('mutations.length', '2'); 424 shouldBe('mutations[0].type', '"attributes"'); 425 shouldBe('mutations[0].attributeName', '"id"'); 426 shouldBe('mutations[0].oldValue', 'null'); 427 shouldBe('mutations[1].type', '"attributes"'); 428 shouldBe('mutations[1].attributeName', '"id"'); 429 shouldBe('mutations[1].oldValue', '"foo"'); 430 observer.disconnect(); 431 debug(''); 432 runNextTest(); 433 } 434 435 start(); 436 } 437 438 var tests = [ 439 testBasic, 440 testWrongType, 441 testMultipleRegistration, 442 testMultipleObservers, 443 testNamespaceURI, 444 testPropertyAccess, 445 testOrderingWrtDOMSubtreeModified, 446 testOldValue, 447 testOldValueAsRequested, 448 testOldValueUnionMultipleObservations, 449 testIDLAttribute 450 ]; 298 451 var testIndex = 0; 299 452 300 453 function runNextTest() { 301 454 if (testIndex < tests.length) -
trunk/Source/WebCore/ChangeLog
r98790 r98791 1 2011-10-28 Adam Klein <adamk@chromium.org> 2 3 [MutationObservers] Support attributeOldValue for attribute mutations 4 https://bugs.webkit.org/show_bug.cgi?id=70861 5 6 Reviewed by Ryosuke Niwa. 7 8 Respect 'attributeOldValue' when passed to WebKitMutationObserver.observe(). 9 10 If multiple observers have different attributeOldValue settings in 11 their registrations, two different MutationRecords are created (one is 12 a wrapper around the other). 13 14 If a single observer has multiple registrations that apply to a single 15 mutation, and those registrations have different values for 16 attributeOldValue, the observer is passed the oldValue. 17 18 * dom/Element.cpp: 19 (WebCore::hasOldValue): 20 (WebCore::enqueueAttributesMutationRecord): 21 (WebCore::Element::setAttribute): 22 * dom/MutationRecord.cpp: 23 (WebCore::MutationRecord::createAttributes): 24 (WebCore::MutationRecord::createWithNullOldValue): 25 * dom/MutationRecord.h: 26 (WebCore::MutationRecord::oldValue): 27 1 28 2011-10-28 Adam Barth <abarth@webkit.org> 2 29 -
trunk/Source/WebCore/dom/Element.cpp
r98659 r98791 618 618 619 619 #if ENABLE(MUTATION_OBSERVERS) 620 static void enqueueAttributesMutationRecord(Element* element, const QualifiedName& name) 620 static inline bool hasOldValue(MutationObserverOptions options) 621 { 622 return options & WebKitMutationObserver::AttributeOldValue; 623 } 624 625 static inline bool isOldValueRequested(const HashMap<WebKitMutationObserver*, MutationObserverOptions>& observers) 626 { 627 for (HashMap<WebKitMutationObserver*, MutationObserverOptions>::const_iterator iter = observers.begin(); iter != observers.end(); ++iter) { 628 if (hasOldValue(iter->second)) 629 return true; 630 } 631 return false; 632 } 633 634 static void enqueueAttributesMutationRecord(Element* element, const QualifiedName& name, const AtomicString& oldValue) 621 635 { 622 636 HashMap<WebKitMutationObserver*, MutationObserverOptions> observers; … … 625 639 return; 626 640 627 RefPtr<MutationRecord> mutation = MutationRecord::createAttributes(element, name); 628 for (HashMap<WebKitMutationObserver*, MutationObserverOptions>::iterator iter = observers.begin(); iter != observers.end(); ++iter) 629 iter->first->enqueueMutationRecord(mutation); 641 RefPtr<MutationRecord> mutation = MutationRecord::createAttributes(element, name, isOldValueRequested(observers) ? oldValue : nullAtom); 642 RefPtr<MutationRecord> mutationWithNullOldValue; 643 for (HashMap<WebKitMutationObserver*, MutationObserverOptions>::iterator iter = observers.begin(); iter != observers.end(); ++iter) { 644 WebKitMutationObserver* observer = iter->first; 645 if (hasOldValue(iter->second)) { 646 observer->enqueueMutationRecord(mutation); 647 continue; 648 } 649 if (!mutationWithNullOldValue) { 650 if (mutation->oldValue().isNull()) 651 mutationWithNullOldValue = mutation; 652 else 653 mutationWithNullOldValue = MutationRecord::createWithNullOldValue(mutation).get(); 654 } 655 observer->enqueueMutationRecord(mutationWithNullOldValue); 656 } 630 657 } 631 658 #endif … … 653 680 #if ENABLE(MUTATION_OBSERVERS) 654 681 // The call to attributeChanged below may dispatch DOMSubtreeModified, so it's important to enqueue a MutationRecord now. 655 enqueueAttributesMutationRecord(this, attributeName );682 enqueueAttributesMutationRecord(this, attributeName, old ? old->value() : nullAtom); 656 683 #endif 657 684 … … 691 718 #if ENABLE(MUTATION_OBSERVERS) 692 719 // The call to attributeChanged below may dispatch DOMSubtreeModified, so it's important to enqueue a MutationRecord now. 693 enqueueAttributesMutationRecord(this, name );720 enqueueAttributesMutationRecord(this, name, old ? old->value() : nullAtom); 694 721 #endif 695 722 -
trunk/Source/WebCore/dom/MutationRecord.cpp
r97659 r98791 48 48 public: 49 49 ChildListRecord(PassRefPtr<Node> target, PassRefPtr<NodeList> added, PassRefPtr<NodeList> removed, PassRefPtr<Node> previousSibling, PassRefPtr<Node> nextSibling) 50 : MutationRecord(target)50 : m_target(target) 51 51 , m_addedNodes(added) 52 52 , m_removedNodes(removed) … … 57 57 58 58 private: 59 virtual const AtomicString& type(); 60 virtual NodeList* addedNodes() { return m_addedNodes.get(); } 61 virtual NodeList* removedNodes() { return m_removedNodes.get(); } 62 virtual Node* previousSibling() { return m_previousSibling.get(); } 63 virtual Node* nextSibling() { return m_nextSibling.get(); } 59 virtual const AtomicString& type() OVERRIDE; 60 virtual Node* target() OVERRIDE { return m_target.get(); } 61 virtual NodeList* addedNodes() OVERRIDE { return m_addedNodes.get(); } 62 virtual NodeList* removedNodes() OVERRIDE { return m_removedNodes.get(); } 63 virtual Node* previousSibling() OVERRIDE { return m_previousSibling.get(); } 64 virtual Node* nextSibling() OVERRIDE { return m_nextSibling.get(); } 64 65 66 RefPtr<Node> m_target; 65 67 RefPtr<NodeList> m_addedNodes; 66 68 RefPtr<NodeList> m_removedNodes; … … 71 73 class AttributesRecord : public MutationRecord { 72 74 public: 73 AttributesRecord(PassRefPtr<Node> target, const QualifiedName& name )74 : MutationRecord(target)75 AttributesRecord(PassRefPtr<Node> target, const QualifiedName& name, const AtomicString& oldValue) 76 : m_target(target) 75 77 , m_attributeName(name.localName()) 76 78 , m_attributeNamespace(name.namespaceURI()) 79 , m_oldValue(oldValue) 77 80 { 78 81 } 79 82 80 83 private: 81 virtual const AtomicString& type() ;82 virtual const AtomicString& attributeName() { return m_attributeName; }83 virtual const AtomicString& attributeName space() { return m_attributeNamespace; }84 virtual String oldValue() { return m_oldValue; }85 virtual void setOldValue(const String& value) { m_oldValue = value; }84 virtual const AtomicString& type() OVERRIDE; 85 virtual Node* target() OVERRIDE { return m_target.get(); } 86 virtual const AtomicString& attributeName() OVERRIDE { return m_attributeName; } 87 virtual const AtomicString& attributeNamespace() OVERRIDE { return m_attributeNamespace; } 88 virtual String oldValue() OVERRIDE { return m_oldValue; } 86 89 90 RefPtr<Node> m_target; 87 91 AtomicString m_attributeName; 88 92 AtomicString m_attributeNamespace; 89 String m_oldValue;93 AtomicString m_oldValue; 90 94 }; 91 95 … … 93 97 public: 94 98 CharacterDataRecord(PassRefPtr<Node> target) 95 : MutationRecord(target)99 : m_target(target) 96 100 { 97 101 } 98 102 99 103 private: 100 virtual const AtomicString& type(); 101 virtual String oldValue() { return m_oldValue; } 102 virtual void setOldValue(const String& value) { m_oldValue = value; } 104 virtual const AtomicString& type() OVERRIDE; 105 virtual Node* target() OVERRIDE { return m_target.get(); } 103 106 104 String m_oldValue; 107 RefPtr<Node> m_target; 108 }; 109 110 class MutationRecordWithNullOldValue : public MutationRecord { 111 public: 112 MutationRecordWithNullOldValue(PassRefPtr<MutationRecord> record) 113 : m_record(record) 114 { 115 } 116 117 private: 118 virtual const AtomicString& type() OVERRIDE { return m_record->type(); } 119 virtual Node* target() OVERRIDE { return m_record->target(); } 120 virtual NodeList* addedNodes() OVERRIDE { return m_record->addedNodes(); } 121 virtual NodeList* removedNodes() OVERRIDE { return m_record->removedNodes(); } 122 virtual Node* previousSibling() OVERRIDE { return m_record->previousSibling(); } 123 virtual Node* nextSibling() OVERRIDE { return m_record->nextSibling(); } 124 virtual const AtomicString& attributeName() OVERRIDE { return m_record->attributeName(); } 125 virtual const AtomicString& attributeNamespace() OVERRIDE { return m_record->attributeNamespace(); } 126 127 virtual String oldValue() OVERRIDE { return String(); } 128 129 RefPtr<MutationRecord> m_record; 105 130 }; 106 131 … … 130 155 } 131 156 132 PassRefPtr<MutationRecord> MutationRecord::createAttributes(PassRefPtr<Node> target, const QualifiedName& name )157 PassRefPtr<MutationRecord> MutationRecord::createAttributes(PassRefPtr<Node> target, const QualifiedName& name, const AtomicString& oldValue) 133 158 { 134 return adoptRef(static_cast<MutationRecord*>(new AttributesRecord(target, name )));159 return adoptRef(static_cast<MutationRecord*>(new AttributesRecord(target, name, oldValue))); 135 160 } 136 161 … … 140 165 } 141 166 142 MutationRecord::MutationRecord(PassRefPtr<Node> target) 143 : m_target(target) 167 PassRefPtr<MutationRecord> MutationRecord::createWithNullOldValue(PassRefPtr<MutationRecord> record) 144 168 { 169 return adoptRef(static_cast<MutationRecord*>(new MutationRecordWithNullOldValue(record))); 145 170 } 146 171 -
trunk/Source/WebCore/dom/MutationRecord.h
r97659 r98791 48 48 public: 49 49 static PassRefPtr<MutationRecord> createChildList(PassRefPtr<Node> target, PassRefPtr<NodeList> added, PassRefPtr<NodeList> removed, PassRefPtr<Node> previousSibling, PassRefPtr<Node> nextSibling); 50 static PassRefPtr<MutationRecord> createAttributes(PassRefPtr<Node> target, const QualifiedName& );50 static PassRefPtr<MutationRecord> createAttributes(PassRefPtr<Node> target, const QualifiedName&, const AtomicString& oldValue); 51 51 static PassRefPtr<MutationRecord> createCharacterData(PassRefPtr<Node> target); 52 53 static PassRefPtr<MutationRecord> createWithNullOldValue(PassRefPtr<MutationRecord>); 52 54 53 55 virtual ~MutationRecord(); 54 56 55 57 virtual const AtomicString& type() = 0; 56 Node* target() { return m_target.get(); }58 virtual Node* target() = 0; 57 59 58 60 virtual NodeList* addedNodes() { return 0; } … … 65 67 66 68 virtual String oldValue() { return String(); } 67 virtual void setOldValue(const String&) { }68 69 protected:70 explicit MutationRecord(PassRefPtr<Node> target);71 72 private:73 RefPtr<Node> m_target;74 69 }; 75 76 70 77 71 } // namespace WebCore
Note: See TracChangeset
for help on using the changeset viewer.