Bug 859707. Convert History to WebIDL bindings. r=bz
authorJohnny Stenback <jst@mozilla.com>
Fri, 09 Aug 2013 23:47:59 -0700
changeset 142166 debcebc0d7ee2b8f82e5a269d9d00882334c7842
parent 142165 b1f332685dcd852a5c54ae7a9fcdf06e536f3590
child 142167 524c84f5a735eb12435c51fef2bb1f57ea30fedc
push id25084
push usercbook@mozilla.com
push dateMon, 12 Aug 2013 09:28:56 +0000
treeherdermozilla-central@f057fca09627 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs859707
milestone26.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 859707. Convert History to WebIDL bindings. r=bz
docshell/base/nsDocShell.cpp
docshell/base/nsIDocShell.idl
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/base/nsGlobalWindow.cpp
dom/base/nsHistory.cpp
dom/base/nsHistory.h
dom/base/nsStructuredCloneContainer.cpp
dom/bindings/Bindings.conf
dom/interfaces/base/domstubs.idl
dom/interfaces/base/nsIDOMHistory.idl
dom/interfaces/base/nsIDOMWindow.idl
dom/interfaces/base/nsIStructuredCloneContainer.idl
dom/tests/mochitest/bugs/test_bug664737.html
dom/webidl/History.webidl
dom/webidl/WebIDL.mk
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -10240,17 +10240,17 @@ nsDocShell::SetReferrerURI(nsIURI * aURI
     mReferrerURI = aURI;        // This assigment addrefs
 }
 
 //*****************************************************************************
 // nsDocShell: Session History
 //*****************************************************************************
 
 NS_IMETHODIMP
-nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
+nsDocShell::AddState(const JS::Value &aData, const nsAString& aTitle,
                      const nsAString& aURL, bool aReplace, JSContext* aCx)
 {
     // Implements History.pushState and History.replaceState
 
     // Here's what we do, roughly in the order specified by HTML5:
     // 1. Serialize aData using structured clone.
     // 2. If the third argument is present,
     //     a. Resolve the url, relative to the first script's base URL
@@ -10299,32 +10299,32 @@ nsDocShell::AddState(nsIVariant *aData, 
     NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
 
     // Step 1: Serialize aData using structured clone.
     nsCOMPtr<nsIStructuredCloneContainer> scContainer;
 
     // scContainer->Init might cause arbitrary JS to run, and this code might
     // navigate the page we're on, potentially to a different origin! (bug
     // 634834)  To protect against this, we abort if our principal changes due
-    // to the InitFromVariant() call.
+    // to the InitFromJSVal() call.
     {
         nsCOMPtr<nsIDocument> origDocument =
             do_GetInterface(GetAsSupports(this));
         if (!origDocument)
             return NS_ERROR_DOM_SECURITY_ERR;
         nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal();
 
         scContainer = new nsStructuredCloneContainer();
         JSContext *cx = aCx;
         nsCxPusher pusher;
         if (!cx) {
             cx = nsContentUtils::GetContextFromDocument(document);
             pusher.Push(cx);
         }
-        rv = scContainer->InitFromVariant(aData, cx);
+        rv = scContainer->InitFromJSVal(aData, cx);
 
         // If we're running in the document's context and the structured clone
         // failed, clear the context's pending exception.  See bug 637116.
         if (NS_FAILED(rv) && !aCx) {
             JS_ClearPendingException(aCx);
         }
         NS_ENSURE_SUCCESS(rv, rv);
 
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -37,17 +37,17 @@ interface nsILayoutHistoryState;
 interface nsISecureBrowserUI;
 interface nsIDOMStorage;
 interface nsIPrincipal;
 interface nsIWebBrowserPrint;
 interface nsIVariant;
 interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
 
-[scriptable, builtinclass, uuid(cdeb1ed0-7794-4e5f-964e-bb9d753d1686)]
+[scriptable, builtinclass, uuid(b5bd6052-ec8c-45bf-b55c-409ad15cecfb)]
 interface nsIDocShell : nsIDocShellTreeItem
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -151,17 +151,17 @@ interface nsIDocShell : nsIDocShellTreeI
                               out nsIDocShell aDocShell,
                               out nsIRequest aRequest);
 
   /**
    * Do either a history.pushState() or history.replaceState() operation,
    * depending on the value of aReplace.
    */
   [implicit_jscontext]
-  void addState(in nsIVariant aData, in DOMString aTitle,
+  void addState(in jsval aData, in DOMString aTitle,
                 in DOMString aURL, in boolean aReplace);
 
   /**
    * Creates a DocShellLoadInfo object that you can manipulate and then pass
    * to loadURI.
    */
   void createLoadInfo(out nsIDocShellLoadInfo loadInfo);
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -49,17 +49,16 @@
 #include "prprf.h"
 #include "nsTArray.h"
 #include "nsCSSValue.h"
 #include "nsThreadUtils.h"
 #include "nsDOMEventTargetHelper.h"
 
 // General helper includes
 #include "nsGlobalWindow.h"
-#include "nsHistory.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMEventListener.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsDOMWindowUtils.h"
@@ -82,17 +81,16 @@
 #include "nsJSEnvironment.h"
 
 // DOM base includes
 #include "nsIDOMLocation.h"
 #include "nsIDOMWindow.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMJSWindow.h"
 #include "nsIDOMWindowCollection.h"
-#include "nsIDOMHistory.h"
 #include "nsIDOMMediaList.h"
 #include "nsIDOMChromeWindow.h"
 #include "nsIDOMConstructor.h"
 
 // DOM core includes
 #include "nsError.h"
 #include "nsIDOMDOMException.h"
 #include "nsIDOMNode.h"
@@ -404,19 +402,16 @@ static nsDOMClassInfoData sClassInfoData
                            DEFAULT_SCRIPTABLE_FLAGS |
                            WINDOW_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(Location, nsLocationSH,
                            ((DOM_DEFAULT_SCRIPTABLE_FLAGS |
                              nsIXPCScriptable::WANT_ADDPROPERTY) &
                             ~nsIXPCScriptable::ALLOW_PROP_MODS_TO_PROTOTYPE))
 
-  NS_DEFINE_CLASSINFO_DATA(History, nsHistorySH,
-                           ARRAY_SCRIPTABLE_FLAGS |
-                           nsIXPCScriptable::WANT_PRECREATE)
   NS_DEFINE_CLASSINFO_DATA(DOMPrototype, nsDOMConstructorSH,
                            DOM_BASE_SCRIPTABLE_FLAGS |
                            nsIXPCScriptable::WANT_PRECREATE |
                            nsIXPCScriptable::WANT_NEWRESOLVE |
                            nsIXPCScriptable::WANT_HASINSTANCE |
                            nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE)
   NS_DEFINE_CLASSINFO_DATA(DOMConstructor, nsDOMConstructorSH,
                            DOM_BASE_SCRIPTABLE_FLAGS |
@@ -1215,20 +1210,16 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(WindowUtils, nsIDOMWindowUtils)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindowUtils)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(Location, nsIDOMLocation)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMLocation)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(History, nsIDOMHistory)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMHistory)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(DOMPrototype, nsIDOMDOMConstructor)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DOMConstructor, nsIDOMDOMConstructor)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
   DOM_CLASSINFO_MAP_END
 
