Bug 1437638, move frame, browser and editor to be based on XULFrameElement, a new subclass of XULElement, r=paolo,bz

This commit is contained in:
Neil Deakin 2018-07-05 20:14:18 -04:00
parent 2cee1b8c81
commit f08f9ce4af
20 changed files with 208 additions and 87 deletions

View File

@ -34,7 +34,7 @@ const getSender = (extension, target, sender) => {
// page-open listener below).
tabId = sender.tabId;
delete sender.tabId;
} else if (ExtensionCommon.instanceOf(target, "XULElement") ||
} else if (ExtensionCommon.instanceOf(target, "XULFrameElement") ||
ExtensionCommon.instanceOf(target, "HTMLIFrameElement")) {
tabId = tabTracker.getBrowserData(target).tabId;
}

View File

@ -143,7 +143,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=549682
var wn = document.getElementById('ifr').contentWindow
.getInterface(Ci.nsIWebNavigation);
ok(wn, "Should have webnavigation");
var cfmm = wn.getInterface(Ci.nsIContentFrameMessageManager);
var cfmm = wn.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIContentFrameMessageManager);
ok(cfmm, "Should have content messageManager");
var didGetSyncMessage = false;

View File

@ -48,6 +48,7 @@
#include "mozilla/dom/HTMLElementBinding.h"
#include "mozilla/dom/HTMLEmbedElementBinding.h"
#include "mozilla/dom/XULElementBinding.h"
#include "mozilla/dom/XULFrameElementBinding.h"
#include "mozilla/dom/XULPopupElementBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ResolveSystemBinding.h"
@ -3868,6 +3869,10 @@ HTMLConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
definition->mLocalName == nsGkAtoms::panel ||
definition->mLocalName == nsGkAtoms::tooltip) {
cb = XULPopupElement_Binding::GetConstructorObject;
} else if (definition->mLocalName == nsGkAtoms::iframe ||
definition->mLocalName == nsGkAtoms::browser ||
definition->mLocalName == nsGkAtoms::editor) {
cb = XULFrameElement_Binding::GetConstructorObject;
} else {
cb = XULElement_Binding::GetConstructorObject;
}

View File

