Bug 1044736 - Part 2. Add nsIBrowserElementAPI.idl and implement nsBrowserElement. r=bz
authorKan-Ru Chen (陳侃如) <kanru@kanru.info>
Wed, 12 Nov 2014 19:27:31 +0800
changeset 239573 c7c9170ab299698df5fa4ea53e98d39795efeaac
parent 239572 78aacc35b4e7bb3d5221634f315621b298d88f05
child 239574 8ecfc1f41ddc53bd3b480c819e0089403829782f
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1044736
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 1044736 - Part 2. Add nsIBrowserElementAPI.idl and implement nsBrowserElement. r=bz
b2g/installer/package-manifest.in
browser/installer/package-manifest.in
dom/browser-element/moz.build
dom/browser-element/nsIBrowserElementAPI.idl
dom/html/nsBrowserElement.cpp
dom/html/nsBrowserElement.h
dom/html/nsGenericHTMLFrameElement.cpp
dom/html/nsGenericHTMLFrameElement.h
dom/webidl/BrowserElement.webidl
mobile/android/installer/package-manifest.in
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -127,16 +127,17 @@
 #endif
 @BINPATH@/components/accessibility.xpt
 #endif
 @BINPATH@/components/appshell.xpt
 @BINPATH@/components/appstartup.xpt
 @BINPATH@/components/autocomplete.xpt
 @BINPATH@/components/autoconfig.xpt
 @BINPATH@/components/browsercompsbase.xpt
+@BINPATH@/components/browser-element.xpt
 @BINPATH@/components/browser-feeds.xpt
 @BINPATH@/components/caps.xpt
 @BINPATH@/components/chardet.xpt
 @BINPATH@/components/chrome.xpt
 @BINPATH@/components/commandhandler.xpt
 @BINPATH@/components/commandlines.xpt
 @BINPATH@/components/composer.xpt
 @BINPATH@/components/content_events.xpt
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -172,16 +172,17 @@
 @BINPATH@/AccessibleMarshal.dll
 #endif
 @BINPATH@/components/accessibility.xpt
 #endif
 @BINPATH@/components/appshell.xpt
 @BINPATH@/components/appstartup.xpt
 @BINPATH@/components/autocomplete.xpt
 @BINPATH@/components/autoconfig.xpt
+@BINPATH@/components/browser-element.xpt
 @BINPATH@/browser/components/browsercompsbase.xpt
 @BINPATH@/browser/components/browser-feeds.xpt
 @BINPATH@/components/caps.xpt
 @BINPATH@/components/chrome.xpt
 @BINPATH@/components/commandhandler.xpt
 @BINPATH@/components/commandlines.xpt
 @BINPATH@/components/composer.xpt
 @BINPATH@/components/content_events.xpt
--- a/dom/browser-element/moz.build
+++ b/dom/browser-element/moz.build
@@ -7,16 +7,22 @@
 EXPORTS.mozilla += [
     'BrowserElementParent.h',
 ]
 
 SOURCES += [
     'BrowserElementParent.cpp',
 ]
 