@@ -4663,71 +4654,16 @@ nsStringArraySH::GetProperty(nsIXPConnec
   }
 
   NS_ENSURE_TRUE(xpc::NonVoidStringToJsval(cx, val, vp),
                  NS_ERROR_OUT_OF_MEMORY);
   return NS_SUCCESS_I_DID_SOMETHING;
 }
 
 
-// History helper
-
-NS_IMETHODIMP
-nsHistorySH::PreCreate(nsISupports *nativeObj, JSContext *cx,
-                       JSObject *globalObj, JSObject **parentObj)
-{
-  nsHistory *history = (nsHistory *)((nsIDOMHistory*)nativeObj);
-  nsCOMPtr<nsPIDOMWindow> innerWindow;
-  history->GetWindow(getter_AddRefs(innerWindow));
-  if (!innerWindow) {
-    NS_WARNING("refusing to create history object in the wrong scope");
-    return NS_ERROR_FAILURE;
-  }
-  return SetParentToWindow(static_cast<nsGlobalWindow *>(innerWindow.get()),
-                           parentObj);
-}
-
-NS_IMETHODIMP
-nsHistorySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
-                         JSObject *aObj, jsid aId, jsval *vp, bool *_retval)
-{
-  JS::Rooted<JSObject*> obj(cx, aObj);
-  JS::Rooted<jsid> id(cx, aId);
-  bool is_number = false;
-  GetArrayIndexFromId(cx, id, &is_number);
-
-  if (!is_number) {
-    return NS_OK;
-  }
-
-  return nsStringArraySH::GetProperty(wrapper, cx, obj, id, vp, _retval);
-}
-
-nsresult
-nsHistorySH::GetStringAt(nsISupports *aNative, int32_t aIndex,
-                         nsAString& aResult)
-{
-  if (aIndex < 0) {
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
-  }
-
-  nsCOMPtr<nsIDOMHistory> history(do_QueryInterface(aNative));
-
-  nsresult rv = history->Item(aIndex, aResult);
-#ifdef DEBUG
-  if (DOMStringIsNull(aResult)) {
-    int32_t length = 0;
-    history->GetLength(&length);
-    NS_ASSERTION(aIndex >= length, "Item should only return null for out-of-bounds access");
-  }
-#endif
-  return rv;
-}
-
-
 // MediaList helper
 
 nsresult
 nsMediaListSH::GetStringAt(nsISupports *aNative, int32_t aIndex,
                            nsAString& aResult)
 {
   if (aIndex < 0) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 DOMCI_CLASS(Window)
 DOMCI_CLASS(Location)
-DOMCI_CLASS(History)
 DOMCI_CLASS(DOMPrototype)
 DOMCI_CLASS(DOMConstructor)
 
 // Core classes
 DOMCI_CLASS(DOMException)
 
 DOMCI_CLASS(DeviceAcceleration)
 DOMCI_CLASS(DeviceRotationRate)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -3371,17 +3371,17 @@ nsGlobalWindow::GetScreen(nsIDOMScreen**
   }
 
   NS_IF_ADDREF(*aScreen = mScreen);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsGlobalWindow::GetHistory(nsIDOMHistory** aHistory)
+nsGlobalWindow::GetHistory(nsISupports** aHistory)
 {
   FORWARD_TO_INNER(GetHistory, (aHistory), NS_ERROR_NOT_INITIALIZED);
 
   *aHistory = nullptr;
 
   if (!mHistory) {
     mHistory = new nsHistory(this);
     if (!mHistory) {
--- a/dom/base/nsHistory.cpp
+++ b/dom/base/nsHistory.cpp
@@ -1,230 +1,161 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 sw=2 et tw=78: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsHistory.h"
-
+#include "mozilla/dom/HistoryBinding.h"
 #include "nsCOMPtr.h"
-#include "nscore.h"
 #include "nsPIDOMWindow.h"
-#include "nsIScriptGlobalObject.h"
 #include "nsIDocument.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIDocShell.h"
 #include "nsIWebNavigation.h"
 #include "nsIHistoryEntry.h"
 #include "nsIURI.h"
-#include "nsIServiceManager.h"
 #include "nsIInterfaceRequestorUtils.h"
-#include "nsXPIDLString.h"
 #include "nsReadableUtils.h"
-#include "nsDOMClassInfoID.h"
-#include "nsError.h"
 #include "nsContentUtils.h"
 #include "nsISHistoryInternal.h"
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
-static const char* sAllowPushStatePrefStr  =
+static const char* sAllowPushStatePrefStr =
   "browser.history.allowPushState";
 static const char* sAllowReplaceStatePrefStr =
   "browser.history.allowReplaceState";
 
 //
-//  History class implementation 
+//  History class implementation
 //
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsHistory)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHistory)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHistory)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHistory)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMHistory) // Empty, needed for extension compat
+NS_INTERFACE_MAP_END
+
 nsHistory::nsHistory(nsPIDOMWindow* aInnerWindow)
   : mInnerWindow(do_GetWeakReference(aInnerWindow))
 {
+  SetIsDOMBinding();
 }
 
 nsHistory::~nsHistory()
 {
 }
 
