Bug 1178513 - Add <extapp> element and interfaces to be used by ACL. r=khuey
authorWilliam Chen <wchen@mozilla.com>
Tue, 30 Jun 2015 11:27:57 -0700
changeset 251034 26b00bd0c546d31f5d900414c6e9b85a21a55520
parent 251033 687e3629e5d8fb4057ca53d74dde7d0efd7c6c2a
child 251035 e09f1f4c063092bdd90e3f64a8216bf8c0e58e12
push id61744
push userwchen@mozilla.com
push dateThu, 02 Jul 2015 00:43:50 +0000
treeherdermozilla-inbound@26b00bd0c546 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs1178513
milestone42.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 1178513 - Add <extapp> element and interfaces to be used by ACL. r=khuey
dom/apps/PermissionsTable.jsm
dom/base/nsGkAtomList.h
dom/html/HTMLExtAppElement.cpp
dom/html/HTMLExtAppElement.h
dom/html/moz.build
dom/html/nsGenericHTMLElement.h
dom/html/test/mochitest.ini
dom/html/test/test_extapp.html
dom/tests/mochitest/general/test_interfaces.html
dom/webidl/ExternalAppEvent.webidl
dom/webidl/HTMLExtAppElement.webidl
dom/webidl/moz.build
editor/libeditor/nsHTMLEditUtils.cpp
parser/htmlparser/nsElementTable.cpp
parser/htmlparser/nsHTMLTagList.h
parser/htmlparser/nsHTMLTags.cpp
xpcom/system/moz.build
xpcom/system/nsIExternalApplication.idl
--- a/dom/apps/PermissionsTable.jsm
+++ b/dom/apps/PermissionsTable.jsm
@@ -537,16 +537,22 @@ this.PermissionsTable =  { geolocation: 
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
                            "inputport": {
                              app: DENY_ACTION,
                              trusted: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
+                           },
+                           "external-app": {
+                             app: DENY_ACTION,
+                             trusted: DENY_ACTION,
+                             privileged: ALLOW_ACTION,
+                             certified: ALLOW_ACTION
                            }
                          };
 
 /**
  * Append access modes to the permission name as suffixes.
  *   e.g. permission name 'contacts' with ['read', 'write'] =
  *   ['contacts-read', contacts-write']
  * @param string aPermName
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -361,16 +361,17 @@ GK_ATOM(equalsize, "equalsize")
 GK_ATOM(error, "error")
 GK_ATOM(even, "even")
 GK_ATOM(event, "event")
 GK_ATOM(events, "events")
 GK_ATOM(excludeResultPrefixes, "exclude-result-prefixes")
 GK_ATOM(excludes, "excludes")
 GK_ATOM(expr, "expr")
 GK_ATOM(expectingSystemMessage, "expecting-system-message")
+GK_ATOM(extapp, "extapp")
 GK_ATOM(extends, "extends")
 GK_ATOM(extensionElementPrefixes, "extension-element-prefixes")
 GK_ATOM(face, "face")
 GK_ATOM(fallback, "fallback")
 GK_ATOM(_false, "false")
 GK_ATOM(farthest, "farthest")
 GK_ATOM(field, "field")
 GK_ATOM(fieldset, "fieldset")
new file mode 100644
--- /dev/null
+++ b/dom/html/HTMLExtAppElement.cpp
@@ -0,0 +1,185 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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 "mozilla/dom/HTMLExtAppElement.h"
+#include "mozilla/dom/HTMLUnknownElement.h"
+#include "mozilla/dom/HTMLExtAppElementBinding.h"
+#include "mozilla/dom/ExternalAppEvent.h"
+
+#include "nsGkAtoms.h"
+#include "nsIAtom.h"
+#include "nsIPermissionManager.h"
+#include "nsStyleConsts.h"
+#include "nsRuleData.h"
+
+nsGenericHTMLElement*
+NS_NewHTMLExtAppElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
+                        mozilla::dom::FromParser aFromParser) {
+  // Return HTMLUnknownElement if the document doesn't have the 'external-app' permission.
+  nsCOMPtr<nsIPermissionManager> permissionManager =
+    mozilla::services::GetPermissionManager();
+  nsRefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
+  nsIPrincipal* principal = ni->GetDocument()->NodePrincipal();
+
+  already_AddRefed<mozilla::dom::NodeInfo> aarni = ni.forget();
+
+  if (!permissionManager) {
+    return new HTMLUnknownElement(aarni);
+  }
+
+  uint32_t perm = nsIPermissionManager::UNKNOWN_ACTION;
+  permissionManager->TestExactPermissionFromPrincipal(principal,
+                                                      "external-app",
+                                                      &perm);
+  if (perm != nsIPermissionManager::ALLOW_ACTION) {
+    return new HTMLUnknownElement(aarni);
+  }
+
+  return new HTMLExtAppElement(aarni);
+}
+
+namespace mozilla {
+namespace dom {
+
+HTMLExtAppElement::HTMLExtAppElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
+  : nsGenericHTMLElement(aNodeInfo)
+{
+  mCustomEventDispatch = new nsCustomEventDispatch(this);
+  mCustomPropertyBag = new nsCustomPropertyBag();
+
+  nsCOMPtr<nsIExternalApplication> app =
+    do_CreateInstance(NS_EXTERNALAPP_CONTRACTID);
+  if (app) {
+    nsresult rv = app->Init(OwnerDoc()->GetInnerWindow(), mCustomPropertyBag, mCustomEventDispatch);
+    if (NS_SUCCEEDED(rv)) {
+      mApp = app;
+    }
+  }
+}
+
+HTMLExtAppElement::~HTMLExtAppElement()
+{
+  mCustomEventDispatch->ClearEventTarget();
+}
+
+void
+HTMLExtAppElement::GetCustomProperty(const nsAString& aName, nsString& aReturn)
+{
+  mCustomPropertyBag->GetCustomProperty(aName, aReturn);
+}
+
+void
+HTMLExtAppElement::PostMessage(const nsAString& aMessage, ErrorResult& aRv)
+{
+  if (!mApp) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
+
+  aRv = mApp->PostMessage(aMessage);
+}
+
+NS_IMPL_ADDREF_INHERITED(HTMLExtAppElement, Element)
+NS_IMPL_RELEASE_INHERITED(HTMLExtAppElement, Element)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLExtAppElement)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLExtAppElement,
+                                                nsGenericHTMLElement)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLExtAppElement,
+                                                  nsGenericHTMLElement)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+// QueryInterface implementation for HTMLExtAppElement
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLExtAppElement)
+NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
+
+NS_IMPL_ELEMENT_CLONE(HTMLExtAppElement)
+
+JSObject*
+HTMLExtAppElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return HTMLExtAppElementBinding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace dom
+} // namespace mozilla
+
+NS_IMPL_ISUPPORTS(nsCustomPropertyBag, nsICustomPropertyBag)
+
+nsCustomPropertyBag::nsCustomPropertyBag()
+{
+}
+
+nsCustomPropertyBag::~nsCustomPropertyBag()
+{
+}
+
+NS_IMETHODIMP
+nsCustomPropertyBag::SetProperty(const nsAString& aName, const nsAString& aValue)
+{
+  mBag.Put(nsString(aName), new nsString(aValue));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCustomPropertyBag::RemoveProperty(const nsAString& aName)
+{
+  mBag.Remove(nsString(aName));
+  return NS_OK;
+}
+
+void
+nsCustomPropertyBag::GetCustomProperty(const nsAString& aName, nsString& aReturn)
+{
+  nsString* value;
+  if (!mBag.Get(nsString(aName), &value)) {
+    aReturn.Truncate();
+    return;
+  }
+
+  MOZ_ASSERT(value);
+  aReturn.Assign(*value);
+}
+
+NS_IMPL_ISUPPORTS(nsCustomEventDispatch, nsICustomEventDispatch)
+
+nsCustomEventDispatch::nsCustomEventDispatch(mozilla::dom::EventTarget* aEventTarget)
+  : mEventTarget(aEventTarget)
+{
+  MOZ_ASSERT(mEventTarget);
+}
+
+void
+nsCustomEventDispatch::ClearEventTarget()
+{
+  mEventTarget = nullptr;
+}
+
+nsCustomEventDispatch::~nsCustomEventDispatch()
+{
+}
+
+NS_IMETHODIMP
+nsCustomEventDispatch::DispatchExternalEvent(const nsAString& value)
+{
+  if (!mEventTarget) {
+    return NS_OK;
+  }
+
+  mozilla::dom::ExternalAppEventInit init;
+  init.mData = value;
+
+  nsRefPtr<mozilla::dom::ExternalAppEvent> event =
+    mozilla::dom::ExternalAppEvent::Constructor(mEventTarget,
+                                                NS_LITERAL_STRING("externalappevent"),
+                                                init);
+
+  bool defaultActionEnabled;
+  return mEventTarget->DispatchEvent(event, &defaultActionEnabled);
+}
new file mode 100644
--- /dev/null
+++ b/dom/html/HTMLExtAppElement.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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/. */
+
+#ifndef mozilla_dom_HTMLExtAppElement_h
+#define mozilla_dom_HTMLExtAppElement_h
+
+#include "nsGenericHTMLElement.h"
+#include "nsIExternalApplication.h"
+
+class nsCustomEventDispatch;
+class nsCustomPropertyBag;
+
+namespace mozilla {
+namespace dom {
+
+class HTMLExtAppElement final : public nsGenericHTMLElement
+{
+public:
+  explicit HTMLExtAppElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
+
+  // nsISupports
+  NS_DECL_ISUPPORTS_INHERITED
+
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLExtAppElement,
+                                           nsGenericHTMLElement)
+
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+
+  void GetCustomProperty(const nsAString& aName, nsString& aReturn);
+  void PostMessage(const nsAString& aMessage, ErrorResult& aRv);
+
+protected:
+  virtual ~HTMLExtAppElement();
+
+  virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  nsRefPtr<nsCustomEventDispatch> mCustomEventDispatch;
+  nsRefPtr<nsCustomPropertyBag> mCustomPropertyBag;
+  nsCOMPtr<nsIExternalApplication> mApp;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+class nsCustomEventDispatch final : public nsICustomEventDispatch
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSICUSTOMEVENTDISPATCH
+
+  explicit nsCustomEventDispatch(mozilla::dom::EventTarget* aEventTarget);
+  void ClearEventTarget();
+
+private:
+  ~nsCustomEventDispatch();
+
+  // Weak pointer, this object is owned by the event target.
+  mozilla::dom::EventTarget* mEventTarget;
+};
+
+class nsCustomPropertyBag final : public nsICustomPropertyBag
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSICUSTOMPROPERTYBAG
+
+  nsCustomPropertyBag();
+  void GetCustomProperty(const nsAString& aName, nsString& aReturn);
+
+private:
+  ~nsCustomPropertyBag();
+
+  nsClassHashtable<nsStringHashKey, nsString> mBag;
+};
+
+#endif // mozilla_dom_HTMLExtAppElement_h
--- a/dom/html/moz.build
+++ b/dom/html/moz.build
@@ -52,16 +52,17 @@ EXPORTS.mozilla.dom += [
     'HTMLBodyElement.h',
     'HTMLBRElement.h',
     'HTMLButtonElement.h',
     'HTMLCanvasElement.h',
     'HTMLContentElement.h',
     'HTMLDataElement.h',
     'HTMLDataListElement.h',
     'HTMLDivElement.h',
+    'HTMLExtAppElement.h',
     'HTMLFieldSetElement.h',
     'HTMLFontElement.h',
     'HTMLFormControlsCollection.h',
     'HTMLFormElement.h',
     'HTMLFrameElement.h',
     'HTMLFrameSetElement.h',
     'HTMLHeadingElement.h',
     'HTMLHRElement.h',
@@ -129,16 +130,17 @@ UNIFIED_SOURCES += [
     'HTMLBRElement.cpp',
     'HTMLButtonElement.cpp',
     'HTMLCanvasElement.cpp',
     'HTMLContentElement.cpp',
     'HTMLDataElement.cpp',
     'HTMLDataListElement.cpp',
     'HTMLDivElement.cpp',
     'HTMLElement.cpp',
+    'HTMLExtAppElement.cpp',
     'HTMLFieldSetElement.cpp',
     'HTMLFontElement.cpp',
     'HTMLFormControlsCollection.cpp',
     'HTMLFormElement.cpp',
     'HTMLFrameElement.cpp',
     'HTMLFrameSetElement.cpp',
     'HTMLHeadingElement.cpp',
     'HTMLHRElement.cpp',
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -1737,16 +1737,17 @@ NS_DECLARE_NS_NEW_HTML_ELEMENT(BR)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Body)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Button)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Canvas)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Content)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Mod)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Data)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(DataList)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Div)
+NS_DECLARE_NS_NEW_HTML_ELEMENT(ExtApp)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(FieldSet)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Font)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Form)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Frame)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(FrameSet)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(HR)
 NS_DECLARE_NS_NEW_HTML_ELEMENT_AS_SHARED(Head)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Heading)
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -589,9 +589,10 @@ skip-if = buildapp == 'b2g' || e10s
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || e10s #Bug 931116, b2g desktop specific, initial triage
 support-files = file_bug871161-1.html file_bug871161-2.html
 [test_bug1013316.html]
 [test_hash_encoded.html]
 [test_bug1081037.html]
 [test_window_open_close.html]
 skip-if = buildapp == 'b2g' # bug 1129014
 [test_img_complete.html]