+XPIDL_SOURCES += [
+    'nsIBrowserElementAPI.idl',
+]
+
+XPIDL_MODULE = 'browser-element'
+
 EXTRA_COMPONENTS += [
     'BrowserElementParent.js',
     'BrowserElementParent.manifest',
 ]
 
 EXTRA_JS_MODULES += [
     'BrowserElementParent.jsm',
     'BrowserElementPromptService.jsm',
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/nsIBrowserElementAPI.idl
@@ -0,0 +1,74 @@
+/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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 "nsISupports.idl"
+
+interface nsIDOMDOMRequest;
+interface nsIFrameLoader;
+
+[scriptable, function, uuid(c0c2dd9b-41ef-42dd-a4c1-e456619c1941)]
+interface nsIBrowserElementNextPaintListener : nsISupports
+{
+  void recvNextPaint();
+};
+
+%{C++
+#define BROWSER_ELEMENT_API_CONTRACTID "@mozilla.org/dom/browser-element-api;1"
+#define BROWSER_ELEMENT_API_CID                                 \
+    { 0x651db7e3, 0x1734, 0x4536,                               \
+      { 0xb1, 0x5a, 0x5b, 0x3a, 0xe6, 0x44, 0x13, 0x4c } }
+%}
+
+/**
+ * Interface to the BrowserElementParent implementation. All methods
+ * but setFrameLoader throw when the remote process is dead.
+ */
+[scriptable, uuid(abae4fb1-7d6f-4e3f-b435-6501f1d4c659)]
+interface nsIBrowserElementAPI : nsISupports
+{
+  void setFrameLoader(in nsIFrameLoader frameLoader);
+
+  void setVisible(in boolean visible);
+  nsIDOMDOMRequest getVisible();
+  void setActive(in boolean active);
+  boolean getActive();
+
+  void sendMouseEvent(in DOMString type,
+                      in uint32_t x,
+                      in uint32_t y,
+                      in uint32_t button,
+                      in uint32_t clickCount,
+                      in uint32_t mifiers);
+  void sendTouchEvent(in DOMString aType,
+                      [const, array, size_is(count)] in uint32_t aIdentifiers,
+                      [const, array, size_is(count)] in int32_t aXs,
+                      [const, array, size_is(count)] in int32_t aYs,
+                      [const, array, size_is(count)] in uint32_t aRxs,
+                      [const, array, size_is(count)] in uint32_t aRys,
+                      [const, array, size_is(count)] in float aRotationAngles,
+                      [const, array, size_is(count)] in float aForces,
+                      in uint32_t count,
+                      in long aModifiers);
+  void goBack();
+  void goForward();
+  void reload(in boolean hardReload);
+  void stop();
+  nsIDOMDOMRequest download(in DOMString url,
+                            [optional] in jsval options);
+  nsIDOMDOMRequest purgeHistory();
+  nsIDOMDOMRequest getScreenshot(in uint32_t width,
+                                 in uint32_t height,
+                                 [optional] in DOMString mimeType);
+  void zoom(in float zoom);
+  nsIDOMDOMRequest getCanGoBack();
+  nsIDOMDOMRequest getCanGoForward();
+  nsIDOMDOMRequest getContentDimensions();
+
+  void addNextPaintListener(in nsIBrowserElementNextPaintListener listener);
+  void removeNextPaintListener(in nsIBrowserElementNextPaintListener listener);
+
+  nsIDOMDOMRequest setInputMethodActive(in boolean isActive);
+};
--- a/dom/html/nsBrowserElement.cpp
+++ b/dom/html/nsBrowserElement.cpp
@@ -1,168 +1,515 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* 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 "nsBrowserElement.h"
 
+#include "mozilla/Preferences.h"
+#include "mozilla/Services.h"
 #include "mozilla/dom/BrowserElementBinding.h"
 #include "mozilla/dom/DOMRequest.h"
-#include "mozilla/Preferences.h"
+#include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/dom/ToJSValue.h"
+
+#include "nsComponentManagerUtils.h"
+#include "nsContentUtils.h"
+#include "nsFrameLoader.h"
+#include "nsIDOMDOMRequest.h"
+#include "nsIDOMElement.h"
+#include "nsINode.h"
+#include "nsIObserver.h"
+#include "nsIObserverService.h"
+#include "nsIPrincipal.h"
+#include "nsWeakReference.h"
+
+using namespace mozilla::dom;
 
 namespace mozilla {
 
+static const char kRemoteBrowserPending[] = "remote-browser-pending";
+static const char kInprocessBrowserShown[] = "inprocess-browser-shown";
+
+class nsBrowserElement::BrowserShownObserver : public nsIObserver
+                                             , public nsSupportsWeakReference
+{
+public:
+  BrowserShownObserver(nsBrowserElement* aBrowserElement);
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+  void AddObserver();
+  void RemoveObserver();
+private:
+  virtual ~BrowserShownObserver();
+
+  // Weak reference to the browser element. nsBrowserElement has a
+  // reference to us. nsBrowserElement's destructor is responsible to
+  // null out this weak reference via RemoveObserver()
+  nsBrowserElement* mBrowserElement;
+};
+
+NS_IMPL_ISUPPORTS(nsBrowserElement::BrowserShownObserver, nsIObserver, nsISupportsWeakReference)
+
+nsBrowserElement::BrowserShownObserver::BrowserShownObserver(nsBrowserElement* aBrowserElement)
+  : mBrowserElement(aBrowserElement)
+{
+}
+
+nsBrowserElement::BrowserShownObserver::~BrowserShownObserver()
+{
+  RemoveObserver();
+}
+
+NS_IMETHODIMP
+nsBrowserElement::BrowserShownObserver::Observe(nsISupports* aSubject,
+                                                const char* aTopic,
+                                                const char16_t* aData)
+{
+  NS_ENSURE_TRUE(mBrowserElement, NS_OK);
+
+  if (!strcmp(aTopic, kRemoteBrowserPending) ||
+      !strcmp(aTopic, kInprocessBrowserShown)) {
+    nsCOMPtr<nsIFrameLoader> frameLoader = do_QueryInterface(aSubject);
+    nsCOMPtr<nsIFrameLoader> myFrameLoader = mBrowserElement->GetFrameLoader();
+    // The browser element API needs the frameloader to
+    // initialize. We still use the observer to get notified when the
+    // frameloader is created. So we check if the frameloader created
+    // is ours, then initialize the browser element API.
+    if (frameLoader && frameLoader == myFrameLoader) {
+      mBrowserElement->InitBrowserElementAPI();
+    }
+  }
+  return NS_OK;
+}
+
+void
+nsBrowserElement::BrowserShownObserver::AddObserver()
+{
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (obs) {
+    obs->AddObserver(this, kRemoteBrowserPending, true);
+    obs->AddObserver(this, kInprocessBrowserShown, true);
+  }
+}
+
+void
+nsBrowserElement::BrowserShownObserver::RemoveObserver()
+{
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (obs) {
+    obs->RemoveObserver(this, kRemoteBrowserPending);
+    obs->RemoveObserver(this, kInprocessBrowserShown);
+  }
+  mBrowserElement = nullptr;
+}
+
+bool
+nsBrowserElement::IsBrowserElementOrThrow(ErrorResult& aRv)
+{
+  if (mBrowserElementAPI) {
+    return true;
+  }
+  aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
+  return false;
+}
+
+void
+nsBrowserElement::InitBrowserElementAPI()
+{
+  bool isBrowserOrApp;
+  nsCOMPtr<nsIFrameLoader> frameLoader = GetFrameLoader();
+  NS_ENSURE_TRUE_VOID(frameLoader);
+  nsresult rv = frameLoader->GetOwnerIsBrowserOrAppFrame(&isBrowserOrApp);
+  NS_ENSURE_SUCCESS_VOID(rv);
+
+  if (!isBrowserOrApp) {
+    return;
+  }
+
+  mBrowserElementAPI = do_CreateInstance("@mozilla.org/dom/browser-element-api;1");
+  if (mBrowserElementAPI) {
+    mBrowserElementAPI->SetFrameLoader(frameLoader);
+  }
+}
+
+nsBrowserElement::nsBrowserElement()
+{
+  mObserver = new BrowserShownObserver(this);
+  mObserver->AddObserver();
+}
+
+nsBrowserElement::~nsBrowserElement()
+{
+  mObserver->RemoveObserver();
+}
+
 void
 nsBrowserElement::SetVisible(bool aVisible, ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
+
+  nsresult rv = mBrowserElementAPI->SetVisible(aVisible);
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+  }
 }
 
-already_AddRefed<dom::DOMRequest>
+already_AddRefed<DOMRequest>
 nsBrowserElement::GetVisible(ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-  return nullptr;
+  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
+
+  nsCOMPtr<nsIDOMDOMRequest> req;
+  nsresult rv = mBrowserElementAPI->GetVisible(getter_AddRefs(req));
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+
+  return req.forget().downcast<DOMRequest>();
 }
 
 void
 nsBrowserElement::SetActive(bool aVisible, ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
+
+  nsresult rv = mBrowserElementAPI->SetActive(aVisible);
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+  }
 }
 
 bool
 nsBrowserElement::GetActive(ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-  return false;
+  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), false);
+
+  bool isActive;
+  nsresult rv = mBrowserElementAPI->GetActive(&isActive);
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return false;
+  }
+
+  return isActive;
 }
 
 void
 nsBrowserElement::SendMouseEvent(const nsAString& aType,
                                  uint32_t aX,
                                  uint32_t aY,
                                  uint32_t aButton,
                                  uint32_t aClickCount,
                                  uint32_t aModifiers,
                                  ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
+
+  nsresult rv = mBrowserElementAPI->SendMouseEvent(aType,
+                                                   aX,
+                                                   aY,
+                                                   aButton,
+                                                   aClickCount,
+                                                   aModifiers);
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+  }
 }
 
 void
 nsBrowserElement::SendTouchEvent(const nsAString& aType,
-                                 const dom::Sequence<uint32_t>& aIdentifiers,
-                                 const dom::Sequence<int32_t>& aXs,
-                                 const dom::Sequence<int32_t>& aYs,
-                                 const dom::Sequence<uint32_t>& aRxs,
-                                 const dom::Sequence<uint32_t>& aRys,
-                                 const dom::Sequence<float>& aRotationAngles,
-                                 const dom::Sequence<float>& aForces,
+                                 const Sequence<uint32_t>& aIdentifiers,
+                                 const Sequence<int32_t>& aXs,
+                                 const Sequence<int32_t>& aYs,
+                                 const Sequence<uint32_t>& aRxs,
+                                 const Sequence<uint32_t>& aRys,
+                                 const Sequence<float>& aRotationAngles,
+                                 const Sequence<float>& aForces,
                                  uint32_t aCount,
                                  uint32_t aModifiers,
                                  ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
+
+  if (aIdentifiers.Length() != aCount ||
+      aXs.Length() != aCount ||
+      aYs.Length() != aCount ||
+      aRxs.Length() != aCount ||
+      aRys.Length() != aCount ||
+      aRotationAngles.Length() != aCount ||
+      aForces.Length() != aCount) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
+    return;
+  }
+
+  nsresult rv = mBrowserElementAPI->SendTouchEvent(aType,
+                                                   aIdentifiers.Elements(),
+                                                   aXs.Elements(),
+                                                   aYs.Elements(),
+                                                   aRxs.Elements(),
+                                                   aRys.Elements(),
+                                                   aRotationAngles.Elements(),
+                                                   aForces.Elements(),
+                                                   aCount,
+                                                   aModifiers);
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+  }
 }
 
 void
 nsBrowserElement::GoBack(ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
+
+  nsresult rv = mBrowserElementAPI->GoBack();
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+  }
 }
 
 void
 nsBrowserElement::GoForward(ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
+
+  nsresult rv = mBrowserElementAPI->GoForward();
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+  }
 }
 
 void
 nsBrowserElement::Reload(bool aHardReload, ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
+
+  nsresult rv = mBrowserElementAPI->Reload(aHardReload);
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+  }
 }
 
 void
 nsBrowserElement::Stop(ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
+
+  nsresult rv = mBrowserElementAPI->Stop();
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+  }
 }
 