-
-DOMCI_DATA(History, nsHistory)
-
-// QueryInterface implementation for nsHistory
-NS_INTERFACE_MAP_BEGIN(nsHistory)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMHistory)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMHistory)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(History)
-NS_INTERFACE_MAP_END
-
-
-NS_IMPL_ADDREF(nsHistory)
-NS_IMPL_RELEASE(nsHistory)
-
-
-NS_IMETHODIMP
-nsHistory::GetLength(int32_t* aLength)
+nsPIDOMWindow*
+nsHistory::GetParentObject() const
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
-  if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow()))
-    return NS_ERROR_DOM_SECURITY_ERR;
-
-  nsCOMPtr<nsISHistory>   sHistory;
-
-  // Get session History from docshell
-  GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(sHistory));
-  NS_ENSURE_TRUE(sHistory, NS_ERROR_FAILURE);
-  return sHistory->GetCount(aLength);
+  return win;
 }
 
-NS_IMETHODIMP
-nsHistory::GetCurrent(nsAString& aCurrent)
+JSObject*
+nsHistory::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
-  if (!nsContentUtils::IsCallerChrome())
-    return NS_ERROR_DOM_SECURITY_ERR;
-
-  int32_t curIndex=0;
-  nsAutoCString curURL;
-  nsCOMPtr<nsISHistory> sHistory;
-
-  // Get SessionHistory from docshell
-  GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(sHistory));
-  NS_ENSURE_TRUE(sHistory, NS_ERROR_FAILURE);
-
-  // Get the current index at session History
-  sHistory->GetIndex(&curIndex);
-  nsCOMPtr<nsIHistoryEntry> curEntry;
-  nsCOMPtr<nsIURI>     uri;
-
-  // Get the SH entry for the current index
-  sHistory->GetEntryAtIndex(curIndex, false, getter_AddRefs(curEntry));
-  NS_ENSURE_TRUE(curEntry, NS_ERROR_FAILURE);
-
-  // Get the URI for the current entry
-  curEntry->GetURI(getter_AddRefs(uri));
-  NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
-  uri->GetSpec(curURL);
-  CopyUTF8toUTF16(curURL, aCurrent);
-
-  return NS_OK;
+  return HistoryBinding::Wrap(aCx, aScope, this);
 }
 
-NS_IMETHODIMP
-nsHistory::GetPrevious(nsAString& aPrevious)
+uint32_t
+nsHistory::GetLength(ErrorResult& aRv) const
 {
-  if (!nsContentUtils::IsCallerChrome())
-    return NS_ERROR_DOM_SECURITY_ERR;
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
+  if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow())) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
 
-  int32_t curIndex;
-  nsAutoCString prevURL;
-  nsCOMPtr<nsISHistory>  sHistory;
+    return 0;
+  }
 
   // Get session History from docshell
-  GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(sHistory));
-  NS_ENSURE_TRUE(sHistory, NS_ERROR_FAILURE);
+  nsCOMPtr<nsISHistory> sHistory = GetSessionHistory();
+  if (!sHistory) {
+    aRv.Throw(NS_ERROR_FAILURE);
 
-  // Get the current index at session History
-  sHistory->GetIndex(&curIndex);
-  nsCOMPtr<nsIHistoryEntry> prevEntry;
-  nsCOMPtr<nsIURI>     uri;
+    return 0;
+  }
 
-  // Get the previous SH entry
-  sHistory->GetEntryAtIndex((curIndex-1), false, getter_AddRefs(prevEntry));
-  NS_ENSURE_TRUE(prevEntry, NS_ERROR_FAILURE);
+  int32_t len;
+  nsresult rv = sHistory->GetCount(&len);
 
-  // Get the URI for the previous entry
-  prevEntry->GetURI(getter_AddRefs(uri));
-  NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
-  uri->GetSpec(prevURL);
-  CopyUTF8toUTF16(prevURL, aPrevious);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
 
-  return NS_OK;
+    return 0;
+  }
+
+  return len >= 0 ? len : 0;
 }
 
-NS_IMETHODIMP
-nsHistory::GetNext(nsAString& aNext)
-{
-  if (!nsContentUtils::IsCallerChrome())
-    return NS_ERROR_DOM_SECURITY_ERR;
-
-  int32_t curIndex;
-  nsAutoCString nextURL;
-  nsCOMPtr<nsISHistory>  sHistory;
-
-  // Get session History from docshell
-  GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(sHistory));
-  NS_ENSURE_TRUE(sHistory, NS_ERROR_FAILURE);
-
-  // Get the current index at session History
-  sHistory->GetIndex(&curIndex);
-  nsCOMPtr<nsIHistoryEntry> nextEntry;
-  nsCOMPtr<nsIURI>     uri;
-
-  // Get the next SH entry
-  sHistory->GetEntryAtIndex((curIndex+1), false, getter_AddRefs(nextEntry));
-  NS_ENSURE_TRUE(nextEntry, NS_ERROR_FAILURE);
-
-  // Get the URI for the next entry
-  nextEntry->GetURI(getter_AddRefs(uri));
-  NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
-  uri->GetSpec(nextURL); 
-  CopyUTF8toUTF16(nextURL, aNext);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHistory::Back()
+JS::Value
+nsHistory::GetState(JSContext* aCx, ErrorResult& aRv) const
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
-  if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow()))
-    return NS_ERROR_DOM_SECURITY_ERR;
+  if (!win) {
+    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+
+    return JS::UndefinedValue();
+  }
+
+  if (!nsContentUtils::CanCallerAccess(win->GetOuterWindow())) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
 
-  nsCOMPtr<nsISHistory>  sHistory;
+    return JS::UndefinedValue();
+  }
+
+  nsCOMPtr<nsIDocument> doc =
+    do_QueryInterface(win->GetExtantDoc());
+  if (!doc) {
+    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+
+    return JS::UndefinedValue();
+  }
 
-  GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(sHistory));
-  NS_ENSURE_TRUE(sHistory, NS_ERROR_FAILURE);
+  nsCOMPtr<nsIVariant> variant;
+  doc->GetStateObject(getter_AddRefs(variant));
+
+  if (variant) {
+    JS::Rooted<JS::Value> jsData(aCx);
+    aRv = variant->GetAsJSVal(jsData.address());
 
-  //QI SHistory to WebNavigation
-  nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(sHistory));
-  NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
-  webNav->GoBack();
+    if (aRv.Failed()) {
+      return JS::UndefinedValue();
+    }
 