@ -1834,6 +1834,7 @@ addExternalIface('nsITreeSelection', nativeType='nsITreeSelection',
notflattened=True)
addExternalIface('nsISupports', nativeType='nsISupports')
addExternalIface('nsIDocShell', nativeType='nsIDocShell', notflattened=True)
addExternalIface('nsIWebNavigation', nativeType='nsIWebNavigation', notflattened=True)
addExternalIface('nsIEditor', nativeType='nsIEditor', notflattened=True)
addExternalIface('nsIVariant', nativeType='nsIVariant', notflattened=True)
addExternalIface('nsIWebBrowserPersistDocumentReceiver',

View File

@ -0,0 +1,17 @@
/* -*- 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/. */
interface nsIDocShell;
interface nsIWebNavigation;
[HTMLConstructor, Func="IsChromeOrXBL"]
interface XULFrameElement : XULElement
{
readonly attribute nsIDocShell? docShell;
readonly attribute nsIWebNavigation? webNavigation;
readonly attribute WindowProxy? contentWindow;
readonly attribute Document? contentDocument;
};

View File

@ -45,6 +45,7 @@ WEBIDL_FILES = [
'StructuredCloneHolder.webidl',
'WebExtensionContentScript.webidl',
'WebExtensionPolicy.webidl',
'XULFrameElement.webidl'
]
if CONFIG['MOZ_PLACES']:

View File

@ -1252,6 +1252,8 @@ var interfaceNamesInGlobalScope =
{name: "XULDocument", insecureContext: true, xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "XULElement", insecureContext: true, xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "XULFrameElement", insecureContext: true, xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "XULPopupElement", insecureContext: true, xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -0,0 +1,57 @@
/* -*- 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 "nsCOMPtr.h"
#include "nsIContent.h"
#include "nsFrameLoader.h"
#include "mozilla/dom/XULFrameElement.h"
#include "mozilla/dom/XULFrameElementBinding.h"
namespace mozilla {
namespace dom {
JSObject*
XULFrameElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
{
return XULFrameElement_Binding::Wrap(aCx, this, aGivenProto);
}
nsIDocShell*
XULFrameElement::GetDocShell()
{
RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
return frameLoader ? frameLoader->GetDocShell(IgnoreErrors()) : nullptr;
}
already_AddRefed<nsIWebNavigation>
XULFrameElement::GetWebNavigation()
{
nsCOMPtr<nsIDocShell> docShell = GetDocShell();
nsCOMPtr<nsIWebNavigation> webnav = do_QueryInterface(docShell);
return webnav.forget();
}
already_AddRefed<nsPIDOMWindowOuter>
XULFrameElement::GetContentWindow()
{
nsCOMPtr<nsIDocShell> docShell = GetDocShell();
if (docShell) {
nsCOMPtr<nsPIDOMWindowOuter> win = docShell->GetWindow();
return win.forget();
}
return nullptr;
}
nsIDocument*
XULFrameElement::GetContentDocument()
{
nsCOMPtr<nsPIDOMWindowOuter> win = GetContentWindow();
return win ? win->GetDoc() : nullptr;
}
} // namespace dom
} // namespace mozilla

47
dom/xul/XULFrameElement.h Normal file
View File

@ -0,0 +1,47 @@
/* -*- 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 XULFrameElement_h__
#define XULFrameElement_h__
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "js/TypeDecls.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "nsString.h"
#include "nsXULElement.h"
class nsIWebNavigation;
namespace mozilla {
namespace dom {
class XULFrameElement final : public nsXULElement
{
public:
explicit XULFrameElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: nsXULElement(aNodeInfo)
{
}
nsIDocShell* GetDocShell();
already_AddRefed<nsIWebNavigation> GetWebNavigation();
already_AddRefed<nsPIDOMWindowOuter> GetContentWindow();
nsIDocument* GetContentDocument();
protected:
virtual ~XULFrameElement()
{
}
JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
};
} // namespace dom
} // namespace mozilla
#endif // XULFrameElement_h

View File

@ -24,6 +24,7 @@ if CONFIG['MOZ_XUL']:
]
EXPORTS.mozilla.dom += [
'XULFrameElement.h',
'XULPopupElement.h',
]
@ -37,6 +38,7 @@ if CONFIG['MOZ_XUL']:
'nsXULPrototypeDocument.cpp',
'nsXULSortService.cpp',
'XULDocument.cpp',
'XULFrameElement.cpp',
'XULPopupElement.cpp',
]

View File

@ -74,6 +74,7 @@
#include "nsCCUncollectableMarker.h"
#include "nsICSSDeclaration.h"
#include "nsLayoutUtils.h"
#include "XULFrameElement.h"
#include "XULPopupElement.h"
#include "mozilla/dom/XULElementBinding.h"
@ -178,6 +179,13 @@ nsXULElement* nsXULElement::Construct(already_AddRefed<mozilla::dom::NodeInfo>&&
return NS_NewXULPopupElement(nodeInfo.forget());
}
if (nodeInfo->Equals(nsGkAtoms::iframe) ||
nodeInfo->Equals(nsGkAtoms::browser) ||
nodeInfo->Equals(nsGkAtoms::editor)) {
already_AddRefed<mozilla::dom::NodeInfo> frameni = nodeInfo.forget();
return new XULFrameElement(frameni);
}
return NS_NewBasicXULElement(nodeInfo.forget());
}

View File

@ -10,7 +10,7 @@ const getSender = (extension, target, sender) => {
// page-open listener below).
tabId = sender.tabId;
delete sender.tabId;
} else if (ChromeUtils.getClassName(target) == "XULElement") {
} else if (ChromeUtils.getClassName(target) == "XULFrameElement") {
tabId = tabTracker.getBrowserData(target).tabId;
}

View File

@ -111,6 +111,7 @@ subsuite = clipboard
[test_findbar_entireword.xul]
[test_findbar_events.xul]
[test_focus_anons.xul]
[test_frames.xul]
[test_hiddenitems.xul]
[test_hiddenpaging.xul]
[test_keys.xul]

View File

@ -0,0 +1,62 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<window onload="setTimeout(runTest, 0);"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script><![CDATA[
SimpleTest.waitForExplicitFinish();
function runTest() {
for (let i = 1; i <= 3; i++) {
let frame = document.getElementById("frame" + i);
ok(frame instanceof XULFrameElement, "XULFrameElement " + i);
// Check the various fields to ensure that they have the correct type.
ok(frame.docShell instanceof Ci.nsIDocShell, "docShell " + i);
ok(frame.webNavigation instanceof Ci.nsIWebNavigation, "webNavigation " + i);
let contentWindow = frame.contentWindow;
let contentDocument = frame.contentDocument;
ok(contentWindow instanceof Window, "contentWindow " + i);
ok(contentDocument instanceof Document, "contentDocument " + i);
is(contentDocument.body.id, "thechildbody" + i, "right document body " + i);
// These fields should all be read-only.
frame.docShell = null;
ok(frame.docShell instanceof Ci.nsIDocShell, "docShell after set " + i);
frame.webNavigation = null;
ok(frame.webNavigation instanceof Ci.nsIWebNavigation, "webNavigation after set " + i);
frame.contentWindow = window;
is(frame.contentWindow, contentWindow, "contentWindow after set " + i);
frame.contentDocument = document;
is(frame.contentDocument, contentDocument, "contentDocument after set " + i);
}
// A non-frame element should not have these fields.
let button = document.getElementById("nonframe");
ok(!(button instanceof XULFrameElement), "XULFrameElement non frame");
is(button.docShell, undefined, "docShell non frame");
is(button.webNavigation, undefined, "webNavigation non frame");
is(button.contentWindow, undefined, "contentWindow non frame");
is(button.contentDocument, undefined, "contentDocument non frame");
SimpleTest.finish();
}
]]>
</script>
<iframe id="frame1" src="data:text/html,&lt;body id='thechildbody1'&gt;"/>
<browser id="frame2" src="data:text/html,&lt;body id='thechildbody2'&gt;"/>
<editor id="frame3" src="data:text/html,&lt;body id='thechildbody3'&gt;"/>
<button id="nonframe"/>
<body xmlns="http://www.w3.org/1999/xhtml">
<div id="content" style="display: none"></div>
</body>
</window>

View File

@ -181,21 +181,6 @@
]]></setter>
</property>
<field name="_docShell">null</field>
<property name="docShell" readonly="true">
<getter><![CDATA[
if (this._docShell)
return this._docShell;
let {frameLoader} = this;
if (!frameLoader)
return null;
this._docShell = frameLoader.docShell;
return this._docShell;
]]></getter>
</property>
<field name="_loadContext">null</field>
<property name="loadContext" readonly="true">
@ -314,23 +299,6 @@
</property>
<field name="_webNavigation">null</field>
<property name="webNavigation"
readonly="true">
<getter>
<![CDATA[
if (!this._webNavigation) {
if (!this.docShell) {
return null;
}
this._webNavigation = this.docShell.QueryInterface(Ci.nsIWebNavigation);
}
return this._webNavigation;
]]>
</getter>
</property>
<field name="_webBrowserFind">null</field>
<property name="webBrowserFind"
@ -425,12 +393,6 @@
readonly="true"
onget="return this.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebProgress);"/>
<field name="_contentWindow">null</field>
<property name="contentWindow"
readonly="true"
onget="return this._contentWindow || (this._contentWindow = this.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindow));"/>
<property name="contentWindowAsCPOW"
readonly="true"
onget="return this.contentWindow;"/>
@ -443,10 +405,6 @@
onget="return this.docShell.contentViewer;"
readonly="true"/>
<property name="contentDocument"
onget="return this.webNavigation.document;"
readonly="true"/>
<property name="contentDocumentAsCPOW"
onget="return this.contentDocument;"
readonly="true"/>
@ -1373,10 +1331,7 @@
// because these notifications are dispatched again once the docshells
// are swapped.
var fieldsToSwap = [
"_docShell",
"_webBrowserFind",
"_contentWindow",
"_webNavigation"
];
if (this.isRemoteBrowser) {

View File

@ -117,23 +117,9 @@
<property name="editortype"
onget="return this.getAttribute('editortype');"
onset="this.setAttribute('editortype', val); return val;"/>
<property name="webNavigation"
onget="return this.docShell.QueryInterface(Components.interfaces.nsIWebNavigation);"
readonly="true"/>
<property name="contentDocument" readonly="true"
onget="return this.webNavigation.document;"/>
<property name="docShell" readonly="true">
<getter><![CDATA[
let {frameLoader} = this;
return frameLoader ? frameLoader.docShell : null;
]]></getter>
</property>
<property name="currentURI"
readonly="true"
onget="return this.webNavigation.currentURI;"/>
<property name="contentWindow"
readonly="true"
onget="return this.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindow);"/>
<property name="contentWindowAsCPOW"
readonly="true"
onget="return this.contentWindow;"/>

View File

@ -57,23 +57,4 @@
</implementation>
</binding>
<binding id="iframe">
<implementation>
<property name="docShell" readonly="true">
<getter><![CDATA[
let {frameLoader} = this;
return frameLoader ? frameLoader.docShell : null;
]]></getter>
</property>
<property name="contentWindow"
readonly="true"
onget="return this.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindow);"/>
<property name="webNavigation"
onget="return this.docShell.QueryInterface(Components.interfaces.nsIWebNavigation);"
readonly="true"/>
<property name="contentDocument" readonly="true"
onget="return this.webNavigation.document;"/>
</implementation>
</binding>
</bindings>

View File

@ -176,10 +176,6 @@ editor {
-moz-binding: url("chrome://global/content/bindings/editor.xml#editor");
}
iframe {
-moz-binding: url("chrome://global/content/bindings/general.xml#iframe");
}
/********** notifications **********/
notificationbox {

View File

@ -224,7 +224,7 @@ var ContentPolicyManager = {
},
receiveMessage(msg) {
let browser = ChromeUtils.getClassName(msg.target) == "XULElement" ? msg.target : null;
let browser = ChromeUtils.getClassName(msg.target) == "XULFrameElement" ? msg.target : null;
let requestId = `fakeRequest-${++nextFakeRequestId}`;
for (let id of msg.data.ids) {

View File

@ -128,7 +128,7 @@ var ContentPolicy = {
let node = loadInfo.loadingContext;
if (node &&
(policyType == Ci.nsIContentPolicy.TYPE_SUBDOCUMENT ||
(ChromeUtils.getClassName(node) == "XULElement" &&
(ChromeUtils.getClassName(node) == "XULFrameElement" &&
node.localName == "browser"))) {
// Chrome sets frameId to the ID of the sub-window. But when
// Firefox loads an iframe, it sets |node| to the <iframe>