-already_AddRefed<dom::DOMRequest>
+already_AddRefed<DOMRequest>
 nsBrowserElement::Download(const nsAString& aUrl,
-                           const dom::BrowserElementDownloadOptions& aOptions,
+                           const BrowserElementDownloadOptions& aOptions,
                            ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-  return nullptr;
+  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
+
+  nsCOMPtr<nsIDOMDOMRequest> req;
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JS::Rooted<JS::Value> options(jsapi.cx());
+  if (!ToJSValue(jsapi.cx(), aOptions, &options)) {
+    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return nullptr;
+  }
+  nsresult rv = mBrowserElementAPI->Download(aUrl, options, getter_AddRefs(req));
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+
+  return req.forget().downcast<DOMRequest>();
 }
 
-already_AddRefed<dom::DOMRequest>
+already_AddRefed<DOMRequest>
 nsBrowserElement::PurgeHistory(ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-  return nullptr;
+  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
+
+  nsCOMPtr<nsIDOMDOMRequest> req;
+  nsresult rv = mBrowserElementAPI->PurgeHistory(getter_AddRefs(req));
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+
+  return req.forget().downcast<DOMRequest>();
 }
 
-already_AddRefed<dom::DOMRequest>
+already_AddRefed<DOMRequest>
 nsBrowserElement::GetScreenshot(uint32_t aWidth,
                                 uint32_t aHeight,
-                                const dom::Optional<nsAString>& aMimeType,
+                                const nsAString& aMimeType,
                                 ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-  return nullptr;
+  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
+
+  nsCOMPtr<nsIDOMDOMRequest> req;
+  nsresult rv = mBrowserElementAPI->GetScreenshot(aWidth, aHeight, aMimeType,
+                                                  getter_AddRefs(req));
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    if (rv == NS_ERROR_INVALID_ARG) {
+      aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
+    } else {
+      aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    }
+    return nullptr;
+  }
+
+  return req.forget().downcast<DOMRequest>();
 }
 
 void
 nsBrowserElement::Zoom(float aZoom, ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
+  nsresult rv = mBrowserElementAPI->Zoom(aZoom);
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+  }
 }
 