-  return NS_OK;
+    if (!JS_WrapValue(aCx, jsData.address())) {
+      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+      return JS::UndefinedValue();
+    }
+
+    return jsData;
+  }
+
+  return JS::UndefinedValue();
 }
 
-NS_IMETHODIMP
-nsHistory::Forward()
+void
+nsHistory::Go(int32_t aDelta, ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
-  if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow()))
-    return NS_ERROR_DOM_SECURITY_ERR;
-
-  nsCOMPtr<nsISHistory>  sHistory;
-
-  GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(sHistory));
-  NS_ENSURE_TRUE(sHistory, NS_ERROR_FAILURE);
+  if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow())) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
 
-  //QI SHistory to WebNavigation
-  nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(sHistory));
-  NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
-  webNav->GoForward();
-
-  return NS_OK;
-}
+    return;
+  }
 
-NS_IMETHODIMP
-nsHistory::Go(int32_t aDelta)
-{
-  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
-  if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow()))
-    return NS_ERROR_DOM_SECURITY_ERR;
-
-  if (aDelta == 0) {
+  if (!aDelta) {
     nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(GetDocShell()));
 
     if (window && window->IsHandlingResizeEvent()) {
       // history.go(0) (aka location.reload()) was called on a window
       // that is handling a resize event. Sites do this since Netscape
       // 4.x needed it, but we don't, and it's a horrible experience
       // for nothing.  In stead of reloading the page, just clear
       // style data and reflow the page since some sites may use this
@@ -234,175 +165,353 @@ nsHistory::Go(int32_t aDelta)
       nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
 
       nsIPresShell *shell;
       nsPresContext *pcx;
       if (doc && (shell = doc->GetShell()) && (pcx = shell->GetPresContext())) {
         pcx->RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
       }
 
-      return NS_OK;
+      return;
     }
   }
 
-  nsCOMPtr<nsISHistory> session_history;
-
-  GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(session_history));
-  NS_ENSURE_TRUE(session_history, NS_ERROR_FAILURE);
+  nsCOMPtr<nsISHistory> session_history = GetSessionHistory();
+  nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(session_history));
+  if (!webnav) {
+    aRv.Throw(NS_ERROR_FAILURE);
 
-  // QI SHistory to nsIWebNavigation
-  nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(session_history));
-  NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
+    return;
+  }
 
-  int32_t curIndex=-1;
+  int32_t curIndex = -1;
   int32_t len = 0;
   session_history->GetIndex(&curIndex);
   session_history->GetCount(&len);
 
   int32_t index = curIndex + aDelta;
-  if (index > -1  &&  index < len)
+  if (index > -1 && index < len)
     webnav->GotoIndex(index);
 
-  // We always want to return a NS_OK, since returning errors 
+  // Ignore the return value from GotoIndex(), since returning errors
   // from GotoIndex() can lead to exceptions and a possible leak
   // of history length
+}
 
-  return NS_OK;
+void
+nsHistory::Back(ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
+  if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow())) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+
+    return;
+  }
+
+  nsCOMPtr<nsISHistory> sHistory = GetSessionHistory();
+  nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(sHistory));
+  if (!webNav) {
+    aRv.Throw(NS_ERROR_FAILURE);
+
+    return;
+  }
+
+  webNav->GoBack();
+}
+
+void
+nsHistory::Forward(ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
+  if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow())) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+
+    return;
+  }
+
+  nsCOMPtr<nsISHistory> sHistory = GetSessionHistory();
+  nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(sHistory));
+  if (!webNav) {
+    aRv.Throw(NS_ERROR_FAILURE);
+
+    return;
+  }
+
+  webNav->GoForward();
+}
+
+void
+nsHistory::PushState(JSContext* aCx, JS::Handle<JS::Value> aData,
+                     const nsAString& aTitle, const nsAString& aUrl,
+                     ErrorResult& aRv)
+{
+  PushOrReplaceState(aCx, aData, aTitle, aUrl, aRv, false);
+}
+
+void
+nsHistory::ReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
+                        const nsAString& aTitle, const nsAString& aUrl,
+                        ErrorResult& aRv)
+{
+  PushOrReplaceState(aCx, aData, aTitle, aUrl, aRv, true);
 }
 
