Bug 973638, update MutationObserver.observe() to follow the spec, r=baku
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Thu, 23 Oct 2014 14:11:40 +0300
changeset 211911 dc8d30fd13e7cb05a73e492126ad0f6b5592da93
parent 211910 9e943a95a25c8122bb78a6fae95842c2061c0838
child 211912 2340c1d21e94d56517970e03ad993d692d2a5af2
push id27693
push userryanvm@gmail.com
push dateThu, 23 Oct 2014 18:06:22 +0000
treeherdermozilla-central@d8de0d7e52e0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs973638
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 973638, update MutationObserver.observe() to follow the spec, r=baku
content/base/src/nsDOMMutationObserver.cpp
content/base/test/test_mutationobservers.html
dom/webidl/MutationObserver.webidl
testing/web-platform/meta/dom/nodes/MutationObserver-attributes.html.ini
testing/web-platform/meta/dom/nodes/MutationObserver-characterData.html.ini
--- a/content/base/src/nsDOMMutationObserver.cpp
+++ b/content/base/src/nsDOMMutationObserver.cpp
@@ -448,56 +448,92 @@ nsDOMMutationObserver::RescheduleForRun(
 }
 
 void
 nsDOMMutationObserver::Observe(nsINode& aTarget,
                                const mozilla::dom::MutationObserverInit& aOptions,
                                mozilla::ErrorResult& aRv)
 {
 
-  if (!(aOptions.mChildList || aOptions.mAttributes || aOptions.mCharacterData)) {
-    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+  bool childList = aOptions.mChildList;
+  bool attributes =
+    aOptions.mAttributes.WasPassed() &&
+    aOptions.mAttributes.Value();
+  bool characterData =
+    aOptions.mCharacterData.WasPassed() &&
+    aOptions.mCharacterData.Value();
+  bool subtree = aOptions.mSubtree;
+  bool attributeOldValue =
+    aOptions.mAttributeOldValue.WasPassed() &&
+    aOptions.mAttributeOldValue.Value();
+  bool characterDataOldValue =
+    aOptions.mCharacterDataOldValue.WasPassed() &&
+    aOptions.mCharacterDataOldValue.Value();
+
+  if (!aOptions.mAttributes.WasPassed() &&
+      (aOptions.mAttributeOldValue.WasPassed() ||
+       aOptions.mAttributeFilter.WasPassed())) {
+    attributes = true;
+  }
+
+  if (!aOptions.mCharacterData.WasPassed() &&
+      aOptions.mCharacterDataOldValue.WasPassed()) {
+    characterData = true;
+  }
+
+  if (!(childList || attributes || characterData)) {
+    aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
     return;
   }
-  if (aOptions.mAttributeOldValue && !aOptions.mAttributes) {
-    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+
+  if (aOptions.mAttributeOldValue.WasPassed() &&
+      aOptions.mAttributeOldValue.Value() &&
+      aOptions.mAttributes.WasPassed() &&
+      !aOptions.mAttributes.Value()) {
+    aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
     return;
   }
-  if (aOptions.mCharacterDataOldValue && !aOptions.mCharacterData) {
-    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+
+  if (aOptions.mAttributeFilter.WasPassed() &&
+      aOptions.mAttributes.WasPassed() &&
+      !aOptions.mAttributes.Value()) {
+    aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
+    return;
+  }
+
+  if (aOptions.mCharacterDataOldValue.WasPassed() &&
+      aOptions.mCharacterDataOldValue.Value() &&
+      aOptions.mCharacterData.WasPassed() &&
+      !aOptions.mCharacterData.Value()) {
+    aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
     return;
   }
 
   nsCOMArray<nsIAtom> filters;
   bool allAttrs = true;
   if (aOptions.mAttributeFilter.WasPassed()) {
     allAttrs = false;
     const mozilla::dom::Sequence<nsString>& filtersAsString =
       aOptions.mAttributeFilter.Value();
     uint32_t len = filtersAsString.Length();
-
-    if (len != 0 && !aOptions.mAttributes) {
-      aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
-      return;
-    }
     filters.SetCapacity(len);
 
     for (uint32_t i = 0; i < len; ++i) {
       nsCOMPtr<nsIAtom> a = do_GetAtom(filtersAsString[i]);
       filters.AppendObject(a);
     }
   }
 
   nsMutationReceiver* r = GetReceiverFor(&aTarget, true);
-  r->SetChildList(aOptions.mChildList);
-  r->SetAttributes(aOptions.mAttributes);
-  r->SetCharacterData(aOptions.mCharacterData);
-  r->SetSubtree(aOptions.mSubtree);
-  r->SetAttributeOldValue(aOptions.mAttributeOldValue);
-  r->SetCharacterDataOldValue(aOptions.mCharacterDataOldValue);
+  r->SetChildList(childList);
+  r->SetAttributes(attributes);
+  r->SetCharacterData(characterData);
+  r->SetSubtree(subtree);
+  r->SetAttributeOldValue(attributeOldValue);
+  r->SetCharacterDataOldValue(characterDataOldValue);
   r->SetAttributeFilter(filters);
   r->SetAllAttributes(allAttrs);
   r->RemoveClones();
 
 #ifdef DEBUG
   for (int32_t i = 0; i < mReceivers.Count(); ++i) {
     NS_WARN_IF_FALSE(mReceivers[i]->Target(),
                      "All the receivers should have a target!");
@@ -536,21 +572,21 @@ nsDOMMutationObserver::TakeRecords(
 void
 nsDOMMutationObserver::GetObservingInfo(nsTArray<Nullable<MutationObservingInfo> >& aResult)
 {
   aResult.SetCapacity(mReceivers.Count());
   for (int32_t i = 0; i < mReceivers.Count(); ++i) {
     MutationObservingInfo& info = aResult.AppendElement()->SetValue();
     nsMutationReceiver* mr = mReceivers[i];
     info.mChildList = mr->ChildList();
-    info.mAttributes = mr->Attributes();
-    info.mCharacterData = mr->CharacterData();
+    info.mAttributes.Construct(mr->Attributes());
+    info.mCharacterData.Construct(mr->CharacterData());
     info.mSubtree = mr->Subtree();
-    info.mAttributeOldValue = mr->AttributeOldValue();
-    info.mCharacterDataOldValue = mr->CharacterDataOldValue();
+    info.mAttributeOldValue.Construct(mr->AttributeOldValue());
+    info.mCharacterDataOldValue.Construct(mr->CharacterDataOldValue());
     nsCOMArray<nsIAtom>& filters = mr->AttributeFilter();
     if (filters.Count()) {
       info.mAttributeFilter.Construct();
       mozilla::dom::Sequence<nsString>& filtersAsStrings =
         info.mAttributeFilter.Value();
       for (int32_t j = 0; j < filters.Count(); ++j) {
         filtersAsStrings.AppendElement(nsDependentAtomString(filters[j]));
       }
--- a/content/base/test/test_mutationobservers.html
+++ b/content/base/test/test_mutationobservers.html
@@ -96,56 +96,49 @@ function runTest() {
 
   var e = null;
   try {
     m.observe(document, {});
   } catch (ex) {
     e = ex;
   }
   ok(e, "Should have thrown an exception");
-  is(e.name, "SyntaxError", "Should have thrown SyntaxError");
-  is(e.code, DOMException.SYNTAX_ERR, "Should have thrown DOMException.SYNTAX_ERR");
+  is(e.name, "TypeError", "Should have thrown TypeError");
 
   e = null;
   try {
     m.observe(document, { childList: true, attributeOldValue: true });
   } catch (ex) {
     e = ex;
   }
-  ok(e, "Should have thrown an exception");
-  is(e.name, "SyntaxError", "Should have thrown SyntaxError");
-  is(e.code, DOMException.SYNTAX_ERR, "Should have thrown DOMException.SYNTAX_ERR");
+  ok(!e, "Shouldn't have thrown an exception");
 
   e = null;
   try {
     m.observe(document, { childList: true, attributeFilter: ["foo"] });
   } catch (ex) {
     e = ex;
   }
-  ok(e, "Should have thrown an exception");
-  is(e.name, "SyntaxError", "Should have thrown SyntaxError");
-  is(e.code, DOMException.SYNTAX_ERR, "Should have thrown DOMException.SYNTAX_ERR");
+  ok(!e, "Shouldn't have thrown an exception");
 
   e = null;
   try {
     m.observe(document, { childList: true, characterDataOldValue: true });
   } catch (ex) {
     e = ex;
   }
-  ok(e, "Should have thrown an exception");
-  is(e.name, "SyntaxError", "Should have thrown SyntaxError");
-  is(e.code, DOMException.SYNTAX_ERR, "Should have thrown DOMException.SYNTAX_ERR");
+  ok(!e, "Shouldn't have thrown an exception");
 
   e = null;
   try {
     m.observe(document);
   } catch (ex) {
     e = ex;
   }
-  ok(e, "Should have thrown an exception");  
+  ok(e, "Should have thrown an exception");
 
   m = new M(function(records, observer) {
       is(observer, m, "2nd parameter should be the mutation observer");
       is(observer, this, "2nd parameter should be 'this'");
       is(records.length, 1, "Should have one record.");
       is(records[0].type, "attributes", "Should have got attributes record");
       is(records[0].target, div, "Should have got div as target");
       is(records[0].attributeName, "foo", "Should have got record about foo attribute");
--- a/dom/webidl/MutationObserver.webidl
+++ b/dom/webidl/MutationObserver.webidl
@@ -42,20 +42,20 @@ interface MutationObserver {
   [ChromeOnly]
   readonly attribute MutationCallback mutationCallback;
 };
 
 callback MutationCallback = void (sequence<MutationRecord> mutations, MutationObserver observer);
 
 dictionary MutationObserverInit {
   boolean childList = false;
-  boolean attributes = false;
-  boolean characterData = false;
+  boolean attributes;
+  boolean characterData;
   boolean subtree = false;
-  boolean attributeOldValue = false;
-  boolean characterDataOldValue = false;
+  boolean attributeOldValue;
+  boolean characterDataOldValue;
   sequence<DOMString> attributeFilter;
 };
 
 dictionary MutationObservingInfo : MutationObserverInit
 {
   Node? observedNode = null;
 };
deleted file mode 100644
--- a/testing/web-platform/meta/dom/nodes/MutationObserver-attributes.html.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[MutationObserver-attributes.html]
-  type: testharness
-  [attributeOldValue alone Element.id: update mutation]
-    expected: FAIL
-
-  [attributeFilter alone Element.id/Element.className: multiple filter update mutation]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/dom/nodes/MutationObserver-characterData.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[MutationObserver-characterData.html]
-  type: testharness
-  [characterData/characterDataOldValue alone Text.data: simple mutation]
-    expected: FAIL
-