-already_AddRefed<dom::DOMRequest>
+already_AddRefed<DOMRequest>
 nsBrowserElement::GetCanGoBack(ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-  return nullptr;
+  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
+
+  nsCOMPtr<nsIDOMDOMRequest> req;
+  nsresult rv = mBrowserElementAPI->GetCanGoBack(getter_AddRefs(req));
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+
+  return req.forget().downcast<DOMRequest>();
 }
 
-already_AddRefed<dom::DOMRequest>
+already_AddRefed<DOMRequest>
 nsBrowserElement::GetCanGoForward(ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-  return nullptr;
+  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
+
+  nsCOMPtr<nsIDOMDOMRequest> req;
+  nsresult rv = mBrowserElementAPI->GetCanGoForward(getter_AddRefs(req));
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+
+  return req.forget().downcast<DOMRequest>();
 }
 
-already_AddRefed<dom::DOMRequest>
+already_AddRefed<DOMRequest>
 nsBrowserElement::GetContentDimensions(ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-  return nullptr;
+  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
+
+  nsCOMPtr<nsIDOMDOMRequest> req;
+  nsresult rv = mBrowserElementAPI->GetContentDimensions(getter_AddRefs(req));
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+
+  return req.forget().downcast<DOMRequest>();
 }
 
 void
-nsBrowserElement::AddNextPaintListener(dom::BrowserElementNextPaintEventCallback& aListener,
+nsBrowserElement::AddNextPaintListener(BrowserElementNextPaintEventCallback& aListener,
                                        ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
+
+  CallbackObjectHolder<BrowserElementNextPaintEventCallback,
+                       nsIBrowserElementNextPaintListener> holder(&aListener);
+  nsCOMPtr<nsIBrowserElementNextPaintListener> listener = holder.ToXPCOMCallback();
+
+  nsresult rv = mBrowserElementAPI->AddNextPaintListener(listener);
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+  }
 }
 
 void