-NS_IMETHODIMP
-nsHistory::PushState(nsIVariant *aData, const nsAString& aTitle,
-                     const nsAString& aURL, JSContext* aCx)
+void
+nsHistory::GetCurrent(nsString& aRetval, ErrorResult& aRv) const
 {
-  // Check that PushState hasn't been pref'ed off.
-  if (!Preferences::GetBool(sAllowPushStatePrefStr, false)) {
-    return NS_OK;
+  MOZ_ASSERT(nsContentUtils::IsCallerChrome());
+
+  aRetval.Truncate();
+
+  int32_t curIndex = 0;
+  nsAutoCString curURL;
+  nsCOMPtr<nsISHistory> sHistory = GetSessionHistory();
+  if (!sHistory) {
+    aRv.Throw(NS_ERROR_FAILURE);
+
+    return;
+  }
+
+  // Get the current index at session History
+  sHistory->GetIndex(&curIndex);
+  nsCOMPtr<nsIHistoryEntry> curEntry;
+  nsCOMPtr<nsIURI> uri;
+
+  // Get the SH entry for the current index
+  sHistory->GetEntryAtIndex(curIndex, false, getter_AddRefs(curEntry));
+  if (!curEntry) {
+    aRv.Throw(NS_ERROR_FAILURE);
+
+    return;
+  }
+
+  // Get the URI for the current entry
+  curEntry->GetURI(getter_AddRefs(uri));
+  if (!uri) {
+    aRv.Throw(NS_ERROR_FAILURE);
+
+    return;
+  }
+
+  uri->GetSpec(curURL);
+  CopyUTF8toUTF16(curURL, aRetval);
+}
+
+void
+nsHistory::GetPrevious(nsString& aRetval, ErrorResult& aRv) const
+{
+  MOZ_ASSERT(nsContentUtils::IsCallerChrome());
+
+  aRetval.Truncate();
+
+  int32_t curIndex;
+  nsAutoCString prevURL;
+  nsCOMPtr<nsISHistory> sHistory = GetSessionHistory();
+  if (!sHistory) {
+    aRv.Throw(NS_ERROR_FAILURE);
+
+    return;
+  }
+
+  // Get the current index at session History
+  sHistory->GetIndex(&curIndex);
+  nsCOMPtr<nsIHistoryEntry> prevEntry;
+  nsCOMPtr<nsIURI> uri;
+
+  // Get the previous SH entry
+  sHistory->GetEntryAtIndex((curIndex - 1), false, getter_AddRefs(prevEntry));
+  if (!prevEntry) {
+    aRv.Throw(NS_ERROR_FAILURE);
+
+    return;
+  }
+
+  // Get the URI for the previous entry
+  prevEntry->GetURI(getter_AddRefs(uri));
+  if (!uri) {
+    aRv.Throw(NS_ERROR_FAILURE);
+
+    return;
   }
 
-  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
-  if (!win)
-    return NS_ERROR_NOT_AVAILABLE;
+  uri->GetSpec(prevURL);
+  CopyUTF8toUTF16(prevURL, aRetval);
+}
+
+void
+nsHistory::GetNext(nsString& aRetval, ErrorResult& aRv) const
+{
+  MOZ_ASSERT(nsContentUtils::IsCallerChrome());
+
+  aRetval.Truncate();
 
-  if (!nsContentUtils::CanCallerAccess(win->GetOuterWindow()))
-    return NS_ERROR_DOM_SECURITY_ERR;
+  int32_t curIndex;
+  nsAutoCString nextURL;
+  nsCOMPtr<nsISHistory> sHistory = GetSessionHistory();
+  if (!sHistory) {
+    aRv.Throw(NS_ERROR_FAILURE);
+
+    return;
+  }
+
+  // Get the current index at session History
+  sHistory->GetIndex(&curIndex);
+  nsCOMPtr<nsIHistoryEntry> nextEntry;
+  nsCOMPtr<nsIURI> uri;
 
-  // AddState might run scripts, so we need to hold a strong reference to the
-  // docShell here to keep it from going away.
-  nsCOMPtr<nsIDocShell> docShell = win->GetDocShell();
+  // Get the next SH entry
+  sHistory->GetEntryAtIndex((curIndex+1), false, getter_AddRefs(nextEntry));
+  if (!nextEntry) {
+    aRv.Throw(NS_ERROR_FAILURE);
 
-  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
+    return;
+  }
+
+  // Get the URI for the next entry
+  nextEntry->GetURI(getter_AddRefs(uri));
 
-  // false tells the docshell to add a new history entry instead of
-  // modifying the current one.
-  nsresult rv = docShell->AddState(aData, aTitle, aURL, false, aCx);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (!uri) {
+    aRv.Throw(NS_ERROR_FAILURE);
+
+    return;
+  }
 
-  return NS_OK;
+  uri->GetSpec(nextURL);
+  CopyUTF8toUTF16(nextURL, aRetval);
+}
+
+void
+nsHistory::Item(uint32_t aIndex, nsString& aRetval, ErrorResult& aRv)
+{
+  bool unused;
+  IndexedGetter(aIndex, unused, aRetval, aRv);
 }
 
-NS_IMETHODIMP
-nsHistory::ReplaceState(nsIVariant *aData, const nsAString& aTitle,
-                        const nsAString& aURL, JSContext* aCx)
+void
+nsHistory::IndexedGetter(uint32_t aIndex, bool &aFound, nsString& aRetval,
+                         ErrorResult& aRv)
 {
-  // Check that ReplaceState hasn't been pref'ed off
-  if (!Preferences::GetBool(sAllowReplaceStatePrefStr, false)) {
-    return NS_OK;
+  aRetval.Truncate();
+  aFound = false;
+
+  if (!nsContentUtils::IsCallerChrome()) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+
+    return;
+  }
+
+  nsCOMPtr<nsISHistory> session_history = GetSessionHistory();
+  if (!session_history) {
+    aRv.Throw(NS_ERROR_FAILURE);
+
+    return;
+  }
+
+  nsCOMPtr<nsIHistoryEntry> sh_entry;
+  nsCOMPtr<nsIURI> uri;
+
+  aRv = session_history->GetEntryAtIndex(aIndex, false,
+                                         getter_AddRefs(sh_entry));
+
+  if (aRv.Failed()) {
+    return;
+  }
+
+  if (sh_entry) {
+    aRv = sh_entry->GetURI(getter_AddRefs(uri));
   }
 
+  if (uri) {
+    nsAutoCString urlCString;
+    aRv = uri->GetSpec(urlCString);
+
+    if (aRv.Failed()) {
+      return;
+    }
+
+    CopyUTF8toUTF16(urlCString, aRetval);
+
+    aFound = true;
+  }
+}
+
+uint32_t
+nsHistory::Length()
+{
+  if (!nsContentUtils::IsCallerChrome()) {
+    return 0;
+  }
+
+  // Get session History from docshell
+  nsCOMPtr<nsISHistory> sHistory = GetSessionHistory();
+  if (!sHistory) {
+    return 0;
+  }
+
+  int32_t len;
+  nsresult rv = sHistory->GetCount(&len);
+
+  if (NS_FAILED(rv) || len < 0) {
+    return 0;
+  }
+
+  return len;
+}
+
+void
+nsHistory::PushOrReplaceState(JSContext* aCx, JS::Value aData,
+                              const nsAString& aTitle, const nsAString& aUrl,
+                              ErrorResult& aRv, bool aReplace)
+{
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
-  if (!win)
-    return NS_ERROR_NOT_AVAILABLE;
+  if (!win) {
+    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+
+    return;
+  }
+
+  if (!nsContentUtils::CanCallerAccess(win->GetOuterWindow())) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
 
-  if (!nsContentUtils::CanCallerAccess(win->GetOuterWindow()))
-    return NS_ERROR_DOM_SECURITY_ERR;
+    return;
+  }
+
+  // Check that PushState hasn't been pref'ed off.
+  if (!Preferences::GetBool(aReplace ? sAllowReplaceStatePrefStr :
+                            sAllowPushStatePrefStr, false)) {
+    return;
+  }
 
   // AddState might run scripts, so we need to hold a strong reference to the
   // docShell here to keep it from going away.
   nsCOMPtr<nsIDocShell> docShell = win->GetDocShell();
 
-  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
-
-  // true tells the docshell to modify the current SHEntry, rather than
-  // create a new one.
-  return docShell->AddState(aData, aTitle, aURL, true, aCx);
-}
-
-NS_IMETHODIMP
-nsHistory::GetState(nsIVariant **aState)
-{
-  *aState = nullptr;
-
-  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
-  if (!win)
-    return NS_ERROR_NOT_AVAILABLE;
+  if (!docShell) {
+    aRv.Throw(NS_ERROR_FAILURE);
 
-  if (!nsContentUtils::CanCallerAccess(win->GetOuterWindow()))
-    return NS_ERROR_DOM_SECURITY_ERR;
-
-  nsCOMPtr<nsIDocument> doc = win->GetExtantDoc();
-  if (!doc)
-    return NS_ERROR_NOT_AVAILABLE;
-
-  return doc->GetStateObject(aState);
-}
-
-NS_IMETHODIMP
-nsHistory::Item(uint32_t aIndex, nsAString& aReturn)
-{
-  aReturn.Truncate();
-  if (!nsContentUtils::IsCallerChrome()) {
-    return NS_ERROR_DOM_SECURITY_ERR;
+    return;
   }
 
-  nsresult rv = NS_OK;
-  nsCOMPtr<nsISHistory>  session_history;
-
-  GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(session_history));
-  NS_ENSURE_TRUE(session_history, NS_ERROR_FAILURE);
-
-  nsCOMPtr<nsIHistoryEntry> sh_entry;
-  nsCOMPtr<nsIURI> uri;
-
-  rv = session_history->GetEntryAtIndex(aIndex, false,
-                                        getter_AddRefs(sh_entry));
+  // The "replace" argument tells the docshell to whether to add a new
+  // history entry or modify the current one.
 
-  if (sh_entry) {
-    rv = sh_entry->GetURI(getter_AddRefs(uri));
-  }
-
-  if (uri) {
-    nsAutoCString urlCString;
-    rv = uri->GetSpec(urlCString);
-
-    CopyUTF8toUTF16(urlCString, aReturn);
-  }
-
-  return rv;
+  aRv = docShell->AddState(aData, aTitle, aUrl, aReplace, aCx);
 }
 
