Bug 1196654 - navigator.mozBrowserElementProxy for access Browser API methods from the embedded, r=kanru, sr=sicking

This commit is contained in:
Tim Chien 2015-10-25 20:06:00 +01:00
parent 65c6b2e305
commit 31d6fa527e
17 changed files with 679 additions and 9 deletions

View File

@ -382,6 +382,8 @@
@RESPATH@/components/ConsoleAPIStorage.js
@RESPATH@/components/BrowserElementParent.manifest
@RESPATH@/components/BrowserElementParent.js
@RESPATH@/components/BrowserElementProxy.manifest
@RESPATH@/components/BrowserElementProxy.js
@RESPATH@/components/ContactManager.js
@RESPATH@/components/ContactManager.manifest
@RESPATH@/components/PhoneNumberService.js

View File

@ -365,6 +365,8 @@
@RESPATH@/components/ConsoleAPIStorage.js
@RESPATH@/components/BrowserElementParent.manifest
@RESPATH@/components/BrowserElementParent.js
@RESPATH@/components/BrowserElementProxy.manifest
@RESPATH@/components/BrowserElementProxy.js
@RESPATH@/components/FeedProcessor.manifest
@RESPATH@/components/FeedProcessor.js
@RESPATH@/components/PackagedAppUtils.js

View File