-nsBrowserElement::RemoveNextPaintListener(dom::BrowserElementNextPaintEventCallback& aListener,
+nsBrowserElement::RemoveNextPaintListener(BrowserElementNextPaintEventCallback& aListener,
                                           ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
+
+  CallbackObjectHolder<BrowserElementNextPaintEventCallback,
+                       nsIBrowserElementNextPaintListener> holder(&aListener);
+  nsCOMPtr<nsIBrowserElementNextPaintListener> listener = holder.ToXPCOMCallback();
+
+  nsresult rv = mBrowserElementAPI->RemoveNextPaintListener(listener);
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+  }
 }
 
-already_AddRefed<dom::DOMRequest>
+already_AddRefed<DOMRequest>
 nsBrowserElement::SetInputMethodActive(bool aIsActive,
                                        ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-  return nullptr;
+  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
+
+  nsCOMPtr<nsIFrameLoader> frameLoader = GetFrameLoader();
+  if (!frameLoader) {
+    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIDOMElement> ownerElement;
+  nsresult rv = frameLoader->GetOwnerElement(getter_AddRefs(ownerElement));
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return nullptr;
+  }
+
+  nsCOMPtr<nsINode> node = do_QueryInterface(ownerElement);
+  nsCOMPtr<nsIPrincipal> principal = node->NodePrincipal();
+  if (!nsContentUtils::IsExactSitePermAllow(principal, "input-manage")) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIDOMDOMRequest> req;
+  rv = mBrowserElementAPI->SetInputMethodActive(aIsActive,
+                                                getter_AddRefs(req));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    if (rv == NS_ERROR_INVALID_ARG) {
+      aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
+    } else {
+      aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    }
+    return nullptr;
+  }
+
+  return req.forget().downcast<DOMRequest>();
 }
 
 } // namespace mozilla