-nsresult
-nsHistory::GetSessionHistoryFromDocShell(nsIDocShell * aDocShell, 
-                                         nsISHistory ** aReturn)
+already_AddRefed<nsISHistory>
+nsHistory::GetSessionHistory() const
 {
-
-  NS_ENSURE_TRUE(aDocShell, NS_ERROR_FAILURE);
-  /* The docshell we have may or may not be
-   * the root docshell. So, get a handle to
-   * SH from the root docshell
-   */
-  
-  // QI mDocShell to nsIDocShellTreeItem
-  NS_ENSURE_TRUE(aDocShell, NS_ERROR_FAILURE);
+  nsIDocShell *docShell = GetDocShell();
+  NS_ENSURE_TRUE(docShell, nullptr);
 
   // Get the root DocShell from it
   nsCOMPtr<nsIDocShellTreeItem> root;
-  aDocShell->GetSameTypeRootTreeItem(getter_AddRefs(root));
-  NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
-  
-  //QI root to nsIWebNavigation
-  nsCOMPtr<nsIWebNavigation>   webNav(do_QueryInterface(root));
-  NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
+  docShell->GetSameTypeRootTreeItem(getter_AddRefs(root));
+  nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(root));
+  NS_ENSURE_TRUE(webNav, nullptr);
+
+  nsCOMPtr<nsISHistory> shistory;
 
-  //Get  SH from nsIWebNavigation
-  return webNav->GetSessionHistory(aReturn);
-  
+  // Get SH from nsIWebNavigation
+  webNav->GetSessionHistory(getter_AddRefs(shistory));
+
+  return shistory.forget();
 }
-
--- a/dom/base/nsHistory.h
+++ b/dom/base/nsHistory.h
@@ -1,51 +1,75 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 sw=2 et tw=79: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsHistory_h___
 #define nsHistory_h___
 
+#include "mozilla/Attributes.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsWrapperCache.h"
 #include "nsIDOMHistory.h"
-#include "nsISupports.h"
-#include "nscore.h"
-#include "nsIScriptContext.h"
+#include "nsString.h"
 #include "nsISHistory.h"
 #include "nsIWeakReference.h"
 #include "nsPIDOMWindow.h"
 
 class nsIDocShell;
 
 // Script "History" object
-class nsHistory : public nsIDOMHistory
+class nsHistory MOZ_FINAL : public nsIDOMHistory, // Empty, needed for extension
+                                                  // backwards compat
+                            public nsWrapperCache
 {
 public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsHistory)
+
+public:
   nsHistory(nsPIDOMWindow* aInnerWindow);
   virtual ~nsHistory();
 
-  // nsISupports
-  NS_DECL_ISUPPORTS
+  nsPIDOMWindow* GetParentObject() const;
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
-  // nsIDOMHistory
-  NS_DECL_NSIDOMHISTORY
+  uint32_t GetLength(mozilla::ErrorResult& aRv) const;
+  JS::Value GetState(JSContext* aCx, mozilla::ErrorResult& aRv) const;
+  void Go(int32_t aDelta, mozilla::ErrorResult& aRv);
+  void Back(mozilla::ErrorResult& aRv);
+  void Forward(mozilla::ErrorResult& aRv);
+  void PushState(JSContext* aCx, JS::Handle<JS::Value> aData,
+                 const nsAString& aTitle, const nsAString& aUrl,
+                 mozilla::ErrorResult& aRv);
+  void ReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
+                    const nsAString& aTitle, const nsAString& aUrl,
+                    mozilla::ErrorResult& aRv);
+  void GetCurrent(nsString& aRetval, mozilla::ErrorResult& aRv) const;
+  void GetPrevious(nsString& aRetval, mozilla::ErrorResult& aRv) const;
+  void GetNext(nsString& aRetval, mozilla::ErrorResult& aRv) const;
+  void Item(uint32_t aIndex, nsString& aRetval, mozilla::ErrorResult& aRv);
+  void IndexedGetter(uint32_t aIndex, bool &aFound, nsString& aRetval,
+                     mozilla::ErrorResult& aRv);
+  uint32_t Length();
 
