merge m-c to fx-team
authorTim Taubert <tim.taubert@gmx.de>
Sun, 01 Apr 2012 18:52:12 +0200
changeset 94114 0e959c772e5fa7d3285d8c9eb1456dee19ce4964
parent 94110 dd21f16d11dae6542beb1adae795ea018838dfeb (current diff)
parent 94113 9669e95f51abcbd1cc27232c63941b433d7ade2c (diff)
child 94115 ba43d5d6a6c300f6ba1c0eb21cd0df6483728434
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone14.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
merge m-c to fx-team
dom/base/nsGlobalWindow.cpp
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8525,27 +8525,22 @@ nsGlobalWindow::Observe(nsISupports* aSu
 
     nsCOMPtr<nsIDOMStorage> changingStorage;
     rv = event->GetStorageArea(getter_AddRefs(changingStorage));
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(changingStorage);
     nsPIDOMStorage::nsDOMStorageType storageType = pistorage->StorageType();
 
+    bool fireMozStorageChanged = false;
     principal = GetPrincipal();
     switch (storageType)
     {
     case nsPIDOMStorage::SessionStorage:
     {
-      if (SameCOMIdentity(mSessionStorage, changingStorage)) {
-        // Do not fire any events for the same storage object, it's not shared
-        // among windows, see nsGlobalWindow::GetSessionStoarge()
-        return NS_OK;
-      }
-
       nsCOMPtr<nsIDOMStorage> storage = mSessionStorage;
       if (!storage) {
         nsIDocShell* docShell = GetDocShell();
         if (principal && docShell) {
           // No need to pass documentURI here, it's only needed when we want
           // to create a new storage, the third paramater would be true
           docShell->GetSessionStorageForPrincipal(principal,
                                                   EmptyString(),
@@ -8561,43 +8556,57 @@ nsGlobalWindow::Observe(nsISupports* aSu
       }
 
 #ifdef PR_LOGGING
       if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
         PR_LogPrint("nsGlobalWindow %p with sessionStorage %p passing event from %p", this, mSessionStorage.get(), pistorage.get());
       }
 #endif
 
+      fireMozStorageChanged = SameCOMIdentity(mSessionStorage, changingStorage);
       break;
     }
     case nsPIDOMStorage::LocalStorage:
     {
-      if (SameCOMIdentity(mLocalStorage, changingStorage)) {
-        // Do not fire any events for the same storage object, it's not shared
-        // among windows, see nsGlobalWindow::GetLocalStoarge()
-        return NS_OK;
-      }
-
       // Allow event fire only for the same principal storages
       // XXX We have to use EqualsIgnoreDomain after bug 495337 lands
       nsIPrincipal *storagePrincipal = pistorage->Principal();
       bool equals;
 
       rv = storagePrincipal->Equals(principal, &equals);
       NS_ENSURE_SUCCESS(rv, rv);
 
       if (!equals)
         return NS_OK;
 
+      fireMozStorageChanged = SameCOMIdentity(mLocalStorage, changingStorage);
       break;
     }
     default:
       return NS_OK;
     }
 
+    // Clone the storage event included in the observer notification. We want
+    // to dispatch clones rather than the original event.
+    rv = CloneStorageEvent(fireMozStorageChanged ?
+                           NS_LITERAL_STRING("MozStorageChanged") :
+                           NS_LITERAL_STRING("storage"),
+                           event);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    privateEvent->SetTrusted(true);
+
+    if (fireMozStorageChanged) {
+      nsEvent *internalEvent = privateEvent->GetInternalNSEvent();
+      internalEvent->flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
+    }
+
     if (IsFrozen()) {
       // This window is frozen, rather than firing the events here,
       // store the domain in which the change happened and fire the
       // events if we're ever thawed.
 
       mPendingStorageEvents.AppendObject(event);
       return NS_OK;
     }
@@ -8623,16 +8632,48 @@ nsGlobalWindow::Observe(nsISupports* aSu
 
     return NS_OK;
   }
 
   NS_WARNING("unrecognized topic in nsGlobalWindow::Observe");
   return NS_ERROR_FAILURE;
 }
 
+nsresult
+nsGlobalWindow::CloneStorageEvent(const nsAString& aType,
+                                  nsCOMPtr<nsIDOMStorageEvent>& aEvent)
+{
+  nsresult rv;
+
+  bool canBubble;
+  bool cancelable;
+  nsAutoString key;
+  nsAutoString oldValue;
+  nsAutoString newValue;
+  nsAutoString url;
+  nsCOMPtr<nsIDOMStorage> storageArea;
+
+  nsCOMPtr<nsIDOMEvent> domEvent = do_QueryInterface(aEvent, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  domEvent->GetBubbles(&canBubble);
+  domEvent->GetCancelable(&cancelable);
+
+  aEvent->GetKey(key);
+  aEvent->GetOldValue(oldValue);
+  aEvent->GetNewValue(newValue);
+  aEvent->GetUrl(url);
+  aEvent->GetStorageArea(getter_AddRefs(storageArea));
+
+  aEvent = new nsDOMStorageEvent();
+  return aEvent->InitStorageEvent(aType, canBubble, cancelable,
+                                  key, oldValue, newValue,
+                                  url, storageArea);
+}
+
 static PLDHashOperator
 FirePendingStorageEvents(const nsAString& aKey, bool aData, void *userArg)
 {
   nsGlobalWindow *win = static_cast<nsGlobalWindow *>(userArg);
 
   nsCOMPtr<nsIDOMStorage> storage;
   win->GetSessionStorage(getter_AddRefs(storage));
 
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -801,16 +801,18 @@ protected:
   virtual void UpdateParentTarget();
 
   bool GetIsTabModalPromptAllowed();
 
   inline PRInt32 DOMMinTimeoutValue() const;
 
   nsresult CreateOuterObject(nsGlobalWindow* aNewInner);
   nsresult SetOuterObject(JSContext* aCx, JSObject* aOuterObject);
+  nsresult CloneStorageEvent(const nsAString& aType,
+                             nsCOMPtr<nsIDOMStorageEvent>& aEvent);
 
   // When adding new member variables, be careful not to create cycles
   // through JavaScript.  If there is any chance that a member variable
   // could own objects that are implemented in JavaScript, then those
   // objects will keep the global object (this object) alive.  To prevent
   // these cycles, ownership of such members must be released in
   // |CleanUp| and |SetDocShell|.
 
--- a/dom/tests/mochitest/localstorage/test_localStorageBase.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageBase.html
@@ -2,16 +2,18 @@
 <head>
 <title>localStorage basic test</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
+var MOZ_STORAGE_CHANGED_COUNT = 14;
+
 function startTest()
 {
   // Initially check the localStorage is empty
   is(localStorage.length, 0, "The storage is empty [1]");
   is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
   is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
   is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
@@ -21,16 +23,27 @@ function startTest()
 
   is(typeof localStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
   is(typeof localStorage["nonexisting"], "object", "['nonexisting'] is object");
   is(typeof localStorage.nonexisting, "object", "nonexisting is object");
   is(typeof localStorage.getItem("nonexisting2"), "object", "getItem('nonexisting2') is object");
   is(typeof localStorage["nonexisting2"], "object", "['nonexisting2'] is object");
   is(typeof localStorage.nonexisting2, "object", "nonexisting2 is object");
 
+  var mozStorageChangedReceived = 0;
+  var localStorageCopy = localStorage;
+
+  function onStorageChanged(e) {
+    if (e.storageArea == localStorageCopy)
+      mozStorageChangedReceived++;
+  }
+
+  // Listen for MozStorageChanged
+  SpecialPowers.addChromeEventListener("MozStorageChanged", onStorageChanged, false);
+
   // add an empty-value key
   localStorage.setItem("empty", "");
   is(localStorage.getItem("empty"), "", "Empty value (getItem())");
   is(localStorage["empty"], "", "Empty value (array access)");
   is(localStorage.empty, "", "Empty value (property access)");
   is(typeof localStorage.getItem("empty"), "string", "getItem('empty') is string");
   is(typeof localStorage["empty"], "string", "['empty'] is string");
   is(typeof localStorage.empty, "string", "empty is string");
@@ -156,18 +169,24 @@ function startTest()
   is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null");
   is(localStorage.getItem("key1"), null, "key1 removed");
   is(localStorage.getItem("key2"), null, "key2 removed");
   localStorage.removeItem("nonexisting"); // Just check there is no exception
   localStorage.removeItem("key1"); // Just check there is no exception
   localStorage.removeItem("key2"); // Just check there is no exception
 
-  localStorage.clear();
-  SimpleTest.finish();
+  SimpleTest.executeSoon(function () {
+    SpecialPowers.removeChromeEventListener("MozStorageChanged", onStorageChanged, false);
+    is(mozStorageChangedReceived, MOZ_STORAGE_CHANGED_COUNT,
+       "received the correct number of events");
+
+    localStorage.clear();
+    SimpleTest.finish();
+  });
 }
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 
 </head>
 
--- a/dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html
+++ b/dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html
@@ -2,20 +2,25 @@
 <head>
 <title>sessionStorage basic test</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
+var MOZ_STORAGE_CHANGED_COUNT = 8;
+
+function setup() {
+  sessionStorage.clear();
+  SimpleTest.executeSoon(startTest);
+}
+
 function startTest()
 {
-  sessionStorage.clear();
-  
   // Initially check the sessionStorage is empty
   is(sessionStorage.length, 0, "The storage is empty [1]");
   is(sessionStorage.key(0), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.key(-1), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
   is(sessionStorage["nonexisting"], null, "Nonexisting item is null (array access)");
   is(sessionStorage.nonexisting, null, "Nonexisting item is null (property access)");
@@ -23,16 +28,27 @@ function startTest()
 
   is(typeof sessionStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
   is(typeof sessionStorage["nonexisting"], "object", "['nonexisting'] is object");
   is(typeof sessionStorage.nonexisting, "object", "nonexisting is object");
   is(typeof sessionStorage.getItem("nonexisting2"), "object", "getItem('nonexisting2') is object");
   is(typeof sessionStorage["nonexisting2"], "object", "['nonexisting2'] is object");
   is(typeof sessionStorage.nonexisting2, "object", "nonexisting2 is object");
 
+  var mozStorageChangedReceived = 0;
+  var sessionStorageCopy = sessionStorage;
+
+  function onStorageChanged(e) {
+    if (e.storageArea == sessionStorageCopy)
+      mozStorageChangedReceived++;
+  }
+
+  // Listen for MozStorageChanged
+  SpecialPowers.addChromeEventListener("MozStorageChanged", onStorageChanged, false);
+
   // add an empty-value key
   sessionStorage.setItem("empty", "");
   is(sessionStorage.getItem("empty"), "", "Empty value (getItem())");
   is(sessionStorage["empty"], "", "Empty value (array access)");
   is(sessionStorage.empty, "", "Empty value (property access)");
   is(typeof sessionStorage.getItem("empty"), "string", "getItem('empty') is string");
   is(typeof sessionStorage["empty"], "string", "['empty'] is string");
   is(typeof sessionStorage.empty, "string", "empty is string");
@@ -125,21 +141,28 @@ function startTest()
   is(sessionStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("nonexisting"), null, "Nonexisting item is null");
   is(sessionStorage.getItem("key1"), null, "key1 removed");
   is(sessionStorage.getItem("key2"), null, "key2 removed");
   sessionStorage.removeItem("nonexisting"); // Just check there is no exception
   sessionStorage.removeItem("key1"); // Just check there is no exception
   sessionStorage.removeItem("key2"); // Just check there is no exception
 
-  SimpleTest.finish();
+  SimpleTest.executeSoon(function () {
+    SpecialPowers.removeChromeEventListener("MozStorageChanged", onStorageChanged, false);
+    is(mozStorageChangedReceived, MOZ_STORAGE_CHANGED_COUNT,
+       "received the correct number of events");
+
+    sessionStorage.clear();
+    SimpleTest.finish();
+  });
 }
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 
 </head>
 
-<body onload="startTest();">
+<body onload="setup();">
 
 </body>
 </html>