--- a/dom/html/nsBrowserElement.h
+++ b/dom/html/nsBrowserElement.h
@@ -5,16 +5,20 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsBrowserElement_h
 #define nsBrowserElement_h
 
 #include "mozilla/dom/BindingDeclarations.h"
 
 #include "nsCOMPtr.h"
+#include "nsIBrowserElementAPI.h"
+
+class nsFrameLoader;
+class nsIObserver;
 
 namespace mozilla {
 
 namespace dom {
 struct BrowserElementDownloadOptions;
 class BrowserElementNextPaintEventCallback;
 class DOMRequest;
 } // namespace dom
@@ -22,16 +26,19 @@ class DOMRequest;
 class ErrorResult;
 
 /**
  * A helper class for browser-element frames
  */
 class nsBrowserElement
 {
 public:
+  nsBrowserElement();
+  virtual ~nsBrowserElement();
+
   void SetVisible(bool aVisible, ErrorResult& aRv);
   already_AddRefed<dom::DOMRequest> GetVisible(ErrorResult& aRv);
   void SetActive(bool aActive, ErrorResult& aRv);
   bool GetActive(ErrorResult& aRv);
 
   void SendMouseEvent(const nsAString& aType,
                       uint32_t aX,
                       uint32_t aY,
@@ -60,29 +67,41 @@ public:
            const dom::BrowserElementDownloadOptions& options,
            ErrorResult& aRv);
 
   already_AddRefed<dom::DOMRequest> PurgeHistory(ErrorResult& aRv);
 
   already_AddRefed<dom::DOMRequest>
   GetScreenshot(uint32_t aWidth,
                 uint32_t aHeight,
-                const dom::Optional<nsAString>& aMimeType,
+                const nsAString& aMimeType,
                 ErrorResult& aRv);
 
   void Zoom(float aZoom, ErrorResult& aRv);
 
   already_AddRefed<dom::DOMRequest> GetCanGoBack(ErrorResult& aRv);
   already_AddRefed<dom::DOMRequest> GetCanGoForward(ErrorResult& aRv);
   already_AddRefed<dom::DOMRequest> GetContentDimensions(ErrorResult& aRv);
 
   void AddNextPaintListener(dom::BrowserElementNextPaintEventCallback& listener,
                             ErrorResult& aRv);
   void RemoveNextPaintListener(dom::BrowserElementNextPaintEventCallback& listener,
                                ErrorResult& aRv);
 
   already_AddRefed<dom::DOMRequest> SetInputMethodActive(bool isActive,
                                                          ErrorResult& aRv);
+
+protected:
+  NS_IMETHOD_(already_AddRefed<nsFrameLoader>) GetFrameLoader() = 0;
+  nsCOMPtr<nsIBrowserElementAPI> mBrowserElementAPI;
+
+private:
+  void InitBrowserElementAPI();
+  bool IsBrowserElementOrThrow(ErrorResult& aRv);
+
+  class BrowserShownObserver;
+  friend class BrowserShownObserver;
+  nsRefPtr<BrowserShownObserver> mObserver;
 };
 
 } // namespace mozilla
 
 #endif // nsBrowserElement_h