-  nsIDocShell *GetDocShell() {
+protected:
+  nsIDocShell *GetDocShell() const {
     nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
     if (!win)
       return nullptr;
     return win->GetDocShell();
   }
 
-  void GetWindow(nsPIDOMWindow **aWindow) {
-    nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
-    *aWindow = win.forget().get();
-  }
+  void PushOrReplaceState(JSContext* aCx, JS::Value aData,
+                          const nsAString& aTitle, const nsAString& aUrl,
+                          mozilla::ErrorResult& aRv, bool aReplace);
 
-protected:
-  nsresult GetSessionHistoryFromDocShell(nsIDocShell * aDocShell,
-                                         nsISHistory ** aReturn);
+  already_AddRefed<nsISHistory> GetSessionHistory() const;
 
   nsCOMPtr<nsIWeakReference> mInnerWindow;
 };
 
 #endif /* nsHistory_h___ */
--- a/dom/base/nsStructuredCloneContainer.cpp
+++ b/dom/base/nsStructuredCloneContainer.cpp
@@ -32,35 +32,30 @@ nsStructuredCloneContainer::nsStructured
 }
 
 nsStructuredCloneContainer::~nsStructuredCloneContainer()
 {
   free(mData);
 }
 
 nsresult
-nsStructuredCloneContainer::InitFromVariant(nsIVariant *aData, JSContext *aCx)
+nsStructuredCloneContainer::InitFromJSVal(const JS::Value & aData,
+                                          JSContext* aCx)
 {
   NS_ENSURE_STATE(!mData);
-  NS_ENSURE_ARG_POINTER(aData);
   NS_ENSURE_ARG_POINTER(aCx);
 
-  // First, try to extract a JS::Value from the variant |aData|.  This works only
-  // if the variant implements GetAsJSVal.
-  JS::Rooted<JS::Value> jsData(aCx);
-  nsresult rv = aData->GetAsJSVal(jsData.address());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
-
   // Make sure that we serialize in the right context.
   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
+  JS::Rooted<JS::Value> jsData(aCx, aData);
   JS_WrapValue(aCx, jsData.address());
 
   uint64_t* jsBytes = nullptr;
   bool success = JS_WriteStructuredClone(aCx, jsData, &jsBytes, &mSize,
-                                           nullptr, nullptr, JSVAL_VOID);
+                                         nullptr, nullptr, JSVAL_VOID);
   NS_ENSURE_STATE(success);
   NS_ENSURE_STATE(jsBytes);
 
   // Copy jsBytes into our own buffer.
   mData = (uint64_t*) malloc(mSize);
   if (!mData) {
     mSize = 0;
     mVersion = 0;
@@ -109,31 +104,33 @@ nsStructuredCloneContainer::DeserializeT
   NS_ENSURE_STATE(mData);
   NS_ENSURE_ARG_POINTER(aData);
   *aData = nullptr;
 
   // Deserialize to a JS::Value.
   JS::Rooted<JS::Value> jsStateObj(aCx);
   bool hasTransferable = false;
   bool success = JS_ReadStructuredClone(aCx, mData, mSize, mVersion,
-                                        jsStateObj.address(), nullptr, nullptr) &&
+                                        jsStateObj.address(), nullptr,
+                                        nullptr) &&
                  JS_StructuredCloneHasTransferables(mData, mSize,
                                                     &hasTransferable);
   // We want to be sure that mData doesn't contain transferable objects
   MOZ_ASSERT(!hasTransferable);
   NS_ENSURE_STATE(success && !hasTransferable);
 
   // Now wrap the JS::Value as an nsIVariant.
   nsCOMPtr<nsIVariant> varStateObj;
   nsCOMPtr<nsIXPConnect> xpconnect = do_GetService(nsIXPConnect::GetCID());
   NS_ENSURE_STATE(xpconnect);
-  xpconnect->JSValToVariant(aCx, jsStateObj.address(), getter_AddRefs(varStateObj));
+  xpconnect->JSValToVariant(aCx, jsStateObj.address(),
+                            getter_AddRefs(varStateObj));
   NS_ENSURE_STATE(varStateObj);
 