-[test_viewport_resize.html]
\ No newline at end of file
+[test_viewport_resize.html]
+[test_extapp.html]
new file mode 100644
--- /dev/null
+++ b/dom/html/test/test_extapp.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for extapp element being HTMLUnknownElement when permission is not available</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+  assert_true(document.createElement("extapp") instanceof HTMLUnknownElement);
+}, "extapp should be HTMLUnknownElement when external-app permission is not enabled.");
+</script>
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -436,16 +436,18 @@ var interfaceNamesInGlobalScope =
     "Event",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "EventSource",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "EventTarget",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "External", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "ExternalAppEvent", b2g: true, permission: ["external-app"]},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "File",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "FileList",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "FileReader",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "FMRadio", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
@@ -514,16 +516,18 @@ var interfaceNamesInGlobalScope =
     "HTMLDListElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLDocument",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLEmbedElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "HTMLExternalAppElement", b2g: true, permission: ["external-app"]},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLFieldSetElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLFontElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLFormControlsCollection",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLFormElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
new file mode 100644
--- /dev/null
+++ b/dom/webidl/ExternalAppEvent.webidl
@@ -0,0 +1,17 @@
+/* -*- 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/.
+ */
+
+[Constructor(DOMString type, optional ExternalAppEventInit eventInitDict),
+ CheckPermissions="external-app"]
+interface ExternalAppEvent : Event
+{
+  readonly attribute DOMString data;
+};
+
+dictionary ExternalAppEventInit : EventInit
+{
+  DOMString data = "";
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/HTMLExtAppElement.webidl
@@ -0,0 +1,16 @@
+/* -*- 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/.
+ */
+
+[CheckPermissions="external-app"]
+interface HTMLExtAppElement : HTMLElement {
+  // Gets the value of the property from a property bag
+  // that was provided to the external application.
+  DOMString getCustomProperty(DOMString name);
+
+  // Posts a message to the external application.
+  [Throws]
+  void postMessage(DOMString name);
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -179,16 +179,17 @@ WEBIDL_FILES = [
     'HTMLDataElement.webidl',
     'HTMLDataListElement.webidl',
     'HTMLDirectoryElement.webidl',
     'HTMLDivElement.webidl',
     'HTMLDListElement.webidl',
     'HTMLDocument.webidl',
     'HTMLElement.webidl',
     'HTMLEmbedElement.webidl',
+    'HTMLExtAppElement.webidl',
     'HTMLFieldSetElement.webidl',
     'HTMLFontElement.webidl',
     'HTMLFormControlsCollection.webidl',
     'HTMLFormElement.webidl',
     'HTMLFrameElement.webidl',
     'HTMLFrameSetElement.webidl',
     'HTMLHeadElement.webidl',
     'HTMLHeadingElement.webidl',
@@ -739,16 +740,17 @@ GENERATED_EVENTS_WEBIDL_FILES = [
     'DeviceLightEvent.webidl',
     'DeviceOrientationEvent.webidl',
     'DeviceProximityEvent.webidl',
     'DeviceStorageAreaChangedEvent.webidl',
     'DeviceStorageChangeEvent.webidl',
     'DOMTransactionEvent.webidl',
     'DownloadEvent.webidl',
     'ErrorEvent.webidl',
+    'ExternalAppEvent.webidl',
     'HashChangeEvent.webidl',
     'IccChangeEvent.webidl',
     'ImageCaptureErrorEvent.webidl',
     'MediaStreamEvent.webidl',
     'MediaStreamTrackEvent.webidl',
     'MozApplicationEvent.webidl',
     'MozCellBroadcastEvent.webidl',
     'MozClirModeEvent.webidl',
--- a/editor/libeditor/nsHTMLEditUtils.cpp
+++ b/editor/libeditor/nsHTMLEditUtils.cpp
@@ -659,16 +659,17 @@ static const nsElementInfo kElements[eHT
   ELEM(del, true, true, GROUP_PHRASE | GROUP_BLOCK, GROUP_FLOW_ELEMENT),
   ELEM(dfn, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
   ELEM(dir, true, false, GROUP_BLOCK, GROUP_LI),
   ELEM(div, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
   ELEM(dl, true, false, GROUP_BLOCK, GROUP_DL_CONTENT),
   ELEM(dt, true, true, GROUP_DL_CONTENT, GROUP_INLINE_ELEMENT),
   ELEM(em, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
   ELEM(embed, false, false, GROUP_NONE, GROUP_NONE),
+  ELEM(extapp, true, true, GROUP_NONE, GROUP_NONE),
   ELEM(fieldset, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
   ELEM(figcaption, true, false, GROUP_FIGCAPTION, GROUP_FLOW_ELEMENT),
   ELEM(figure, true, true, GROUP_BLOCK,
        GROUP_FLOW_ELEMENT | GROUP_FIGCAPTION),
   ELEM(font, true, true, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
   ELEM(footer, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
   ELEM(form, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
   ELEM(frame, false, false, GROUP_FRAME, GROUP_NONE),
--- a/parser/htmlparser/nsElementTable.cpp
+++ b/parser/htmlparser/nsElementTable.cpp
@@ -167,16 +167,20 @@ const nsHTMLElement gHTMLElements[] = {
     /*tag*/         eHTMLTag_em,
     /*parent,leaf*/ kPhrase, false
   },
   {
     /*tag*/         eHTMLTag_embed,
     /*parent,leaf*/ kSpecial, true
   },
   {
+    /*tag*/         eHTMLTag_extapp,
+    /*parent,leaf*/ kNone, false
+  },
+  {
     /*tag*/         eHTMLTag_fieldset,
     /*parent,leaf*/ kBlock, false
   },
   {
     /*tag*/         eHTMLTag_figcaption,
     /*parent,leaf*/ kPhrase, false
   },
   {
--- a/parser/htmlparser/nsHTMLTagList.h
+++ b/parser/htmlparser/nsHTMLTagList.h
@@ -68,16 +68,17 @@ HTML_HTMLELEMENT_TAG(dd)
 HTML_TAG(del, Mod)
 HTML_HTMLELEMENT_TAG(dfn)
 HTML_TAG(dir, Shared)
 HTML_TAG(div, Div)
 HTML_TAG(dl, SharedList)
 HTML_HTMLELEMENT_TAG(dt)
 HTML_HTMLELEMENT_TAG(em)
 HTML_TAG(embed, SharedObject)
+HTML_TAG(extapp, ExtApp)
 HTML_TAG(fieldset, FieldSet)
 HTML_HTMLELEMENT_TAG(figcaption)
 HTML_HTMLELEMENT_TAG(figure)
 HTML_TAG(font, Font)
 HTML_HTMLELEMENT_TAG(footer)
 HTML_TAG(form, Form)
 HTML_TAG(frame, Frame)
 HTML_TAG(frameset, FrameSet)
--- a/parser/htmlparser/nsHTMLTags.cpp
+++ b/parser/htmlparser/nsHTMLTags.cpp
@@ -88,16 +88,18 @@ static const char16_t sHTMLTagUnicodeNam
 static const char16_t sHTMLTagUnicodeName_dl[] =
   {'d', 'l', '\0'};
 static const char16_t sHTMLTagUnicodeName_dt[] =
   {'d', 't', '\0'};
 static const char16_t sHTMLTagUnicodeName_em[] =
   {'e', 'm', '\0'};
 static const char16_t sHTMLTagUnicodeName_embed[] =
   {'e', 'm', 'b', 'e', 'd', '\0'};
+static const char16_t sHTMLTagUnicodeName_extapp[] =
+  {'e', 'x', 't', 'a', 'p', 'p', '\0'};
 static const char16_t sHTMLTagUnicodeName_fieldset[] =
   {'f', 'i', 'e', 'l', 'd', 's', 'e', 't', '\0'};
 static const char16_t sHTMLTagUnicodeName_figcaption[] =
   {'f', 'i', 'g', 'c', 'a', 'p', 't', 'i', 'o', 'n', '\0'};
 static const char16_t sHTMLTagUnicodeName_figure[] =
   {'f', 'i', 'g', 'u', 'r', 'e', '\0'};
 static const char16_t sHTMLTagUnicodeName_font[] =
   {'f', 'o', 'n', 't', '\0'};
--- a/xpcom/system/moz.build
+++ b/xpcom/system/moz.build
@@ -2,16 +2,17 @@
 # vim: set filetype=python:
 # 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/.
 
 XPIDL_SOURCES += [
     'nsIBlocklistService.idl',
     'nsIDeviceSensors.idl',
+    'nsIExternalApplication.idl',
     'nsIGConfService.idl',
     'nsIGeolocationProvider.idl',
     'nsIGIOService.idl',
     'nsIGSettingsService.idl',
     'nsIHapticFeedback.idl',
     'nsIPackageKitService.idl',
     'nsIXULAppInfo.idl',
     'nsIXULRuntime.idl',
new file mode 100644
--- /dev/null
+++ b/xpcom/system/nsIExternalApplication.idl
@@ -0,0 +1,31 @@
+/* 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 nsPIDOMWindow;
+
+[builtinclass, uuid(adf6b501-609a-4f54-ac16-39b54d6358b5)]
+interface nsICustomEventDispatch : nsISupports {
+  // Dispatches an event named "externalappevent" with the data
+  // in a property named "data" on the event.
+  void dispatchExternalEvent(in AString data);
+};
+
+[builtinclass, uuid(4d797f32-a24d-4cbc-b608-1eb0fc8e442b)]
+interface nsICustomPropertyBag : nsISupports {
+  void setProperty(in AString name, in AString value);
+  void removeProperty(in AString name);
+};
+
+[builtinclass, uuid(c100de94-e699-4941-b528-eaff1af5b15c)]
+interface nsIExternalApplication : nsISupports {
+  void init(in nsPIDOMWindow window, in nsICustomPropertyBag bag, in nsICustomEventDispatch callback);
+  void postMessage(in AString message);
+};
+
+%{C++
+#define NS_EXTERNALAPP_CONTRACTID "@mozilla.org/externalapp;1"
+#define NS_EXTERNALAPP_CID {0x8ec5dce2, 0x67e1, 0x49cd, {0xa0, 0x12, 0xf9, 0xfe, 0x32, 0x00, 0xd0, 0x8e}}
+%}