--- a/dom/html/nsGenericHTMLFrameElement.cpp
+++ b/dom/html/nsGenericHTMLFrameElement.cpp
@@ -29,16 +29,17 @@
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
                                                   nsGenericHTMLElement)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserElementAPI)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_ADDREF_INHERITED(nsGenericHTMLFrameElement, nsGenericHTMLElement)
 NS_IMPL_RELEASE_INHERITED(nsGenericHTMLFrameElement, nsGenericHTMLElement)
 
 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsGenericHTMLFrameElement)
   NS_INTERFACE_TABLE_INHERITED(nsGenericHTMLFrameElement,
                                nsIDOMMozBrowserFrame,
--- a/dom/html/nsGenericHTMLFrameElement.h
+++ b/dom/html/nsGenericHTMLFrameElement.h
@@ -29,16 +29,17 @@ class nsGenericHTMLFrameElement : public
                                   public mozilla::nsBrowserElement,
                                   public nsIMozBrowserFrame
 {
 public:
   nsGenericHTMLFrameElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
                             mozilla::dom::FromParser aFromParser)
     : nsGenericHTMLElement(aNodeInfo)
     , nsElementFrameLoaderOwner(aFromParser)
+    , nsBrowserElement()
   {
   }
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMMOZBROWSERFRAME
   NS_DECL_NSIMOZBROWSERFRAME
 
@@ -69,16 +70,29 @@ public:
   virtual int32_t TabIndexDefault() MOZ_OVERRIDE;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsGenericHTMLFrameElement,
                                                      nsGenericHTMLElement)
 
   static bool BrowserFramesEnabled();
 
   /**
+   * nsIFrameLoaderOwner defines two GetFrameLoader() overloads. One
+   * is XPCOM style interface, the other one is C++ only.  "using" pulls
+   * them both in, now GetFrameLoader() is ambiguous because
+   * nsBrowserElement also has GetFrameLoader(). Explicit redefine
+   * GetFrameLoader() to choose nsElementFrameLoaderOwner::GetFrameLoader()
+   */
+  using nsElementFrameLoaderOwner::GetFrameLoader;
+  NS_IMETHOD_(already_AddRefed<nsFrameLoader>) GetFrameLoader() MOZ_OVERRIDE
+  {
+    return nsElementFrameLoaderOwner::GetFrameLoader();
+  }
+
+  /**
    * Helper method to map a HTML 'scrolling' attribute value to a nsIScrollable
    * enum value.  scrolling="no" (and its synonyms) maps to
    * nsIScrollable::Scrollbar_Never, and anything else (including nullptr) maps
    * to nsIScrollable::Scrollbar_Auto.
    * @param aValue the attribute value to map or nullptr
    * @return nsIScrollable::Scrollbar_Never or nsIScrollable::Scrollbar_Auto
    */
   static int32_t MapScrollingAttribute(const nsAttrValue* aValue);
--- a/dom/webidl/BrowserElement.webidl
+++ b/dom/webidl/BrowserElement.webidl
@@ -108,17 +108,17 @@ interface BrowserElementPrivileged {
    CheckPermissions="browser"]
   DOMRequest purgeHistory();
 
   [Throws,
    Pref="dom.mozBrowserFramesEnabled",
    CheckPermissions="browser"]
   DOMRequest getScreenshot([EnforceRange] unsigned long width,
                            [EnforceRange] unsigned long height,
-                           optional DOMString mimeType);
+                           optional DOMString mimeType="");
 
   [Throws,
    Pref="dom.mozBrowserFramesEnabled",
    CheckPermissions="browser"]
   void zoom(float zoom);
 
   [Throws,
    Pref="dom.mozBrowserFramesEnabled",
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -112,16 +112,17 @@
 #ifdef ACCESSIBILITY
 @BINPATH@/components/accessibility.xpt
 #endif
 @BINPATH@/components/appshell.xpt
 @BINPATH@/components/appstartup.xpt
 @BINPATH@/components/autocomplete.xpt
 @BINPATH@/components/autoconfig.xpt
 @BINPATH@/components/browsercompsbase.xpt
+@BINPATH@/components/browser-element.xpt
 @BINPATH@/components/browser-feeds.xpt
 @BINPATH@/components/caps.xpt
 @BINPATH@/components/chardet.xpt
 @BINPATH@/components/chrome.xpt
 @BINPATH@/components/commandhandler.xpt
 @BINPATH@/components/commandlines.xpt
 @BINPATH@/components/composer.xpt
 @BINPATH@/components/content_events.xpt