-  NS_IF_ADDREF(*aData = varStateObj);
+  NS_ADDREF(*aData = varStateObj);
   return NS_OK;
 }
 
 nsresult
 nsStructuredCloneContainer::GetDataAsBase64(nsAString &aOut)
 {
   NS_ENSURE_STATE(mData);
   aOut.Truncate();
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -411,16 +411,21 @@ DOMInterfaces = {
 'GainNode': {
     'resultNotAddRefed': [ 'gain' ],
 },
 
 'Geolocation': {
     'headerFile': 'nsGeolocation.h'
 },
 
+'History': {
+    'headerFile': 'nsHistory.h',
+    'nativeType': 'nsHistory'
+},
+
 'HTMLAppletElement': {
     'nativeType': 'mozilla::dom::HTMLSharedObjectElement'
 },
 
 'HTMLBaseElement': {
     'nativeType': 'mozilla::dom::HTMLSharedElement'
 },
 
--- a/dom/interfaces/base/domstubs.idl
+++ b/dom/interfaces/base/domstubs.idl
@@ -40,17 +40,16 @@ interface nsIDOMStyleSheetList;
 interface nsIDOMStyleSheet;
 interface nsIDOMMediaList;
 
 // Base
 interface nsIDOMWindow;
 interface nsIDOMWindowCollection;
 interface nsIDOMNavigator;
 interface nsIDOMScreen;
-interface nsIDOMHistory;
 
 // Events
 interface nsIDOMEvent;
 interface nsIDOMEventTarget;
 interface nsIDOMEventListener;
 
 // HTML
 interface nsIDOMHTMLElement;
--- a/dom/interfaces/base/nsIDOMHistory.idl
+++ b/dom/interfaces/base/nsIDOMHistory.idl
@@ -4,34 +4,13 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
 %{ C++
 struct JSContext;
 %}
 
-interface nsIVariant;
-
-[scriptable, uuid(d5a3006b-dd6b-4ba3-81be-6559f8889e60)]
+[scriptable, uuid(55226663-fe68-48ba-addf-08e32eaab569)]
 interface nsIDOMHistory : nsISupports
 {
-  readonly attribute long             length;
-  readonly attribute DOMString        current;
-  readonly attribute DOMString        previous;
-  readonly attribute DOMString        next;
-
-  void                       back();
-  void                       forward();
-
-  void                       go([optional] in long aDelta);
-  DOMString                  item(in unsigned long index);
-  [implicit_jscontext]
-  void                       pushState(in nsIVariant aData,
-                                       in DOMString aTitle,
-                                       [optional] in DOMString aURL);
-  [implicit_jscontext]
-  void                       replaceState(in nsIVariant aData,
-                                          in DOMString aTitle,
-                                          [optional] in DOMString aURL);
-
-  readonly attribute nsIVariant state;
+  // Empty interface that exists only for extension backwards compat
 };
--- a/dom/interfaces/base/nsIDOMWindow.idl
+++ b/dom/interfaces/base/nsIDOMWindow.idl
@@ -20,17 +20,17 @@ interface nsIVariant;
  * The nsIDOMWindow interface is the primary interface for a DOM
  * window object. It represents a single window object that may
  * contain child windows if the document in the window contains a
  * HTML frameset document or if the document contains iframe elements.
  *
  * @see <http://www.whatwg.org/html/#window>
  */
 
-[scriptable, uuid(db8ea3c8-6997-460a-8715-0a1cbf20f15d)]
+[scriptable, uuid(e4610a67-ce3c-4dff-a5cf-b0e858452bf5)]
 interface nsIDOMWindow : nsISupports
 {
   // the current browsing context
   readonly attribute nsIDOMWindow                       window;
 
   /* [replaceable] self */
   readonly attribute nsIDOMWindow                       self;
 
@@ -44,17 +44,17 @@ interface nsIDOMWindow : nsISupports
    *
    * This attribute is "replaceable" in JavaScript
    */
            attribute DOMString                          name;
 
   /* The setter that takes a string argument needs to be special cased! */
   readonly attribute nsIDOMLocation                     location;
 
-  readonly attribute nsIDOMHistory                      history;
+  readonly attribute nsISupports                        history;
 
 
   /* [replaceable] locationbar */
   /* BarProp */
   readonly attribute nsISupports                        locationbar;
 
   /* [replaceable] menubar */
   /* BarProp */
--- a/dom/interfaces/base/nsIStructuredCloneContainer.idl
+++ b/dom/interfaces/base/nsIStructuredCloneContainer.idl
@@ -22,25 +22,25 @@ struct JSContext;
  * initFromVariant or initFromBase64.  It's an error to initialize an
  * nsIStructuredCloneContainer more than once.
  *
  * Once you've initialized the container, you can get a copy of the object it
  * stores by calling deserializeToVariant.  You can also get a base-64-encoded
  * string containing a copy of the container's serialized data, using
  * getDataAsBase64.
  */
-[scriptable, uuid(400a282d-7157-4ed0-85b4-8bdc2fa634cd)]
+[scriptable, uuid(c8852f01-4c05-47c3-acca-253a958f39f6)]
 interface nsIStructuredCloneContainer : nsISupports
 {
   /**
    * Initialize this structured clone container so it contains a clone of the
-   * given variant. aData must be backed by a jsval.
+   * given jsval.
    */
-  [implicit_jscontext]
-  void initFromVariant(in nsIVariant aData);
+  [noscript, implicit_jscontext]
+  void initFromJSVal(in jsval aData);
 
   /**
    * Initialize this structured clone container from a base-64-encoded byte
    * stream, stored in aData.  aFormatVersion should be the version of the
    * structured clone algorithm which was used to generate aData.
    */
   [implicit_jscontext]
   void initFromBase64(in AString aData,in unsigned long aFormatVersion);
--- a/dom/tests/mochitest/bugs/test_bug664737.html
+++ b/dom/tests/mochitest/bugs/test_bug664737.html
@@ -14,26 +14,26 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 664737 **/
-function shouldfail(name) {
+function isUndefined(name) {
     try {
         var rv = history[name];
-        fail(false, "able to access history." + name);
+        is(rv, undefined, "No value found for history." + name);
     } catch (e) {
-        ok(e.message.indexOf("Permission denied") >= 0, "cannot access history." + name);
+        ok(false, "Accessing history." + name + " threw: " + e);
     }
 }
 
-shouldfail("current");
-shouldfail("previous");
-shouldfail("next");
+isUndefined("current");
+isUndefined("previous");
+isUndefined("next");
 
 
 </script>
 </pre>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/webidl/History.webidl
@@ -0,0 +1,39 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://www.whatwg.org/specs/web-apps/current-work/#the-history-interface
+ *
+ *  Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
+ * Opera Software ASA. You are granted a license to use, reproduce
+ * and create derivative works of this document.
+ */
+
+interface History {
+  [Throws]
+  readonly attribute unsigned long length;
+  [Throws]
+  readonly attribute any state;
+  [Throws]
+  void go(optional long delta = 0);
+  [Throws]
+  void back();
+  [Throws]
+  void forward();
+  [Throws]
+  void pushState(any data, DOMString title, optional DOMString? url = null);
+  [Throws]
+  void replaceState(any data, DOMString title, optional DOMString? url = null);
+
+  // Chrome only methods.
+  [Throws, ChromeOnly]
+  readonly attribute DOMString current;
+  [Throws, ChromeOnly]
+  readonly attribute DOMString previous;
+  [Throws, ChromeOnly]
+  readonly attribute DOMString next;
+  [Throws, ChromeOnly]
+  getter DOMString? item(unsigned long index);
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -89,16 +89,17 @@ webidl_files = \
   FileReader.webidl \
   FileReaderSync.webidl \
   FileRequest.webidl \
   FocusEvent.webidl \
   FormData.webidl \
   Function.webidl \
   GainNode.webidl \
   Geolocation.webidl \
+  History.webidl \
   HTMLAnchorElement.webidl \
   HTMLAppletElement.webidl \
   HTMLAreaElement.webidl \
   HTMLAudioElement.webidl \
   HTMLBaseElement.webidl \
   HTMLBodyElement.webidl \
   HTMLBRElement.webidl \
   HTMLButtonElement.webidl \