@ -131,6 +131,11 @@ this.PermissionsTable = { geolocation: {
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
"browser:embedded-system-app": {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
bluetooth: {
app: DENY_ACTION,
privileged: DENY_ACTION,

View File

@ -85,6 +85,38 @@ const COMMAND_MAP = {
var global = this;
function BrowserElementProxyForwarder() {
}
BrowserElementProxyForwarder.prototype = {
init: function() {
Services.obs.addObserver(this, "browser-element-api:proxy-call", false);
addMessageListener("browser-element-api:proxy", this);
},
uninit: function() {
Services.obs.removeObserver(this, "browser-element-api:proxy-call", false);
removeMessageListener("browser-element-api:proxy", this);
},
// Observer callback receives messages from BrowserElementProxy.js
observe: function(subject, topic, stringifedData) {
if (subject !== content) {
return;
}
// Forward it to BrowserElementParent.js
sendAsyncMessage(topic, JSON.parse(stringifedData));
},
// Message manager callback receives messages from BrowserElementParent.js
receiveMessage: function(mmMsg) {
// Forward it to BrowserElementProxy.js
Services.obs.notifyObservers(
content, mmMsg.name, JSON.stringify(mmMsg.json));
}
};
function BrowserElementChild() {
// Maps outer window id --> weak ref to window. Used by modal dialog code.
this._windowIDDict = {};
@ -104,6 +136,8 @@ function BrowserElementChild() {
this._pendingSetInputMethodActive = [];
this._selectionStateChangedTarget = null;
this.forwarder = new BrowserElementProxyForwarder();
this._init();
};
@ -288,6 +322,8 @@ BrowserElementChild.prototype = {
OBSERVED_EVENTS.forEach((aTopic) => {
Services.obs.addObserver(this, aTopic, false);
});
this.forwarder.init();
},
observe: function(subject, topic, data) {
@ -327,6 +363,9 @@ BrowserElementChild.prototype = {
OBSERVED_EVENTS.forEach((aTopic) => {
Services.obs.removeObserver(this, aTopic);
});
this.forwarder.uninit();
this.forwarder = null;
},
get _windowUtils() {
@ -934,7 +973,7 @@ BrowserElementChild.prototype = {
},
_getSystemCtxMenuData: function(elem) {
let documentURI =
let documentURI =
docShell.QueryInterface(Ci.nsIWebNavigation).currentURI.spec;
if ((elem instanceof Ci.nsIDOMHTMLAnchorElement && elem.href) ||
(elem instanceof Ci.nsIDOMHTMLAreaElement && elem.href)) {

View File

@ -64,6 +64,177 @@ function defineDOMRequestMethod(msgName) {
};
}
function BrowserElementParentProxyCallHandler() {
}
BrowserElementParentProxyCallHandler.prototype = {
_frameElement: null,
_mm: null,
MOZBROWSER_EVENT_NAMES: Object.freeze([
"loadstart", "loadend", "close", "error", "firstpaint",
"documentfirstpaint", "audioplaybackchange",
"contextmenu", "securitychange", "locationchange",
"iconchange", "scrollareachanged", "titlechange",
"opensearch", "manifestchange", "metachange",
"resize", "selectionstatechanged", "scrollviewchange",
"caretstatechanged", "activitydone", "scroll", "opentab"]),
init: function(frameElement, mm) {
this._frameElement = frameElement;
this._mm = mm;
this.innerWindowIDSet = new Set();
mm.addMessageListener("browser-element-api:proxy-call", this);
},
// Message manager callback receives messages from BrowserElementProxy.js
receiveMessage: function(mmMsg) {
let data = mmMsg.json;
let mm;
try {
mm = mmMsg.target.QueryInterface(Ci.nsIFrameLoaderOwner)
.frameLoader.messageManager;
} catch(e) {
mm = mmMsg.target;
}
if (!mm.assertPermission("browser:embedded-system-app")) {
dump("BrowserElementParent.js: Method call " + data.methodName +
" from a content process with no 'browser:embedded-system-app'" +
" privileges.\n");
return;
}
switch (data.methodName) {
case '_proxyInstanceInit':
if (!this.innerWindowIDSet.size) {
this._attachEventListeners();
}
this.innerWindowIDSet.add(data.innerWindowID);
break;
case '_proxyInstanceUninit':
this.innerWindowIDSet.delete(data.innerWindowID);
if (!this.innerWindowIDSet.size) {
this._detachEventListeners();
}
break;
// void methods
case 'setVisible':
case 'setActive':
case 'sendMouseEvent':
case 'sendTouchEvent':
case 'goBack':
case 'goForward':
case 'reload':
case 'stop':
case 'zoom':
case 'setNFCFocus':
case 'findAll':
case 'findNext':
case 'clearMatch':
case 'mute':
case 'unmute':
case 'setVolume':
this._frameElement[data.methodName]
.apply(this._frameElement, data.args);
break;
// DOMRequest methods
case 'getVisible':
case 'download':
case 'purgeHistory':
case 'getCanGoBack':
case 'getCanGoForward':
case 'getContentDimensions':
case 'setInputMethodActive':
case 'executeScript':
case 'getMuted':
case 'getVolume':
let req = this._frameElement[data.methodName]
.apply(this._frameElement, data.args);
req.onsuccess = () => {
this._sendToProxy({
domRequestId: data.domRequestId,
innerWindowID: data.innerWindowID,
result: req.result
});
};
req.onerror = () => {
this._sendToProxy({
domRequestId: data.domRequestId,
innerWindowID: data.innerWindowID,
err: req.error
});
};
break;
// Not implemented
case 'getActive': // Sync ???
case 'addNextPaintListener': // Takes a callback
case 'removeNextPaintListener': // Takes a callback
case 'getScreenshot': // Need to pass a blob back
dump("BrowserElementParentProxyCallHandler Error:" +
"Attempt to call unimplemented method " + data.methodName + ".\n");
break;
default:
dump("BrowserElementParentProxyCallHandler Error:" +
"Attempt to call non-exist method " + data.methodName + ".\n");
break;
}
},
// Receving events from the frame element and forward it.
handleEvent: function(evt) {
// Ignore the events from nested mozbrowser iframes
if (evt.target !== this._frameElement) {
return;
}
let detailString;
try {
detailString = JSON.stringify(evt.detail);
} catch (e) {
dump("BrowserElementParentProxyCallHandler Error:" +
"Event detail of " + evt.type + " can't be stingified.\n");
return;
}
this.innerWindowIDSet.forEach((innerWindowID) => {
this._sendToProxy({
eventName: evt.type,
innerWindowID: innerWindowID,
eventDetailString: detailString
});
});
},
_sendToProxy: function(data) {
this._mm.sendAsyncMessage("browser-element-api:proxy", data);
},
_attachEventListeners: function() {
this.MOZBROWSER_EVENT_NAMES.forEach(function(eventName) {
this._frameElement.addEventListener(
"mozbrowser" + eventName, this, true);
}, this);
},
_detachEventListeners: function() {
this.MOZBROWSER_EVENT_NAMES.forEach(function(eventName) {
this._frameElement.removeEventListener(
"mozbrowser" + eventName, this, true);
}, this);
}
};
function BrowserElementParent() {
debug("Creating new BrowserElementParent object");
this._domRequestCounter = 0;
@ -77,6 +248,8 @@ function BrowserElementParent() {
Services.obs.addObserver(this, 'oop-frameloader-crashed', /* ownsWeak = */ true);
Services.obs.addObserver(this, 'copypaste-docommand', /* ownsWeak = */ true);
Services.obs.addObserver(this, 'ask-children-to-execute-copypaste-command', /* ownsWeak = */ true);
this.proxyCallHandler = new BrowserElementParentProxyCallHandler();
}
BrowserElementParent.prototype = {
@ -123,6 +296,9 @@ BrowserElementParent.prototype = {
BrowserElementPromptService.mapFrameToBrowserElementParent(this._frameElement, this);
this._setupMessageListener();
this._registerAppManifest();
this.proxyCallHandler.init(
this._frameElement, this._frameLoader.messageManager);
},
_runPendingAPICall: function() {
@ -736,7 +912,7 @@ BrowserElementParent.prototype = {
if (!this._isAlive()) {
return null;
}
let uri = Services.io.newURI(_url, null, null);
let url = uri.QueryInterface(Ci.nsIURL);
@ -826,7 +1002,7 @@ BrowserElementParent.prototype = {
Ci.nsIRequestObserver])
};
// If we have a URI we'll use it to get the triggering principal to use,
// If we have a URI we'll use it to get the triggering principal to use,
// if not available a null principal is acceptable.
let referrer = null;
let principal = null;
@ -849,9 +1025,9 @@ BrowserElementParent.prototype = {
debug('Using principal? ' + !!principal);
let channel =
let channel =
Services.io.newChannelFromURI2(url,
null, // No document.
null, // No document.
principal, // Loading principal
principal, // Triggering principal
Ci.nsILoadInfo.SEC_NORMAL,
@ -872,7 +1048,7 @@ BrowserElementParent.prototype = {
channel.loadFlags |= flags;
if (channel instanceof Ci.nsIHttpChannel) {
debug('Setting HTTP referrer = ' + (referrer && referrer.spec));
debug('Setting HTTP referrer = ' + (referrer && referrer.spec));
channel.referrer = referrer;
if (channel instanceof Ci.nsIHttpChannelInternal) {
channel.forceAllowThirdPartyCookie = true;

View File

@ -0,0 +1,220 @@
/* 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/. */
'use strict';
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
function defineNoReturnMethod(methodName) {
return function noReturnMethod() {
let args = Array.slice(arguments);
this._sendToParent(methodName, args);
};
}
function defineDOMRequestMethod(methodName) {
return function domRequestMethod() {
let args = Array.slice(arguments);
return this._sendDOMRequest(methodName, args);
};
}
function defineUnimplementedMethod(methodName) {
return function unimplementedMethod() {
throw Components.Exception(
'Unimplemented method: ' + methodName, Cr.NS_ERROR_FAILURE);
};
}
/**
* The BrowserElementProxy talks to the Browser IFrameElement instance on
* behave of the embedded document. It implements all the methods on
* the Browser IFrameElement and the methods will work if they are applicable.
*
* The message is forwarded to BrowserElementParent.js by creating an
* 'browser-element-api:proxy-call' observer message.
* BrowserElementChildPreload will get notified and send the message through
* to the main process through sendAsyncMessage with message of the same name.
*
* The return message will follow the same route. The message name on the
* return route is 'browser-element-api:proxy'.
*
* Both BrowserElementProxy and BrowserElementParent must be modified if there
* is a new method implemented, or a new event added to the Browser
* IFrameElement.
*
* Other details unmentioned here are checks of message sender and recipients
* to identify proxy instance on different innerWindows or ensure the content
* process has the right permission.
*/
function BrowserElementProxy() {
// Pad the 0th element so that DOMRequest ID will always be a truthy value.
this._pendingDOMRequests = [ undefined ];
}
BrowserElementProxy.prototype = {
classDescription: 'BrowserElementProxy allowed embedded frame to control ' +
'it\'s own embedding browser element frame instance.',
classID: Components.ID('{7e95d54c-9930-49c8-9a10-44fe40fe8251}'),
contractID: '@mozilla.org/dom/browser-element-proxy;1',
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIDOMGlobalPropertyInitializer,
Ci.nsIObserver]),
_window: null,
_innerWindowID: undefined,
get allowedAudioChannels() {
return this._window.navigator.mozAudioChannelManager ?
this._window.navigator.mozAudioChannelManager.allowedAudioChannels :
null;
},
init: function(win) {
this._window = win;
this._innerWindowID = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.currentInnerWindowID;
this._sendToParent('_proxyInstanceInit');
Services.obs.addObserver(this, 'browser-element-api:proxy', false);
},
uninit: function(win) {
this._sendToParent('_proxyInstanceUninit');
this._window = null;
this._innerWindowID = undefined;
Services.obs.removeObserver(this, 'browser-element-api:proxy');
},
observe: function(subject, topic, stringifedData) {
let data = JSON.parse(stringifedData);
if (subject !== this._window ||
data.innerWindowID !== data.innerWindowID) {
return;
}
if (data.eventName) {
this._fireEvent(data.eventName, JSON.parse(data.eventDetailString));
return;
}
if ('domRequestId' in data) {
let req = this._pendingDOMRequests[data.domRequestId];
this._pendingDOMRequests[data.domRequestId] = undefined;
if (!req) {
dump('BrowserElementProxy Error: ' +
'Multiple observer messages for the same DOMRequest result.\n');
return;
}
if ('result' in data) {
let clientObj = Cu.cloneInto(data.result, this._window);
Services.DOMRequest.fireSuccess(req, clientObj);
} else {
let clientObj = Cu.cloneInto(data.error, this._window);
Services.DOMRequest.fireSuccess(req, clientObj);
}
return;
}
dump('BrowserElementProxy Error: ' +
'Received unhandled observer messages ' + stringifedData + '.\n');
},
_sendDOMRequest: function(methodName, args) {
let id = this._pendingDOMRequests.length;
let req = Services.DOMRequest.createRequest(this._window);
this._pendingDOMRequests.push(req);
this._sendToParent(methodName, args, id);
return req;
},
_sendToParent: function(methodName, args, domRequestId) {
let data = {
methodName: methodName,
args: args,
innerWindowID: this._innerWindowID
};
if (domRequestId) {
data.domRequestId = domRequestId;
}
Services.obs.notifyObservers(
this._window, 'browser-element-api:proxy-call', JSON.stringify(data));
},
_fireEvent: function(name, detail) {
let evt = this._createEvent(name, detail,
/* cancelable = */ false);
this.__DOM_IMPL__.dispatchEvent(evt);
},
_createEvent: function(evtName, detail, cancelable) {
// This will have to change if we ever want to send a CustomEvent with null
// detail. For now, it's OK.
if (detail !== undefined && detail !== null) {
detail = Cu.cloneInto(detail, this._window);
return new this._window.CustomEvent(evtName,
{ bubbles: false,
cancelable: cancelable,
detail: detail });
}
return new this._window.Event(evtName,
{ bubbles: false,
cancelable: cancelable });
},
setVisible: defineNoReturnMethod('setVisible'),
setActive: defineNoReturnMethod('setActive'),
sendMouseEvent: defineNoReturnMethod('sendMouseEvent'),
sendTouchEvent: defineNoReturnMethod('sendTouchEvent'),
goBack: defineNoReturnMethod('goBack'),
goForward: defineNoReturnMethod('goForward'),
reload: defineNoReturnMethod('reload'),
stop: defineNoReturnMethod('stop'),
zoom: defineNoReturnMethod('zoom'),
setNFCFocus: defineNoReturnMethod('setNFCFocus'),
findAll: defineNoReturnMethod('findAll'),
findNext: defineNoReturnMethod('findNext'),
clearMatch: defineNoReturnMethod('clearMatch'),
mute: defineNoReturnMethod('mute'),
unmute: defineNoReturnMethod('unmute'),
setVolume: defineNoReturnMethod('setVolume'),
getVisible: defineDOMRequestMethod('getVisible'),
download: defineDOMRequestMethod('download'),
purgeHistory: defineDOMRequestMethod('purgeHistory'),
getCanGoBack: defineDOMRequestMethod('getCanGoBack'),
getCanGoForward: defineDOMRequestMethod('getCanGoForward'),
getContentDimensions: defineDOMRequestMethod('getContentDimensions'),
setInputMethodActive: defineDOMRequestMethod('setInputMethodActive'),
executeScript: defineDOMRequestMethod('executeScript'),
getMuted: defineDOMRequestMethod('getMuted'),
getVolume: defineDOMRequestMethod('getVolume'),
getActive: defineUnimplementedMethod('getActive'),
addNextPaintListener: defineUnimplementedMethod('addNextPaintListener'),
removeNextPaintListener: defineUnimplementedMethod('removeNextPaintListener'),
getScreenshot: defineUnimplementedMethod('getScreenshot')
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([BrowserElementProxy]);

View File

@ -0,0 +1,2 @@
component {7e95d54c-9930-49c8-9a10-44fe40fe8251} BrowserElementProxy.js
contract @mozilla.org/dom/browser-element-proxy;1 {7e95d54c-9930-49c8-9a10-44fe40fe8251}

View File

@ -0,0 +1,161 @@
/* Any copyright is dedicated to the public domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
SimpleTest.waitForExplicitFinish();
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
function runTest() {
let frameUrl = SimpleTest.getTestFileURL('/file_empty.html');
SpecialPowers.pushPermissions([{
type: 'browser:embedded-system-app',
allow: true,
context: {
url: frameUrl,
appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
isInBrowserElement: true
}
},{
type: 'browser',
allow: true,
context: {
url: frameUrl,
appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
isInBrowserElement: true
}
}], createFrame);
}
var frame;
var mm;
function createFrame() {
let loadEnd = function() {
// The frame script running in the frame where the input is hosted.
let appFrameScript = function appFrameScript() {
let i = 1;
addMessageListener('test:next', function() {
try {
switch (i) {
case 1:
content.document.addEventListener(
'visibilitychange', function fn() {
content.document.removeEventListener('visibilitychange', fn);
sendAsyncMessage('test:done', {
ok: true,
msg: 'setVisible()'
});
});
// Test a no return method
content.navigator.mozBrowserElementProxy.setVisible(false);
break;
case 2:
// Test a DOMRequest method
var req = content.navigator.mozBrowserElementProxy.getVisible();
req.onsuccess = function() {
sendAsyncMessage('test:done', {
ok: true,
msg: 'getVisible()'
});
};
req.onerror = function() {
sendAsyncMessage('test:done', {
ok: false,
msg: 'getVisible() DOMRequest return error.'
});
};
break;
case 3:
// Test an unimplemented method
try {
content.navigator.mozBrowserElementProxy.getActive();
sendAsyncMessage('test:done', {
ok: false,
msg: 'getActive() should throw.'
});
} catch (e) {
sendAsyncMessage('test:done', {
ok: true,
msg: 'getActive() throws.'
});
}
break;
case 4:
content.navigator.mozBrowserElementProxy
.addEventListener(
'mozbrowserlocationchange',
function() {
content.navigator.mozBrowserElementProxy
.onmozbrowserlocationchange = null;
sendAsyncMessage('test:done', {
ok: true,
msg: 'mozbrowserlocationchange'
});
});
// Test event
content.location.hash = '#foo';
break;
}
} catch (e) {
sendAsyncMessage('test:done', {
ok: false, msg: 'thrown: ' + e.toString() });
}
i++;
});
sendAsyncMessage('test:done', {});
}
mm = SpecialPowers.getBrowserFrameMessageManager(frame);
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
mm.addMessageListener("test:done", next);
};
frame = document.createElement('iframe');
frame.setAttribute('mozbrowser', 'true');
frame.src = 'file_empty.html';
document.body.appendChild(frame);
frame.addEventListener('mozbrowserloadend', loadEnd);
}
var i = 0;
function next(msg) {
let wrappedMsg = SpecialPowers.wrap(msg);
let isOK = wrappedMsg.data.ok;
let msgString = wrappedMsg.data.msg;
switch (i) {
case 0:
mm.sendAsyncMessage('test:next');
break;
case 1:
case 2:
case 3:
ok(isOK, msgString);
mm.sendAsyncMessage('test:next');
break;
case 4:
ok(isOK, msgString);
SimpleTest.finish();
break;
}
i++;
}
addEventListener('testready', runTest);

View File

@ -76,6 +76,8 @@ skip-if = (toolkit == 'gonk') # Disabled on emulator. See bug 1144015 comment 8
[test_browserElement_oop_PrivateBrowsing.html]
[test_browserElement_oop_PromptCheck.html]
[test_browserElement_oop_PromptConfirm.html]
[test_browserElement_oop_Proxy.html]
skip-if = (toolkit == 'gonk') # Disabled on B2G Emulator bug 1198163
[test_browserElement_oop_PurgeHistory.html]
[test_browserElement_oop_Reload.html]
[test_browserElement_oop_ReloadPostRequest.html]

View File

@ -54,6 +54,7 @@ support-files =
browserElement_PrivateBrowsing.js
browserElement_PromptCheck.js
browserElement_PromptConfirm.js
browserElement_Proxy.js
browserElement_PurgeHistory.js
browserElement_Reload.js
browserElement_ReloadPostRequest.js
@ -204,6 +205,8 @@ skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_inproc_PrivateBrowsing.html]
[test_browserElement_inproc_PromptCheck.html]
[test_browserElement_inproc_PromptConfirm.html]
[test_browserElement_inproc_Proxy.html]
skip-if = (toolkit == 'gonk') # Disabled on B2G Emulator bug 1198163
[test_browserElement_inproc_PurgeHistory.html]
[test_browserElement_inproc_ReloadPostRequest.html]
[test_browserElement_inproc_RemoveBrowserElement.html]

View File

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1196654
-->
<head>
<title>Test for Bug 1196654</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1196654">Mozilla Bug 1196654</a>
<script type="application/javascript;version=1.7" src="browserElement_Proxy.js">
</script>
</body>
</html>

View File

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1196654
-->
<head>
<title>Test for Bug 1196654</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1196654">Mozilla Bug 1196654</a>
<script type="application/javascript;version=1.7" src="browserElement_Proxy.js">
</script>
</body>
</html>

View File

@ -26,6 +26,8 @@ XPIDL_MODULE = 'browser-element'
EXTRA_COMPONENTS += [
'BrowserElementParent.js',
'BrowserElementParent.manifest',
'BrowserElementProxy.js',
'BrowserElementProxy.manifest',
]
EXTRA_JS_MODULES += [

View File

@ -0,0 +1,15 @@
/* -*- 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,
JSImplementation="@mozilla.org/dom/browser-element-proxy;1",
NavigatorProperty="mozBrowserElementProxy",
Pref="dom.mozBrowserFramesEnabled",
CheckAnyPermissions="browser:embedded-system-app"]
interface BrowserElementProxy : EventTarget {
};
BrowserElementProxy implements BrowserElementCommon;
BrowserElementProxy implements BrowserElementPrivileged;

View File

@ -59,6 +59,7 @@ WEBIDL_FILES = [
'BrowserElement.webidl',
'BrowserElementAudioChannel.webidl',
'BrowserElementDictionaries.webidl',
'BrowserElementProxy.webidl',
'Cache.webidl',
'CacheStorage.webidl',
'CallsList.webidl',

View File

@ -2,7 +2,7 @@
; 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/.
; Package file for the Fennec build.
; Package file for the Fennec build.
;
; File format:
;
@ -309,6 +309,8 @@
@BINPATH@/components/SettingsService.manifest
@BINPATH@/components/BrowserElementParent.manifest
@BINPATH@/components/BrowserElementParent.js
@BINPATH@/components/BrowserElementProxy.manifest
@BINPATH@/components/BrowserElementProxy.js
@BINPATH@/components/PackagedAppUtils.manifest
@BINPATH@/components/PackagedAppUtils.js
@BINPATH@/components/BrowserFeeds.manifest
@ -518,7 +520,7 @@
@BINPATH@/defaults/profile/prefs.js
; [Layout Engine Resources]
; Style Sheets, Graphics and other Resources used by the layout engine.
; Style Sheets, Graphics and other Resources used by the layout engine.
@BINPATH@/res/EditorOverride.css
@BINPATH@/res/contenteditable.css
@BINPATH@/res/designmode.css
@ -649,7 +651,7 @@ bin/libfreebl_32int64_3.so
@BINPATH@/components/browsercomps.xpt
#ifdef ENABLE_MARIONETTE
@BINPATH@/chrome/marionette@JAREXT@
@BINPATH@/chrome/marionette@JAREXT@
@BINPATH@/chrome/marionette.manifest
@BINPATH@/components/MarionetteComponents.manifest
@BINPATH@/components/marionettecomponent.js

View File

@ -310,6 +310,8 @@
@BINPATH@/components/SettingsManager.manifest
@BINPATH@/components/BrowserElementParent.manifest
@BINPATH@/components/BrowserElementParent.js
@BINPATH@/components/BrowserElementProxy.manifest
@BINPATH@/components/BrowserElementProxy.js
@BINPATH@/components/FeedProcessor.manifest
@BINPATH@/components/FeedProcessor.js
@BINPATH@/components/PackagedAppUtils.manifest