Merge latest green b2g-inbound changeset and mozilla-central; a=merge

This commit is contained in:
Ed Morley 2014-08-19 15:08:54 +01:00
commit ac1319df2b
508 changed files with 3841 additions and 1643 deletions

View File

@ -1522,7 +1522,7 @@ pref("browser.newtabpage.enhanced", false);
pref("browser.newtabpage.rows", 3);
// number of columns of newtab grid
pref("browser.newtabpage.columns", 8);
pref("browser.newtabpage.columns", 5);
// directory tiles download URL
pref("browser.newtabpage.directory.source", "chrome://global/content/directoryLinks.json");

View File

@ -3097,16 +3097,16 @@ const BrowserSearch = {
}
#endif
let openSearchPageIfFieldIsNotActive = function(aSearchBar) {
let doc = gBrowser.selectedBrowser.contentDocument;
let url = doc.documentURI.toLowerCase();
let mm = gBrowser.selectedBrowser.messageManager;
if (url === "about:home") {
AboutHome.focusInput(mm);
} else if (url === "about:newtab") {
ContentSearch.focusInput(mm);
} else if (!aSearchBar || document.activeElement != aSearchBar.textbox.inputField) {
openUILinkIn("about:home", "current");
if (!aSearchBar || document.activeElement != aSearchBar.textbox.inputField) {
let url = gBrowser.currentURI.spec.toLowerCase();
let mm = gBrowser.selectedBrowser.messageManager;
if (url === "about:home") {
AboutHome.focusInput(mm);
} else if (url === "about:newtab") {
ContentSearch.focusInput(mm);
} else {
openUILinkIn("about:home", "current");
}
}
};
@ -3319,6 +3319,7 @@ function FillHistoryMenu(aParent) {
PlacesUtils.favicons.getFaviconURLForPage(entry.URI, function (aURI) {
if (aURI) {
let iconURL = PlacesUtils.favicons.getFaviconLinkForIcon(aURI).spec;
iconURL = PlacesUtils.getImageURLForResolution(window, iconURL);
item.style.listStyleImage = "url(" + iconURL + ")";
}
});

View File

@ -29,7 +29,7 @@ addMessageListener("Browser:HideSessionRestoreButton", function (message) {
let doc = content.document;
let container;
if (doc.documentURI.toLowerCase() == "about:home" &&
(container = doc.getElementById("sessionRestoreContainer"))){
(container = doc.getElementById("sessionRestoreContainer"))) {
container.hidden = true;
}
});
@ -90,18 +90,37 @@ if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
let AboutHomeListener = {
init: function(chromeGlobal) {
chromeGlobal.addEventListener('AboutHomeLoad', () => this.onPageLoad(), false, true);
chromeGlobal.addEventListener('AboutHomeLoad', this, false, true);
},
get isAboutHome() {
return content.document.documentURI.toLowerCase() == "about:home";
},
handleEvent: function(aEvent) {
if (!this.isAboutHome) {
return;
}
switch (aEvent.type) {
case "AboutHomeLoad":
this.onPageLoad();
break;
case "AboutHomeSearchEvent":
this.onSearch(aEvent);
break;
case "click":
this.onClick(aEvent);
break;
case "pagehide":
this.onPageHide(aEvent);
break;
}
},
receiveMessage: function(aMessage) {
if (!this.isAboutHome) {
return;
}
switch (aMessage.name) {
case "AboutHome:Update":
this.onUpdate(aMessage.data);
@ -114,9 +133,6 @@ let AboutHomeListener = {
onUpdate: function(aData) {
let doc = content.document;
if (doc.documentURI.toLowerCase() != "about:home")
return;
if (aData.showRestoreLastSession && !PrivateBrowsingUtils.isWindowPrivate(content))
doc.getElementById("launcher").setAttribute("session", "true");
@ -133,25 +149,15 @@ let AboutHomeListener = {
onPageLoad: function() {
let doc = content.document;
if (doc.documentURI.toLowerCase() != "about:home" ||
doc.documentElement.hasAttribute("hasBrowserHandlers")) {
if (doc.documentElement.hasAttribute("hasBrowserHandlers")) {
return;
}
doc.documentElement.setAttribute("hasBrowserHandlers", "true");
let self = this;
addMessageListener("AboutHome:Update", self);
addMessageListener("AboutHome:FocusInput", self);
addEventListener("click", this.onClick, true);
addEventListener("pagehide", function onPageHide(event) {
if (event.target.defaultView.frameElement)
return;
removeMessageListener("AboutHome:Update", self);
removeEventListener("click", self.onClick, true);
removeEventListener("pagehide", onPageHide, true);
if (event.target.documentElement)
event.target.documentElement.removeAttribute("hasBrowserHandlers");
}, true);
addMessageListener("AboutHome:Update", this);
addMessageListener("AboutHome:FocusInput", this);
addEventListener("click", this, true);
addEventListener("pagehide", this, true);
// XXX bug 738646 - when Marketplace is launched, remove this statement and
// the hidden attribute set on the apps button in aboutHome.xhtml
@ -160,10 +166,7 @@ let AboutHomeListener = {
doc.getElementById("apps").removeAttribute("hidden");
sendAsyncMessage("AboutHome:RequestUpdate");
doc.addEventListener("AboutHomeSearchEvent", function onSearch(e) {
sendAsyncMessage("AboutHome:Search", { searchData: e.detail });
}, true, true);
doc.addEventListener("AboutHomeSearchEvent", this, true, true);
},
onClick: function(aEvent) {
@ -217,8 +220,27 @@ let AboutHomeListener = {
}
},
onPageHide: function(aEvent) {
if (event.target.defaultView.frameElement) {
return;
}
removeMessageListener("AboutHome:Update", this);
removeEventListener("click", this, true);
removeEventListener("pagehide", this, true);
if (event.target.documentElement) {
event.target.documentElement.removeAttribute("hasBrowserHandlers");
}
},
onSearch: function(aEvent) {
sendAsyncMessage("AboutHome:Search", { searchData: aEvent.detail });
},
onFocusInput: function () {
content.document.getElementById("searchText").focus();
let searchInput = content.document.getElementById("searchText");
if (searchInput) {
searchInput.focus();
}
},
};
AboutHomeListener.init(this);

View File

@ -85,6 +85,9 @@
Components.classes["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"]
.getService(Components.interfaces.mozIPlacesAutoComplete);
</field>
<field name="PlacesUtils" readonly="true">
(Components.utils.import("resource://gre/modules/PlacesUtils.jsm", {})).PlacesUtils;
</field>
<field name="mTabBox" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "tabbox");
</field>
@ -840,9 +843,7 @@
let sizedIconUrl = browser.mIconURL || "";
if (sizedIconUrl) {
let size = Math.round(16 * window.devicePixelRatio);
sizedIconUrl += (sizedIconUrl.contains("#") ? "&" : "#") +
"-moz-resolution=" + size + "," + size;
sizedIconUrl = this.PlacesUtils.getImageURLForResolution(window, sizedIconUrl);
}
if (sizedIconUrl != aTab.getAttribute("image")) {
if (sizedIconUrl)

View File

@ -420,8 +420,11 @@ let gTests = [
}
},
{
desc: "Cmd+k should focus the search bar element",
setup: function () {},
desc: "Cmd+k should focus the search box in the page when the search box in the toolbar is absent",
setup: function () {
// Remove the search bar from toolbar
CustomizableUI.removeWidgetFromArea("search-container");
},
run: Task.async(function* () {
let doc = gBrowser.selectedTab.linkedBrowser.contentDocument;
let logo = doc.getElementById("brandLogo");
@ -433,8 +436,25 @@ let gTests = [
EventUtils.synthesizeKey("k", { accelKey: true });
yield promiseWaitForCondition(() => doc.activeElement === searchInput);
is(searchInput, doc.activeElement, "Search input should be the active element.");
CustomizableUI.reset();
})
},
{
desc: "Cmd+k should focus the search box in the toolbar when it's present",
setup: function () {},
run: Task.async(function* () {
let logo = gBrowser.selectedTab.linkedBrowser.contentDocument.getElementById("brandLogo");
let doc = window.document;
let searchInput = doc.getElementById("searchbar").textbox.inputField;
EventUtils.synthesizeMouseAtCenter(logo, {});
isnot(searchInput, doc.activeElement, "Search bar should not be the active element.");
EventUtils.synthesizeKey("k", { accelKey: true });
yield promiseWaitForCondition(() => doc.activeElement === searchInput);
is(searchInput, doc.activeElement, "Search bar should be the active element.");
})
}
];

View File

@ -17,8 +17,8 @@ function runTests() {
// Expected length of grid
let expectedValues = [1, 1, 1, 1, 8, 10];
// Values before setting new pref values (24 is the default value -> 8 x 3)
let previousValues = [24, 1, 1, 1, 1, 8];
// Values before setting new pref values (15 is the default value -> 5 x 3)
let previousValues = [15, 1, 1, 1, 1, 8];
let existingTab, existingTabGridLength, newTab, newTabGridLength;
yield addNewTabPageTab();

View File

@ -186,15 +186,24 @@ function runTests() {
EventUtils.synthesizeKey("VK_DELETE", {});
ok(table.hidden, "Search suggestion table hidden");
// Focus a different element than the search input.
// Remove the search bar from toolbar
CustomizableUI.removeWidgetFromArea("search-container");
// Focus a different element than the search input from the page.
let btn = getContentDocument().getElementById("newtab-customize-button");
yield promiseClick(btn).then(TestRunner.next);
isnot(input, getContentDocument().activeElement, "Search input should not be focused");
// Test that Ctrl/Cmd + K will focus the input field.
// Test that Ctrl/Cmd + K will focus the input field from the page.
EventUtils.synthesizeKey("k", { accelKey: true });
yield promiseSearchEvents(["FocusInput"]).then(TestRunner.next);
is(input, getContentDocument().activeElement, "Search input should be focused");
// Reset changes made to toolbar
CustomizableUI.reset();
// Test that Ctrl/Cmd + K will focus the search bar from toolbar.
let searchBar = gWindow.document.getElementById("searchbar");
EventUtils.synthesizeKey("k", { accelKey: true });
is(searchBar.textbox.inputField, gWindow.document.activeElement, "Toolbar's search bar should be focused");
// Done. Revert the current engine and remove the new engines.
Services.search.currentEngine = oldCurrentEngine;

View File

@ -159,6 +159,7 @@ const CustomizableWidgets = [{
// Populate our list of history
const kMaxResults = 15;
let doc = aEvent.detail.ownerDocument;
let win = doc.defaultView;
let options = PlacesUtils.history.getNewQueryOptions();
options.excludeQueries = true;
@ -201,8 +202,10 @@ const CustomizableWidgets = [{
item.addEventListener("click", function (aEvent) {
onHistoryVisit(uri, aEvent, item);
});
if (icon)
item.setAttribute("image", "moz-anno:favicon:" + icon);
if (icon) {
let iconURL = PlacesUtils.getImageURLForResolution(win, "moz-anno:favicon:" + icon);
item.setAttribute("image", iconURL);
}
fragment.appendChild(item);
} catch (e) {
ERROR("Error while showing history subview: " + e);

View File

@ -14,6 +14,8 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/osfile.jsm", this);
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/FxAccountsOAuthClient.jsm");
this.EXPORTED_SYMBOLS = ["MozLoopService"];
@ -56,6 +58,8 @@ let gHawkClient = null;
let gRegisteredLoopServer = false;
let gLocalizedStrings = null;
let gInitializeTimer = null;
let gFxAOAuthClientPromise = null;
let gFxAOAuthClient = null;
/**
* Internal helper methods and state
@ -449,7 +453,86 @@ let MozLoopServiceInternal = {
};
Chat.open(contentWindow, origin, title, url, undefined, undefined, callback);
}
},
/**
* Fetch Firefox Accounts (FxA) OAuth parameters from the Loop Server.
*
* @return {Promise} resolved with the body of the hawk request for OAuth parameters.
*/
promiseFxAOAuthParameters: function() {
return this.hawkRequest("/fxa-oauth/params", "POST").then(response => {
return JSON.parse(response.body);
});
},
/**
* Get the OAuth client constructed with Loop OAauth parameters.
*
* @return {Promise}
*/
promiseFxAOAuthClient: Task.async(function* () {
// We must make sure to have only a single client otherwise they will have different states and
// multiple channels. This would happen if the user clicks the Login button more than once.
if (gFxAOAuthClientPromise) {
return gFxAOAuthClientPromise;
}
gFxAOAuthClientPromise = this.promiseFxAOAuthParameters().then(
parameters => {
try {
gFxAOAuthClient = new FxAccountsOAuthClient({
parameters: parameters,
});
} catch (ex) {
gFxAOAuthClientPromise = null;
throw ex;
}
return gFxAOAuthClient;
},
error => {
gFxAOAuthClientPromise = null;
return error;
}
);
return gFxAOAuthClientPromise;
}),
/**
* Params => web flow => code
*/
promiseFxAOAuthAuthorization: function() {
let deferred = Promise.defer();
this.promiseFxAOAuthClient().then(
client => {
client.onComplete = this._fxAOAuthComplete.bind(this, deferred);
client.launchWebFlow();
},
error => {
Cu.reportError(error);
deferred.reject(error);
}
);
return deferred.promise;
},
/**
* Called once gFxAOAuthClient fires onComplete.
*
* @param {Deferred} deferred used to resolve or reject the gFxAOAuthClientPromise
* @param {Object} result (with code and state)
*/
_fxAOAuthComplete: function(deferred, result) {
gFxAOAuthClientPromise = null;
// Note: The state was already verified in FxAccountsOAuthClient.
if (result) {
deferred.resolve(result);
} else {
deferred.reject("Invalid token data");
}
},
};
Object.freeze(MozLoopServiceInternal);
@ -469,6 +552,17 @@ let gInitializeTimerFunc = () => {
* Public API
*/
this.MozLoopService = {
#ifdef DEBUG
// Test-only helpers
get internal() {
return MozLoopServiceInternal;
},
resetFxA: function() {
gFxAOAuthClientPromise = null;
},
#endif
set initializeTimerFunc(value) {
gInitializeTimerFunc = value;
},
@ -636,6 +730,19 @@ this.MozLoopService = {
}
},
/**
* Start the FxA login flow using the OAuth client and params from the Loop server.
*
* The caller should be prepared to handle rejections related to network, server or login errors.
*
* @return {Promise} that resolves when the FxA login flow is complete.
*/
logInToFxA: function() {
return MozLoopServiceInternal.promiseFxAOAuthAuthorization().then(response => {
return MozLoopServiceInternal.promiseFxAOAuthToken(response.code, response.state);
});
},
/**
* Performs a hawk based request to the loop server.
*

View File

@ -234,11 +234,17 @@ loop.panel = (function(_, mozL10n) {
// readOnly attr will suppress a warning regarding this issue
// from the react lib.
var cx = React.addons.classSet;
var inputCSSClass = cx({
"pending": this.state.pending,
// Used in functional testing, signals that
// call url was received from loop server
"callUrl": !this.state.pending
});
return (
PanelLayout({summary: __("share_link_header_text")},
React.DOM.div({className: "invite"},
React.DOM.input({type: "url", value: this.state.callUrl, readOnly: "true",
className: cx({pending: this.state.pending})}),
className: inputCSSClass}),
React.DOM.p({className: "button-group url-actions"},
React.DOM.button({className: "btn btn-email", disabled: !this.state.callUrl,
onClick: this.handleEmailButtonClick,

View File

@ -234,11 +234,17 @@ loop.panel = (function(_, mozL10n) {
// readOnly attr will suppress a warning regarding this issue
// from the react lib.
var cx = React.addons.classSet;
var inputCSSClass = cx({
"pending": this.state.pending,
// Used in functional testing, signals that
// call url was received from loop server
"callUrl": !this.state.pending
});
return (
<PanelLayout summary={__("share_link_header_text")}>
<div className="invite">
<input type="url" value={this.state.callUrl} readOnly="true"
className={cx({pending: this.state.pending})} />
className={inputCSSClass} />
<p className="button-group url-actions">
<button className="btn btn-email" disabled={!this.state.callUrl}
onClick={this.handleEmailButtonClick}

View File

@ -179,9 +179,10 @@ loop.shared.views = (function(_, OT, l10n) {
render: function() {
/* jshint ignore:start */
var hangupButtonClasses = "btn btn-hangup";
return (
React.DOM.ul({className: "conversation-toolbar"},
React.DOM.li(null, React.DOM.button({className: "btn btn-hangup",
React.DOM.li(null, React.DOM.button({className: hangupButtonClasses,
onClick: this.handleClickHangup,
title: l10n.get("hangup_button_title")})),
React.DOM.li(null, MediaControlButton({action: this.handleToggleVideo,

View File

@ -179,9 +179,10 @@ loop.shared.views = (function(_, OT, l10n) {
render: function() {
/* jshint ignore:start */
var hangupButtonClasses = "btn btn-hangup";
return (
<ul className="conversation-toolbar">
<li><button className="btn btn-hangup"
<li><button className={hangupButtonClasses}
onClick={this.handleClickHangup}
title={l10n.get("hangup_button_title")}></button></li>
<li><MediaControlButton action={this.handleToggleVideo}

View File

@ -15,6 +15,9 @@ BROWSER_CHROME_MANIFESTS += [
EXTRA_JS_MODULES.loop += [
'MozLoopAPI.jsm',
'MozLoopPushHandler.jsm',
'MozLoopService.jsm',
'MozLoopWorker.js',
]
EXTRA_PP_JS_MODULES.loop += [
'MozLoopService.jsm',
]

View File

@ -197,7 +197,6 @@ loop.webapp = (function($, _, OT, webL10n) {
var date = (new Date(callUrlInfo.urlCreationDate * 1000));
var options = {year: "numeric", month: "long", day: "numeric"};
var timestamp = date.toLocaleDateString(navigator.language, options);
this.setState({urlCreationDateString: timestamp});
}
},

View File

@ -197,7 +197,6 @@ loop.webapp = (function($, _, OT, webL10n) {
var date = (new Date(callUrlInfo.urlCreationDate * 1000));
var options = {year: "numeric", month: "long", day: "numeric"};
var timestamp = date.toLocaleDateString(navigator.language, options);
this.setState({urlCreationDateString: timestamp});
}
},

View File

@ -0,0 +1,20 @@
# Loop server configuration
CONTENT_SERVER_PORT = 3001
LOOP_SERVER_PORT = 5001
FIREFOX_PREFERENCES = {
"loop.server": "http://localhost:" + str(LOOP_SERVER_PORT),
"browser.dom.window.dump.enabled": True,
# Need to find the correct Pythonic syntax for this (unless just using
# a string is the way to go), as well as find the bug with the
# other preference for shunting ice to localhost that ekr/drno did,
# and other stuff before we can support offline call tests
# XXX "media.peerconnection.default_iceservers": "[]",
"media.peerconnection.use_document_iceservers": False,
"devtools.chrome.enabled": True,
"devtools.debugger.prompt-connection": False,
"devtools.debugger.remote-enabled": True,
"media.volume_scale": "0",
# this dialog is fragile, and likely to introduce intermittent failures
"media.navigator.permission.disabled": True
}

View File

@ -3,4 +3,4 @@ b2g = false
browser = true
qemu = false
[test_get_url.py]
[test_1_browser_call.py]

View File

@ -0,0 +1,70 @@
# Pull down and configure the loop server
# Start the Loop server
# Start the standalone server
# Other util functions
# noinspection PyUnresolvedReferences
from mozprocess import processhandler
# XXX We want to convince ourselves that the race condition that importing
# hanging_threads.py works around, tracked by bug 1046873, is gone, and get
# rid of this inclusion entirely before we hook our functional tests up to
# Tbpl, so that we don't introduce an intermittent failure.
import sys
import os
sys.path.append(os.path.dirname(__file__))
import hanging_threads
from config import *
CONTENT_SERVER_COMMAND = ["make", "runserver"]
CONTENT_SERVER_ENV = os.environ.copy()
# Set PORT so that it does not interfere with any other
# development server that might be running
CONTENT_SERVER_ENV.update({"PORT": str(CONTENT_SERVER_PORT),
"LOOP_SERVER_PORT": str(LOOP_SERVER_PORT)})
WEB_APP_URL = "http://localhost:" + str(CONTENT_SERVER_PORT) + \
"/content/#call/{token}"
LOOP_SERVER_COMMAND = ["make", "runserver"]
LOOP_SERVER_ENV = os.environ.copy()
# Set PORT so that it does not interfere with any other
# development server that might be running
LOOP_SERVER_ENV.update({"NODE_ENV": "dev",
"PORT": str(LOOP_SERVER_PORT),
"WEB_APP_URL": WEB_APP_URL})
class LoopTestServers:
def __init__(self):
self.loop_server = self.start_loop_server()
self.content_server = self.start_content_server()
@staticmethod
def start_loop_server():
loop_server_location = os.environ.get('LOOP_SERVER')
if loop_server_location is None:
raise Exception('LOOP_SERVER variable not set')
os.chdir(loop_server_location)
p = processhandler.ProcessHandler(LOOP_SERVER_COMMAND,
env=LOOP_SERVER_ENV)
p.run()
return p
@staticmethod
def start_content_server():
content_server_location = os.path.join(os.path.dirname(__file__),
"../../standalone")
os.chdir(content_server_location)
p = processhandler.ProcessHandler(CONTENT_SERVER_COMMAND,
env=CONTENT_SERVER_ENV)
p.run()
return p
def shutdown(self):
self.content_server.kill()
self.loop_server.kill()

View File

@ -0,0 +1,161 @@
from marionette_test import MarionetteTestCase
from by import By
import urlparse
from marionette.errors import NoSuchElementException, StaleElementException
# noinspection PyUnresolvedReferences
from marionette.wait import Wait
from time import sleep
import os
import sys
sys.path.insert(1, os.path.dirname(os.path.abspath(__file__)))
from serversetup import LoopTestServers
from config import *
class Test1BrowserCall(MarionetteTestCase):
# XXX Move this to setup class so it doesn't restart the server
# after every test.
def setUp(self):
# start server
self.loop_test_servers = LoopTestServers()
MarionetteTestCase.setUp(self)
# Unfortunately, enforcing preferences currently comes with the side
# effect of launching and restarting the browser before running the
# real functional tests. Bug 1048554 has been filed to track this.
self.marionette.enforce_gecko_prefs(FIREFOX_PREFERENCES)
# this is browser chrome, kids, not the content window just yet
self.marionette.set_context("chrome")
# taken from https://github.com/mozilla-b2g/gaia/blob/master/tests/python/gaia-ui-tests/gaiatest/gaia_test.py#L858
# XXX factor out into utility object for use by other tests
def wait_for_element_displayed(self, by, locator, timeout=None):
Wait(self.marionette, timeout,
ignored_exceptions=[NoSuchElementException, StaleElementException])\
.until(lambda m: m.find_element(by, locator).is_displayed())
return self.marionette.find_element(by, locator)
# XXX workaround for Marionette bug YYY
def wait_for_element_exists(self, by, locator, timeout=None):
Wait(self.marionette, timeout,
ignored_exceptions=[NoSuchElementException, StaleElementException]) \
.until(lambda m: m.find_element(by, locator))
return self.marionette.find_element(by, locator)
def switch_to_panel(self):
button = self.marionette.find_element(By.ID, "loop-call-button")
# click the element
button.click()
# switch to the frame
frame = self.marionette.find_element(By.ID, "loop")
self.marionette.switch_to_frame(frame)
def load_and_verify_standalone_ui(self, url):
self.marionette.set_context("content")
self.marionette.navigate(url)
call_url_link = self.marionette.find_element(By.CLASS_NAME, "call-url") \
.text
self.assertEqual(url, call_url_link,
"should be on the correct page")
def get_and_verify_call_url(self):
# get and check for a call url
url_input_element = self.wait_for_element_displayed(By.TAG_NAME,
"input")
# wait for pending state to finish
self.assertEqual(url_input_element.get_attribute("class"), "pending",
"expect the input to be pending")
# get and check the input (the "callUrl" class is only added after
# the pending class is removed and the URL has arrived).
#
# XXX should investigate getting rid of the fragile and otherwise
# unnecessary callUrl class and replacing this with a By.CSS_SELECTOR
# and some possible combination of :not and/or an attribute selector
# once bug 1048551 is fixed.
url_input_element = self.wait_for_element_displayed(By.CLASS_NAME,
"callUrl")
call_url = url_input_element.get_attribute("value")
self.assertNotEqual(call_url, u'',
"input is populated with call URL after pending"
" is finished")
self.assertIn(urlparse.urlparse(call_url).scheme, ['http', 'https'],
"call URL returned by server " + call_url +
" has invalid scheme")
return call_url
def start_and_verify_outgoing_call(self):
# make the call!
call_button = self.marionette.find_element(By.CLASS_NAME, "btn-success")
call_button.click()
# expect a video container on standalone side
video = self.wait_for_element_displayed(By.CLASS_NAME, "media")
self.assertEqual(video.tag_name, "div", "expect a video container")
def accept_and_verify_incoming_call(self):
self.marionette.set_context("chrome")
self.marionette.switch_to_frame()
# XXX should be using wait_for_element_displayed, but need to wait
# for Marionette bug 1055309 to be fixed.
chatbox = self.wait_for_element_exists(By.TAG_NAME, 'chatbox')
script = ("return document.getAnonymousElementByAttribute("
"arguments[0], 'class', 'chat-frame');")
frame = self.marionette.execute_script(script, [chatbox])
self.marionette.switch_to_frame(frame)
# Accept the incoming call
call_button = self.marionette.find_element(By.CLASS_NAME,
"btn-success")
# accept call from the desktop side
call_button.click()
# expect a video container on desktop side
video = self.wait_for_element_displayed(By.CLASS_NAME, "media")
self.assertEqual(video.tag_name, "div", "expect a video container")
def hangup_call_and_verify_feedback(self):
self.marionette.set_context("chrome")
button = self.marionette.find_element(By.CLASS_NAME, "btn-hangup")
# XXX For whatever reason, the click doesn't take effect unless we
# wait for a bit (even if we wait for the element to actually be
# displayed first, which we're not currently bothering with). It's
# not entirely clear whether the click is being delivered in this case,
# or whether there's a Marionette bug here.
sleep(2)
button.click()
# check that the feedback form is displayed
feedback_form = self.wait_for_element_displayed(By.CLASS_NAME, "faces")
self.assertEqual(feedback_form.tag_name, "div", "expect feedback form")
def test_1_browser_call(self):
self.switch_to_panel()
call_url = self.get_and_verify_call_url()
# load the link clicker interface into the current content browser
self.load_and_verify_standalone_ui(call_url)
self.start_and_verify_outgoing_call()
# Switch to the conversation window and answer
self.accept_and_verify_incoming_call()
# hangup the call
self.hangup_call_and_verify_feedback()
def tearDown(self):
self.loop_test_servers.shutdown()
MarionetteTestCase.tearDown(self)

View File

@ -1,145 +0,0 @@
from marionette_test import MarionetteTestCase
from marionette.errors import NoSuchElementException
from marionette.errors import StaleElementException
from by import By
# noinspection PyUnresolvedReferences
from marionette.wait import Wait
import os
# noinspection PyUnresolvedReferences
from mozprocess import processhandler
import urlparse
# XXX We want to convince ourselves that the race condition that importing
# hanging_threads.py works around, tracked by bug 1046873, is gone, and get
# rid of this inclusion entirely before we hook our functional tests up to
# Tbpl, so that we don't introduce an intermittent failure.
import sys
sys.path.append(os.path.dirname(__file__))
import hanging_threads
CONTENT_SERVER_PORT = 3001
LOOP_SERVER_PORT = 5001
CONTENT_SERVER_COMMAND = ["make", "runserver"]
CONTENT_SERVER_ENV = os.environ.copy()
# Set PORT so that it does not interfere with any other
# development server that might be running
CONTENT_SERVER_ENV.update({"PORT": str(CONTENT_SERVER_PORT),
"LOOP_SERVER_PORT": str(LOOP_SERVER_PORT)})
WEB_APP_URL = "http://localhost:" + str(CONTENT_SERVER_PORT) + \
"/content/#call/{token}"
LOOP_SERVER_COMMAND = ["make", "runserver"]
LOOP_SERVER_ENV = os.environ.copy()
# Set PORT so that it does not interfere with any other
# development server that might be running
LOOP_SERVER_ENV.update({"NODE_ENV": "dev", "PORT": str(LOOP_SERVER_PORT),
"WEB_APP_URL": WEB_APP_URL})
class LoopTestServers:
def __init__(self):
self.loop_server = self.start_loop_server()
self.content_server = self.start_content_server()
@staticmethod
def start_loop_server():
loop_server_location = os.environ.get('LOOP_SERVER')
if loop_server_location is None:
raise Exception('LOOP_SERVER variable not set')
os.chdir(loop_server_location)
p = processhandler.ProcessHandler(LOOP_SERVER_COMMAND,
env=LOOP_SERVER_ENV)
p.run()
return p
@staticmethod
def start_content_server():
content_server_location = os.path.join(os.path.dirname(__file__),
"../../standalone")
os.chdir(content_server_location)
p = processhandler.ProcessHandler(CONTENT_SERVER_COMMAND,
env=CONTENT_SERVER_ENV)
p.run()
return p
def shutdown(self):
self.content_server.kill()
self.loop_server.kill()
class TestGetUrl(MarionetteTestCase):
# XXX Move this to setup class so it doesn't restart the server
# after every test. This can happen when we write our second test,
# expected to be in bug 976116.
def setUp(self):
# start server
self.loop_test_servers = LoopTestServers()
MarionetteTestCase.setUp(self)
# Unfortunately, enforcing preferences currently comes with the side
# effect of launching and restarting the browser before running the
# real functional tests. Bug 1048554 has been filed to track this.
preferences = {"loop.server": "http://localhost:" + str(LOOP_SERVER_PORT)}
self.marionette.enforce_gecko_prefs(preferences)
# this is browser chrome, kids, not the content window just yet
self.marionette.set_context("chrome")
def switch_to_panel(self):
button = self.marionette.find_element(By.ID, "loop-call-button")
# click the element
button.click()
# switch to the frame
frame = self.marionette.find_element(By.ID, "loop")
self.marionette.switch_to_frame(frame)
# taken from https://github.com/mozilla-b2g/gaia/blob/master/tests/python/gaia-ui-tests/gaiatest/gaia_test.py#L858
# XXX factor out into utility object for use by other tests, this can
# when we write our second test, in bug 976116
def wait_for_element_displayed(self, by, locator, timeout=None):
Wait(self.marionette, timeout,
ignored_exceptions=[NoSuchElementException, StaleElementException])\
.until(lambda m: m.find_element(by, locator).is_displayed())
return self.marionette.find_element(by, locator)
def test_get_url(self):
self.switch_to_panel()
# get and check for a call url
url_input_element = self.wait_for_element_displayed(By.TAG_NAME,
"input")
# wait for pending state to finish
self.assertEqual(url_input_element.get_attribute("class"), "pending",
"expect the input to be pending")
# get and check the input (the "callUrl" class is only added after
# the pending class is removed and the URL has arrived).
#
# XXX should investigate getting rid of the fragile and otherwise
# unnecessary callUrl class and replacing this with a By.CSS_SELECTOR
# and some possible combination of :not and/or an attribute selector
# once bug 1048551 is fixed.
url_input_element = self.wait_for_element_displayed(By.CLASS_NAME,
"callUrl")
call_url = url_input_element.get_attribute("value")
self.assertNotEqual(call_url, u'',
"input is populated with call URL after pending"
" is finished")
self.assertIn(urlparse.urlparse(call_url).scheme, ['http', 'https'],
"call URL returned by server " + call_url +
" has invalid scheme")
def tearDown(self):
self.loop_test_servers.shutdown()
MarionetteTestCase.tearDown(self)

View File

@ -2,7 +2,10 @@
support-files =
head.js
loop_fxa.sjs
../../../../base/content/test/general/browser_fxa_oauth.html
[browser_fxa_login.js]
skip-if = !debug
[browser_loop_fxa_server.js]
[browser_mozLoop_appVersionInfo.js]
[browser_mozLoop_prefs.js]

View File

@ -0,0 +1,92 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test FxA logins with Loop.
*/
"use strict";
const BASE_URL = "http://mochi.test:8888/browser/browser/components/loop/test/mochitest/loop_fxa.sjs?";
add_task(function* setup() {
Services.prefs.setCharPref("loop.server", BASE_URL);
Services.prefs.setCharPref("services.push.serverURL", "ws://localhost/");
registerCleanupFunction(function* () {
info("cleanup time");
yield promiseDeletedOAuthParams(BASE_URL);
Services.prefs.clearUserPref("loop.server");
Services.prefs.clearUserPref("services.push.serverURL");
});
});
add_task(function* checkOAuthParams() {
let params = {
client_id: "client_id",
content_uri: BASE_URL + "/content",
oauth_uri: BASE_URL + "/oauth",
profile_uri: BASE_URL + "/profile",
state: "state",
};
yield promiseOAuthParamsSetup(BASE_URL, params);
let client = yield MozLoopService.internal.promiseFxAOAuthClient();
for (let key of Object.keys(params)) {
ise(client.parameters[key], params[key], "Check " + key + " was passed to the OAuth client");
}
});
add_task(function* basicAuthorization() {
let result = yield MozLoopService.internal.promiseFxAOAuthAuthorization();
is(result.code, "code1", "Check code");
is(result.state, "state", "Check state");
});
add_task(function* sameOAuthClientForTwoCalls() {
MozLoopService.resetFxA();
let client1 = yield MozLoopService.internal.promiseFxAOAuthClient();
let client2 = yield MozLoopService.internal.promiseFxAOAuthClient();
ise(client1, client2, "The same client should be returned");
});
add_task(function* paramsInvalid() {
MozLoopService.resetFxA();
// Delete the params so an empty object is returned.
yield promiseDeletedOAuthParams(BASE_URL);
let result = null;
let loginPromise = MozLoopService.logInToFxA();
let caught = false;
yield loginPromise.catch(() => {
ok(true, "The login promise should be rejected due to invalid params");
caught = true;
});
ok(caught, "Should have caught the rejection");
is(result, null, "No token data should be returned");
});
add_task(function* params_nonJSON() {
MozLoopService.resetFxA();
Services.prefs.setCharPref("loop.server", "https://loop.invalid");
let result = null;
let loginPromise = MozLoopService.logInToFxA();
yield loginPromise.catch(() => {
ok(true, "The login promise should be rejected due to non-JSON params");
});
is(result, null, "No token data should be returned");
Services.prefs.setCharPref("loop.server", BASE_URL);
});
add_task(function* invalidState() {
MozLoopService.resetFxA();
let params = {
client_id: "client_id",
content_uri: BASE_URL + "/content",
oauth_uri: BASE_URL + "/oauth",
profile_uri: BASE_URL + "/profile",
state: "invalid_state",
};
yield promiseOAuthParamsSetup(BASE_URL, params);
let loginPromise = MozLoopService.logInToFxA();
yield loginPromise.catch((error) => {
ok(error, "The login promise should be rejected due to invalid state");
});
});

View File

@ -89,7 +89,7 @@ function promiseDeletedOAuthParams(baseURL) {
createInstance(Ci.nsIXMLHttpRequest);
xhr.open("DELETE", baseURL + "/setup_params", true);
xhr.addEventListener("load", () => deferred.resolve(xhr));
xhr.addEventListener("error", error => deferred.reject(error));
xhr.addEventListener("error", deferred.reject);
xhr.send();
return deferred.promise;

View File

@ -15,13 +15,17 @@ Components.utils.import("resource://gre/modules/NetUtil.jsm");
* Entry point for HTTP requests.
*/
function handleRequest(request, response) {
switch (request.queryString) {
// Look at the query string but ignore past the encoded ? when deciding on the handler.
switch (request.queryString.replace(/%3F.*/,"")) {
case "/setup_params":
setup_params(request, response);
return;
case "/fxa-oauth/params":
params(request, response);
return;
case encodeURIComponent("/oauth/authorization"):
oauth_authorization(request, response);
return;
case "/fxa-oauth/token":
token(request, response);
return;
@ -89,6 +93,16 @@ function params(request, response) {
response.write(JSON.stringify(params, null, 2));
}
/**
* GET /oauth/authorization endpoint for the test params.
*
* Redirect to a test page that uses WebChannel to complete the web flow.
*/
function oauth_authorization(request, response) {
response.setStatusLine(request.httpVersion, 302, "Found");
response.setHeader("Location", "browser_fxa_oauth.html");
}
/**
* POST /fxa-oauth/token
*

View File

@ -1014,33 +1014,6 @@ this.PlacesUIUtils = {
Weave.Service.engineManager.get("tabs") &&
Weave.Service.engineManager.get("tabs").enabled;
},
/**
* Returns the passed URL with a #moz-resolution fragment
* for the specified dimensions and devicePixelRatio.
*
* @param aWindow
* A window from where we want to get the device
* pixel Ratio
*
* @param aURL
* The URL where we should add the fragment
*
* @param aWidth
* The target image width
*
* @param aHeight
* The target image height
*
* @return The URL with the fragment at the end
*/
getImageURLForResolution:
function PUIU_getImageURLForResolution(aWindow, aURL, aWidth = 16, aHeight = 16) {
let width = Math.round(aWidth * aWindow.devicePixelRatio);
let height = Math.round(aHeight * aWindow.devicePixelRatio);
return aURL + (aURL.contains("#") ? "&" : "#") +
"-moz-resolution=" + width + "," + height;
},
};
XPCOMUtils.defineLazyServiceGetter(PlacesUIUtils, "RDF",

View File

@ -363,7 +363,7 @@ PlacesViewBase.prototype = {
let icon = aPlacesNode.icon;
if (icon)
element.setAttribute("image",
PlacesUIUtils.getImageURLForResolution(window, icon));
PlacesUtils.getImageURLForResolution(window, icon));
}
element._placesNode = aPlacesNode;
@ -502,7 +502,7 @@ PlacesViewBase.prototype = {
elt.removeAttribute("image");
else if (icon != elt.getAttribute("image"))
elt.setAttribute("image",
PlacesUIUtils.getImageURLForResolution(window, icon));
PlacesUtils.getImageURLForResolution(window, icon));
},
nodeAnnotationChanged:
@ -1019,7 +1019,7 @@ PlacesToolbar.prototype = {
let icon = aChild.icon;
if (icon)
button.setAttribute("image",
PlacesUIUtils.getImageURLForResolution(window, icon));
PlacesUtils.getImageURLForResolution(window, icon));
if (PlacesUtils.containerTypes.indexOf(type) != -1) {
button.setAttribute("type", "menu");
@ -1844,7 +1844,7 @@ PlacesPanelMenuView.prototype = {
let icon = aChild.icon;
if (icon)
button.setAttribute("image",
PlacesUIUtils.getImageURLForResolution(window, icon));
PlacesUtils.getImageURLForResolution(window, icon));
if (PlacesUtils.containerTypes.indexOf(type) != -1) {
button.setAttribute("container", "true");

View File

@ -1396,7 +1396,11 @@ PlacesTreeView.prototype = {
if (this._getColumnType(aColumn) != this.COLUMN_TYPE_TITLE)
return "";
return this._getNodeForRow(aRow).icon;
let node = this._getNodeForRow(aRow);
if (PlacesUtils.nodeIsURI(node) && node.icon)
return PlacesUtils.getImageURLForResolution(window, node.icon);
return node.icon;
},
getProgressMode: function(aRow, aColumn) { },

View File

@ -125,6 +125,9 @@
<field name="FormHistory" readonly="true">
(Components.utils.import("resource://gre/modules/FormHistory.jsm", {})).FormHistory;
</field>
<field name="PlacesUtils" readonly="true">
(Components.utils.import("resource://gre/modules/PlacesUtils.jsm", {})).PlacesUtils;
</field>
<property name="engines" readonly="true">
<getter><![CDATA[
@ -292,9 +295,7 @@
<parameter name="uri"/>
<body><![CDATA[
if (uri) {
let size = Math.round(16 * window.devicePixelRatio);
if (!uri.contains("#"))
uri += "#-moz-resolution=" + size + "," + size;
uri = this.PlacesUtils.getImageURLForResolution(window, uri);
}
element.setAttribute("src", uri);
]]></body>

View File

@ -13,6 +13,7 @@ var Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm");
@ -45,7 +46,7 @@ this.RecentlyClosedTabsAndWindowsMenuUtils = {
let element = doc.createElementNS(kNSXUL, aTagName);
element.setAttribute("label", closedTabs[i].title);
if (closedTabs[i].image) {
setImage(closedTabs[i], element);
setImage(aWindow, closedTabs[i], element);
}
element.setAttribute("value", i);
if (aTagName == "menuitem") {
@ -117,7 +118,7 @@ this.RecentlyClosedTabsAndWindowsMenuUtils = {
item.setAttribute("label", menuLabel);
let selectedTab = undoItem.tabs[undoItem.selected - 1];
if (selectedTab.image) {
setImage(selectedTab, item);
setImage(aWindow, selectedTab, item);
}
if (aTagName == "menuitem") {
item.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon");
@ -167,10 +168,11 @@ this.RecentlyClosedTabsAndWindowsMenuUtils = {
},
};
function setImage(aItem, aElement) {
let iconURL = aItem.image;
function setImage(aWindow, aItem, aElement) {
let iconURL = PlacesUtils.getImageURLForResolution(aWindow, aItem.image);
// don't initiate a connection just to fetch a favicon (see bug 467828)
if (/^https?:/.test(iconURL))
iconURL = "moz-anno:favicon:" + iconURL;
aElement.setAttribute("image", iconURL);
}

View File

@ -2,6 +2,8 @@
* 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/. */
Components.utils.import('resource://gre/modules/PlacesUtils.jsm');
let FavIcons = {
// Pref that controls whether to display site icons.
PREF_CHROME_SITE_ICONS: "browser.chrome.site_icons",
@ -87,6 +89,8 @@ let FavIcons = {
tabImage = this._favIconService.getFaviconLinkForIcon(tabImageURI).spec;
}
tabImage = PlacesUtils.getImageURLForResolution(window, tabImage);
callback(tabImage);
},
@ -99,7 +103,9 @@ let FavIcons = {
let {currentURI} = tab.linkedBrowser;
this._favIconService.getFaviconURLForPage(currentURI, function (uri) {
if (uri) {
callback(this._favIconService.getFaviconLinkForIcon(uri).spec);
let icon = PlacesUtils.getImageURLForResolution(window,
this._favIconService.getFaviconLinkForIcon(uri).spec);
callback(icon);
} else {
callback(this.defaultFavicon);
}

View File

@ -9,13 +9,13 @@ function test() {
let newState = {
windows: [{
tabs: [{
entries: [{ url: "http://www.google.com" }],
entries: [{ url: "about:mozilla" }],
hidden: true,
attributes: {},
extData: {
"tabview-tab":
'{"bounds":{"left":21,"top":29,"width":204,"height":153},' +
'"userSize":null,"url":"http://www.google.com","groupID":1,' +
'"userSize":null,"url":"about:mozilla","groupID":1,' +
'"imageData":null,"title":null}'
}
},{

View File

@ -23,6 +23,13 @@ function test() {
yield changeManifestValue("name", "the best app");
yield changeManifestValueBad("name", "the worst app");
yield addNewManifestProperty("developer", "foo", "bar");
// add duplicate property in the same parent doesn't create duplicates
yield addNewManifestProperty("developer", "foo", "bar2");
// add propery with same key in other parent is allowed
yield addNewManifestProperty("tester", "foo", "new");
yield addNewManifestPropertyBad("developer", "blob", "bob");
yield removeManifestProperty("developer", "foo");
gManifestWindow = null;
@ -94,15 +101,14 @@ function changeManifestValueBad(key, value) {
}
function addNewManifestProperty(parent, key, value) {
info("Adding new property - parent: " + parent + "; key: " + key + "; value: " + value + "\n\n");
return Task.spawn(function() {
let parentElem = gManifestWindow.document
.querySelector("[id ^= '" + parent + "']");
ok(parentElem,
"Found parent element");
let addPropertyElem = parentElem
.querySelector(".variables-view-add-property");
ok(addPropertyElem,
"Found add-property button");
ok(parentElem, "Found parent element: " + parentElem.id);
let addPropertyElem = parentElem.querySelector(".variables-view-add-property");
ok(addPropertyElem, "Found add-property button");
EventUtils.sendMouseEvent({ type: "mousedown" }, addPropertyElem, gManifestWindow);
@ -116,10 +122,13 @@ function addNewManifestProperty(parent, key, value) {
yield waitForUpdate();
let newElem = gManifestWindow.document.querySelector("[id ^= '" + key + "']");
parentElem = gManifestWindow.document.querySelector("[id ^= '" + parent + "']");
let elems = parentElem.querySelectorAll("[id ^= '" + key + "']");
is(elems.length, 1, "No duplicate property is added");
let newElem = elems[0];
let nameElem = newElem.querySelector(".name");
is(nameElem.value, key,
"Key doesn't match expected Key");
is(nameElem.value, key, "Key doesn't match expected Key");
ok(key in gManifestEditor.manifest[parent],
"Manifest doesn't contain expected key");

View File

@ -2,5 +2,8 @@
"name": "My packaged app",
"developer": {
"name": "Foo Bar"
},
"tester" : {
"who": "qa"
}
}

View File

@ -49,9 +49,16 @@ function connect() {
});
}
// Certain options should be toggled since we can assume chrome debugging here
function setPrefDefaults() {
Services.prefs.setBoolPref("devtools.inspector.showUserAgentStyles", true);
Services.prefs.setBoolPref("devtools.profiler.ui.show-platform-data", true);
}
window.addEventListener("load", function() {
let cmdClose = document.getElementById("toolbox-cmd-close");
cmdClose.addEventListener("command", onCloseCommand);
setPrefDefaults();
connect();
});

View File

@ -295,7 +295,6 @@ function MonitorClient(client, form) {
MonitorClient.prototype.destroy = function () {
this.client.unregisterClient(this);
}
MonitorClient.prototype.detach = function () {}
MonitorClient.prototype.start = function () {
this.client.request({
to: this.actor,

View File

@ -8,7 +8,12 @@ const CLIENT_EVENT_TYPE = "ContentSearchClient";
// Forward events from the in-content service to the test.
content.addEventListener(SERVICE_EVENT_TYPE, event => {
sendAsyncMessage(TEST_MSG, event.detail);
// The event dispatch code in content.js clones the event detail into the
// content scope. That's generally the right thing, but causes us to end
// up with an XrayWrapper to it here, which will screw us up when trying to
// serialize the object in sendAsyncMessage. Waive Xrays for the benefit of
// the test machinery.
sendAsyncMessage(TEST_MSG, Components.utils.waiveXrays(event.detail));
});
// Forward messages from the test to the in-content service.

View File

@ -65,9 +65,10 @@
#newtab-customize-button {
background-color: transparent;
background-image: -moz-image-rect(url(chrome://browser/skin/newtab/controls.svg), 0, 32, 32, 0);
background-size: 28px;
border: none;
height: 32px;
width: 32px;
height: 28px;
width: 28px;
}
#newtab-customize-button:-moz-any(:hover, :active, [active]) {
@ -166,9 +167,10 @@
/* CONTROLS */
.newtab-control {
background-color: transparent;
background-size: 24px;
border: none;
height: 32px;
width: 32px;
height: 24px;
width: 24px;
}
.newtab-control-pin,
@ -199,10 +201,9 @@
}
.newtab-control-sponsored {
width: 24px;
height: 24px;
background-image: url(chrome://browser/skin/newtab/controls.png);
background-position: -249px -1px;
background-size: auto;
}
@media (min-resolution: 2dppx) {

View File

@ -2632,6 +2632,7 @@ nsContentUtils::GenerateStateKey(nsIContent* aContent,
nsIPrincipal*
nsContentUtils::SubjectPrincipal()
{
MOZ_ASSERT(IsInitialized());
JSContext* cx = GetCurrentJSContext();
if (!cx) {
return GetSystemPrincipal();
@ -4697,6 +4698,7 @@ nsContentUtils::CheckSecurityBeforeLoad(nsIURI* aURIToLoad,
bool
nsContentUtils::IsSystemPrincipal(nsIPrincipal* aPrincipal)
{
MOZ_ASSERT(IsInitialized());
return aPrincipal == sSystemPrincipal;
}
@ -4710,6 +4712,7 @@ nsContentUtils::IsExpandedPrincipal(nsIPrincipal* aPrincipal)
nsIPrincipal*
nsContentUtils::GetSystemPrincipal()
{
MOZ_ASSERT(IsInitialized());
return sSystemPrincipal;
}
@ -5521,6 +5524,7 @@ JSContext *
nsContentUtils::GetCurrentJSContext()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(IsInitialized());
return sXPConnect->GetCurrentJSContext();
}
@ -5529,6 +5533,7 @@ JSContext *
nsContentUtils::GetSafeJSContext()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(IsInitialized());
return sXPConnect->GetSafeJSContext();
}
@ -5536,6 +5541,7 @@ nsContentUtils::GetSafeJSContext()
JSContext *
nsContentUtils::GetDefaultJSContextForThread()
{
MOZ_ASSERT(IsInitialized());
if (MOZ_LIKELY(NS_IsMainThread())) {
return GetSafeJSContext();
} else {
@ -5547,6 +5553,7 @@ nsContentUtils::GetDefaultJSContextForThread()
JSContext *
nsContentUtils::GetCurrentJSContextForThread()
{
MOZ_ASSERT(IsInitialized());
if (MOZ_LIKELY(NS_IsMainThread())) {
return GetCurrentJSContext();
} else {

View File

@ -107,9 +107,7 @@ nsDOMFileReader::Init()
// Instead of grabbing some random global from the context stack,
// let's use the default one (junk scope) for now.
// We should move away from this Init...
nsCOMPtr<nsIGlobalObject> global = xpc::GetJunkScopeGlobal();
NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
BindToOwner(global);
BindToOwner(xpc::GetNativeForGlobal(xpc::PrivilegedJunkScope()));
return NS_OK;
}

View File

@ -39,6 +39,7 @@
#include "nsIDocShellTreeItem.h"
#include "nsCOMArray.h"
#include "nsDOMClassInfo.h"
#include "mozilla/Services.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/BasicEvents.h"
@ -2142,7 +2143,7 @@ nsDocument::Init()
// we use the default compartment for this document, instead of creating
// wrapper in some random compartment when the document is exposed to js
// via some events.
nsCOMPtr<nsIGlobalObject> global = xpc::GetJunkScopeGlobal();
nsCOMPtr<nsIGlobalObject> global = xpc::GetNativeForGlobal(xpc::PrivilegedJunkScope());
NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
mScopeObject = do_GetWeakReference(global);
MOZ_ASSERT(mScopeObject);
@ -4494,7 +4495,7 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
return;
}
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (swm) {
swm->MaybeStartControlling(this);
mMaybeServiceWorkerControlled = true;
@ -8526,7 +8527,7 @@ nsDocument::Destroy()
mRegistry = nullptr;
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (swm) {
swm->MaybeStopControlling(this);
}

View File

@ -352,9 +352,7 @@ nsXMLHttpRequest::Init()
// Instead of grabbing some random global from the context stack,
// let's use the default one (junk scope) for now.
// We should move away from this Init...
nsCOMPtr<nsIGlobalObject> global = xpc::GetJunkScopeGlobal();
NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
Construct(subjectPrincipal, global);
Construct(subjectPrincipal, xpc::GetNativeForGlobal(xpc::PrivilegedJunkScope()));
return NS_OK;
}

View File

@ -179,7 +179,6 @@ LOCAL_INCLUDES += [
'/dom/canvas',
'/dom/xbl',
'/editor/libeditor',
'/editor/libeditor/text',
'/editor/txmgr',
'/layout/forms',
'/layout/generic',

View File

@ -261,6 +261,24 @@ AudioNodeStream::SetChannelMixingParameters(uint32_t aNumberOfChannels,
aChannelInterpretation));
}
void
AudioNodeStream::SetPassThrough(bool aPassThrough)
{
class Message : public ControlMessage {
public:
Message(AudioNodeStream* aStream, bool aPassThrough)
: ControlMessage(aStream), mPassThrough(aPassThrough) {}
virtual void Run()
{
static_cast<AudioNodeStream*>(mStream)->mPassThrough = mPassThrough;
}
bool mPassThrough;
};
MOZ_ASSERT(this);
GraphImpl()->AppendMessage(new Message(this, aPassThrough));
}
void
AudioNodeStream::SetChannelMixingParametersImpl(uint32_t aNumberOfChannels,
ChannelCountMode aChannelCountMode,
@ -453,10 +471,15 @@ AudioNodeStream::ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags)
ObtainInputBlock(inputChunks[i], i);
}
bool finished = false;
if (maxInputs <= 1 && mEngine->OutputCount() <= 1) {
mEngine->ProcessBlock(this, inputChunks[0], &mLastChunks[0], &finished);
if (mPassThrough) {
MOZ_ASSERT(outputCount == 1, "For now, we only support nodes that have one output port");
mLastChunks[0] = inputChunks[0];
} else {
mEngine->ProcessBlocksOnPorts(this, inputChunks, mLastChunks, &finished);
if (maxInputs <= 1 && mEngine->OutputCount() <= 1) {
mEngine->ProcessBlock(this, inputChunks[0], &mLastChunks[0], &finished);
} else {
mEngine->ProcessBlocksOnPorts(this, inputChunks, mLastChunks, &finished);
}
}
for (uint16_t i = 0; i < outputCount; ++i) {
NS_ASSERTION(mLastChunks[i].GetDuration() == WEBAUDIO_BLOCK_SIZE,

View File

@ -54,7 +54,8 @@ public:
mKind(aKind),
mNumberOfInputChannels(2),
mMarkAsFinishedAfterThisBlock(false),
mAudioParamStream(false)
mAudioParamStream(false),
mPassThrough(false)
{
MOZ_ASSERT(NS_IsMainThread());
mChannelCountMode = ChannelCountMode::Max;
@ -85,6 +86,7 @@ public:
void SetChannelMixingParameters(uint32_t aNumberOfChannels,
ChannelCountMode aChannelCountMoe,
ChannelInterpretation aChannelInterpretation);
void SetPassThrough(bool aPassThrough);
ChannelInterpretation GetChannelInterpretation()
{
return mChannelInterpretation;
@ -192,6 +194,8 @@ protected:
bool mMarkAsFinishedAfterThisBlock;
// Whether the stream is an AudioParamHelper stream.
bool mAudioParamStream;
// Whether the stream just passes its input through.
bool mPassThrough;
};
}

View File

@ -159,6 +159,7 @@ public:
// Only used by WebMReader and MediaOmxReader for now, so stub here rather
// than in every reader than inherits from MediaDecoderReader.
virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) {}
virtual int64_t GetEvictionOffset(double aTime) { return -1; }
virtual MediaQueue<AudioData>& AudioQueue() { return mAudioQueue; }
virtual MediaQueue<VideoData>& VideoQueue() { return mVideoQueue; }

View File

@ -109,9 +109,10 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
, mVideo("MP4 video decoder data", Preferences::GetUint("media.mp4-video-decode-ahead", 2))
, mLastReportedNumDecodedFrames(0)
, mLayersBackendType(layers::LayersBackend::LAYERS_NONE)
, mTimeRangesMonitor("MP4Reader::TimeRanges")
, mDemuxerInitialized(false)
, mIsEncrypted(false)
, mIndexReady(false)
, mIndexMonitor("MP4 index")
{
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
MOZ_COUNT_CTOR(MP4Reader);
@ -304,6 +305,11 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
bool ok = mDemuxer->Init();
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
{
MonitorAutoLock mon(mIndexMonitor);
mIndexReady = true;
}
mInfo.mVideo.mHasVideo = mVideo.mActive = mDemuxer->HasValidVideo();
const VideoDecoderConfig& video = mDemuxer->VideoConfig();
// If we have video, we *only* allow H.264 to be decoded.
@ -417,6 +423,8 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
*aInfo = mInfo;
*aTags = nullptr;
UpdateIndex();
return NS_OK;
}
@ -774,28 +782,52 @@ MP4Reader::NotifyDataArrived(const char* aBuffer, uint32_t aLength,
void
MP4Reader::UpdateIndex()
{
nsTArray<MediaByteRange> ranges;
nsTArray<Interval<Microseconds>> timeRanges;
MonitorAutoLock mon(mIndexMonitor);
if (!mIndexReady) {
return;
}
MediaResource* resource = mDecoder->GetResource();
resource->Pin();
nsTArray<MediaByteRange> ranges;
if (NS_SUCCEEDED(resource->GetCachedRanges(ranges))) {
mDemuxer->ConvertByteRangesToTime(ranges, &timeRanges);
mDemuxer->UpdateIndex(ranges);
}
resource->Unpin();
MonitorAutoLock mon(mTimeRangesMonitor);
mTimeRanges = timeRanges;
}
int64_t
MP4Reader::GetEvictionOffset(double aTime)
{
MonitorAutoLock mon(mIndexMonitor);
if (!mIndexReady) {
return 0;
}
return mDemuxer->GetEvictionOffset(aTime * 1000000.0);
}
nsresult
MP4Reader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
{
MonitorAutoLock mon(mTimeRangesMonitor);
for (size_t i = 0; i < mTimeRanges.Length(); i++) {
aBuffered->Add((mTimeRanges[i].start - aStartTime) / 1000000.0,
(mTimeRanges[i].end - aStartTime) / 1000000.0);
MonitorAutoLock mon(mIndexMonitor);
if (!mIndexReady) {
return NS_OK;
}
MediaResource* resource = mDecoder->GetResource();
nsTArray<MediaByteRange> ranges;
resource->Pin();
nsresult rv = resource->GetCachedRanges(ranges);
resource->Unpin();
if (NS_SUCCEEDED(rv)) {
nsTArray<Interval<Microseconds>> timeRanges;
mDemuxer->ConvertByteRangesToTime(ranges, &timeRanges);
for (size_t i = 0; i < timeRanges.Length(); i++) {
aBuffered->Add((timeRanges[i].start - aStartTime) / 1000000.0,
(timeRanges[i].end - aStartTime) / 1000000.0);
}
}
return NS_OK;

View File

@ -55,6 +55,8 @@ public:
virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength,
int64_t aOffset) MOZ_OVERRIDE;
virtual int64_t GetEvictionOffset(double aTime) MOZ_OVERRIDE;
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered,
int64_t aStartTime) MOZ_OVERRIDE;
@ -181,14 +183,15 @@ private:
layers::LayersBackend mLayersBackendType;
nsTArray<nsTArray<uint8_t>> mInitDataEncountered;
Monitor mTimeRangesMonitor;
nsTArray<mp4_demuxer::Interval<Microseconds>> mTimeRanges;
// True if we've read the streams' metadata.
bool mDemuxerInitialized;
// Synchronized by decoder monitor.
bool mIsEncrypted;
bool mIndexReady;
Monitor mIndexMonitor;
};
} // namespace mozilla

View File

@ -112,11 +112,16 @@ SubBufferDecoder::GetBuffered(dom::TimeRanges* aBuffered)
int64_t
SubBufferDecoder::ConvertToByteOffset(double aTime)
{
int64_t readerOffset = mReader->GetEvictionOffset(aTime);
if (readerOffset >= 0) {
return readerOffset;
}
// Uses a conversion based on (aTime/duration) * length. For the
// purposes of eviction this should be adequate since we have the
// byte threshold as well to ensure data actually gets evicted and
// we ensure we don't evict before the current playable point.
if (mMediaDuration == -1) {
if (mMediaDuration <= 0) {
return -1;
}
int64_t length = GetResource()->GetLength();

View File

@ -65,6 +65,7 @@ AudioNode::AudioNode(AudioContext* aContext,
, mChannelCountMode(aChannelCountMode)
, mChannelInterpretation(aChannelInterpretation)
, mId(gId++)
, mPassThrough(false)
#ifdef DEBUG
, mDemiseNotified(false)
#endif
@ -416,5 +417,22 @@ AudioNode::RemoveOutputParam(AudioParam* aParam)
mOutputParams.RemoveElement(aParam);
}
bool
AudioNode::PassThrough() const
{
MOZ_ASSERT(NumberOfInputs() == 1 && NumberOfOutputs() == 1);
return mPassThrough;
}
void
AudioNode::SetPassThrough(bool aPassThrough)
{
MOZ_ASSERT(NumberOfInputs() == 1 && NumberOfOutputs() == 1);
mPassThrough = aPassThrough;
AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());
MOZ_ASSERT(ns, "How come we don't have a stream here?");
ns->SetPassThrough(mPassThrough);
}
}
}

View File

@ -133,6 +133,9 @@ public:
uint32_t Id() const { return mId; }
bool PassThrough() const;
void SetPassThrough(bool aPassThrough);
uint32_t ChannelCount() const { return mChannelCount; }
virtual void SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv)
{
@ -267,6 +270,9 @@ private:
ChannelCountMode mChannelCountMode;
ChannelInterpretation mChannelInterpretation;
const uint32_t mId;
// Whether the node just passes through its input. This is a devtools API that
// only works for some node types.
bool mPassThrough;
#ifdef DEBUG
// In debug builds, check to make sure that the node demise notification has
// been properly sent before the node is destroyed.

View File

@ -24,6 +24,8 @@ support-files =
webaudio.js
[test_analyserNode.html]
[test_analyserNodeOutput.html]
[test_analyserNodePassThrough.html]
[test_AudioBuffer.html]
[test_audioBufferSourceNode.html]
[test_audioBufferSourceNodeEnded.html]
@ -49,6 +51,7 @@ skip-if = (toolkit == 'gonk' && !debug) || (toolkit == 'android') #bug 906752
[test_audioParamTimelineDestinationOffset.html]
[test_badConnect.html]
[test_biquadFilterNode.html]
[test_biquadFilterNodePassThrough.html]
[test_biquadFilterNodeWithGain.html]
[test_bug808374.html]
[test_bug827541.html]
@ -74,6 +77,7 @@ skip-if = (toolkit == 'gonk' && !debug) || (toolkit == 'android') #bug 906752
[test_convolverNode.html]
[test_convolverNode_mono_mono.html]
[test_convolverNodeChannelCount.html]
[test_convolverNodePassThrough.html]
[test_convolverNodeWithGain.html]
[test_currentTime.html]
[test_decodeMultichannel.html]
@ -81,6 +85,7 @@ skip-if = (toolkit == 'gonk' && !debug) || (toolkit == 'android') #bug 906752
[test_delayNodeAtMax.html]
[test_delayNodeChannelChanges.html]
[test_delayNodeCycles.html]
[test_delayNodePassThrough.html]
[test_delayNodeSmallMaxDelay.html]
[test_delayNodeTailIncrease.html]
[test_delayNodeTailWithDisconnect.html]
@ -88,8 +93,10 @@ skip-if = (toolkit == 'gonk' && !debug) || (toolkit == 'android') #bug 906752
[test_delayNodeTailWithReconnect.html]
[test_delayNodeWithGain.html]
[test_dynamicsCompressorNode.html]
[test_dynamicsCompressorNodePassThrough.html]
[test_gainNode.html]
[test_gainNodeInLoop.html]
[test_gainNodePassThrough.html]
[test_maxChannelCount.html]
[test_mediaDecoding.html]
[test_mediaElementAudioSourceNode.html]
@ -125,4 +132,5 @@ skip-if = (toolkit == 'gonk' && !debug)
[test_waveDecoder.html]
[test_waveShaper.html]
[test_waveShaperNoCurve.html]
[test_waveShaperPassThrough.html]
[test_waveShaperZeroLengthCurve.html]

View File

@ -0,0 +1,43 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test AnalyserNode</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var source = context.createBufferSource();
var analyser = context.createAnalyser();
source.buffer = this.buffer;
source.connect(analyser);
source.start(0);
return analyser;
},
createExpectedBuffers: function(context) {
this.buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
this.buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
}
return [this.buffer];
},
};
runTest();
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test AnalyserNode with passthrough</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var source = context.createBufferSource();
var analyser = context.createAnalyser();
source.buffer = this.buffer;
source.connect(analyser);
var analyserWrapped = SpecialPowers.wrap(analyser);
ok("passThrough" in analyserWrapped, "AnalyserNode should support the passThrough API");
analyserWrapped.passThrough = true;
source.start(0);
return analyser;
},
createExpectedBuffers: function(context) {
this.buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
this.buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
}
return [this.buffer];
},
};
runTest();
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test BiquadFilterNode with passthrough</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var source = context.createBufferSource();
var filter = context.createBiquadFilter();
source.buffer = this.buffer;
source.connect(filter);
var filterWrapped = SpecialPowers.wrap(filter);
ok("passThrough" in filterWrapped, "BiquadFilterNode should support the passThrough API");
filterWrapped.passThrough = true;
source.start(0);
return filter;
},
createExpectedBuffers: function(context) {
this.buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
this.buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
}
return [this.buffer];
},
};
runTest();
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,48 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test ConvolverNode with passthrough</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var source = context.createBufferSource();
var convolver = context.createConvolver();
source.buffer = this.buffer;
convolver.buffer = this.buffer;
source.connect(convolver);
var convolverWrapped = SpecialPowers.wrap(convolver);
ok("passThrough" in convolverWrapped, "ConvolverNode should support the passThrough API");
convolverWrapped.passThrough = true;
source.start(0);
return convolver;
},
createExpectedBuffers: function(context) {
this.buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
this.buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
}
return [this.buffer];
},
};
runTest();
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,53 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test DelayNode</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script src="webaudio.js" type="text/javascript"></script>
<script class="testbody" type="text/javascript">
var gTest = {
length: 4096,
numberOfChannels: 1,
createGraph: function(context) {
var source = context.createBufferSource();
var delay = context.createDelay();
source.buffer = this.buffer;
source.connect(delay);
delay.delayTime.value = 0.5;
// Delay the source stream by 2048 frames
delay.delayTime.value = 2048 / context.sampleRate;
var delayWrapped = SpecialPowers.wrap(delay);
ok("passThrough" in delayWrapped, "DelayNode should support the passThrough API");
delayWrapped.passThrough = true;
source.start(0);
return delay;
},
createExpectedBuffers: function(context) {
this.buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
this.buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
}
var silence = context.createBuffer(1, 2048, context.sampleRate);
return [this.buffer, silence];
},
};
runTest();
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test DynamicsCompressorNode with passthrough</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var source = context.createBufferSource();
var compressor = context.createDynamicsCompressor();
source.buffer = this.buffer;
source.connect(compressor);
var compressorWrapped = SpecialPowers.wrap(compressor);
ok("passThrough" in compressorWrapped, "DynamicsCompressorNode should support the passThrough API");
compressorWrapped.passThrough = true;
source.start(0);
return compressor;
},
createExpectedBuffers: function(context) {
this.buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
this.buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
}
return [this.buffer];
},
};
runTest();
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,49 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test GainNode with passthrough</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var source = context.createBufferSource();
var gain = context.createGain();
source.buffer = this.buffer;
source.connect(gain);
gain.gain.value = 0.5;
var gainWrapped = SpecialPowers.wrap(gain);
ok("passThrough" in gainWrapped, "GainNode should support the passThrough API");
gainWrapped.passThrough = true;
source.start(0);
return gain;
},
createExpectedBuffers: function(context) {
this.buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
this.buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
}
return [this.buffer];
},
};
runTest();
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,53 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test PannerNode with passthrough</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var source = context.createBufferSource();
var panner = context.createPanner();
source.buffer = this.buffer;
source.connect(panner);
context.listener.setOrientation(0, 6.311749985202524e+307, 0, 0.1, 1000, 0);
context.listener.setOrientation(0, 0, -6.311749985202524e+307, 0, 0, 6.311749985202524e+307);
panner.setPosition(2, 0, 0);
panner.rolloffFactor = 0;
panner.panningModel = "equalpower";
var pannerWrapped = SpecialPowers.wrap(panner);
ok("passThrough" in pannerWrapped, "PannerNode should support the passThrough API");
pannerWrapped.passThrough = true;
source.start(0);
return panner;
},
createExpectedBuffers: function(context) {
this.buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
this.buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
}
return [this.buffer];
},
};
runTest();
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,55 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test WaveShaperNode with passthrough</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var gTest = {
length: 4096,
numberOfChannels: 1,
createGraph: function(context) {
var source = context.createBufferSource();
source.buffer = this.buffer;
var shaper = context.createWaveShaper();
shaper.curve = this.curve;
var shaperWrapped = SpecialPowers.wrap(shaper);
ok("passThrough" in shaperWrapped, "WaveShaperNode should support the passThrough API");
shaperWrapped.passThrough = true;
source.connect(shaper);
source.start(0);
return shaper;
},
createExpectedBuffers: function(context) {
this.buffer = context.createBuffer(1, 4096, context.sampleRate);
for (var i = 1; i < 4095; ++i) {
this.buffer.getChannelData(0)[i] = 2 * (i / 4096) - 1;
}
// Two out of range values
this.buffer.getChannelData(0)[0] = -2;
this.buffer.getChannelData(0)[4095] = 2;
this.curve = new Float32Array(2048);
for (var i = 0; i < 2048; ++i) {
this.curve[i] = Math.sin(100 * Math.PI * (i + 1) / context.sampleRate);
}
return [this.buffer];
},
};
runTest();
</script>
</pre>
</body>
</html>

View File

@ -2531,7 +2531,7 @@ nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
{
NS_ENSURE_TRUE(aProtoDoc, NS_ERROR_UNEXPECTED);
AutoSafeJSContext cx;
JS::Rooted<JSObject*> global(cx, xpc::GetCompilationScope());
JS::Rooted<JSObject*> global(cx, xpc::CompilationScope());
NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
JSAutoCompartment ac(cx, global);
@ -2553,8 +2553,7 @@ nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
// been set.
JS::Handle<JSScript*> script =
JS::Handle<JSScript*>::fromMarkedLocation(mScriptObject.address());
// Note - Inverting the order of these operands is a rooting hazard.
MOZ_ASSERT(xpc::GetCompilationScope() == JS::CurrentGlobalOrNull(cx));
MOZ_ASSERT(xpc::CompilationScope() == JS::CurrentGlobalOrNull(cx));
return nsContentUtils::XPConnect()->WriteScript(aStream, cx,
xpc_UnmarkGrayScript(script));
}
@ -2621,7 +2620,7 @@ nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream,
aStream->Read32(&mLangVersion);
AutoSafeJSContext cx;
JS::Rooted<JSObject*> global(cx, xpc::GetCompilationScope());
JS::Rooted<JSObject*> global(cx, xpc::CompilationScope());
NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
JSAutoCompartment ac(cx, global);
@ -2731,7 +2730,7 @@ NotifyOffThreadScriptCompletedRunnable::Run()
JSScript *script;
{
AutoSafeJSContext cx;
JSAutoCompartment ac(cx, xpc::GetCompilationScope());
JSAutoCompartment ac(cx, xpc::CompilationScope());
script = JS::FinishOffThreadScript(cx, JS_GetRuntime(cx), mToken);
}
@ -2757,9 +2756,8 @@ nsXULPrototypeScript::Compile(JS::SourceBufferHolder& aSrcBuf,
nsIOffThreadScriptReceiver *aOffThreadReceiver /* = nullptr */)
{
// We'll compile the script in the compilation scope.
NS_ENSURE_TRUE(xpc::GetCompilationScope(), NS_ERROR_UNEXPECTED);
AutoSafeJSContext cx;
JSAutoCompartment ac(cx, xpc::GetCompilationScope());
JSAutoCompartment ac(cx, xpc::CompilationScope());
nsAutoCString urlspec;
nsContentUtils::GetWrapperSafeScriptFilename(aDocument, aURI, urlspec);

View File

@ -1113,7 +1113,7 @@ Console::ProcessCallData(ConsoleCallData* aData)
// mStorage, but that's a bit fragile. Instead, we just use the junk scope,
// with explicit permission from the XPConnect module owner. If you're
// tempted to do that anywhere else, talk to said module owner first.
JSAutoCompartment ac2(cx, xpc::GetJunkScope());
JSAutoCompartment ac2(cx, xpc::PrivilegedJunkScope());
JS::Rooted<JS::Value> eventValue(cx);
if (!ToJSValue(cx, event, &eventValue)) {

View File

@ -499,7 +499,7 @@ ThreadsafeAutoJSContext::operator JSContext*() const
AutoSafeJSContext::AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
: AutoJSContext(true MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
, mAc(mCx, XPCJSRuntime::Get()->GetJSContextStack()->GetSafeJSContextGlobal())
, mAc(mCx, xpc::UnprivilegedJunkScope())
{
}

View File

@ -124,7 +124,7 @@ nsJSUtils::ReportPendingException(JSContext *aContext)
// The SafeJSContext has no default object associated with it.
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aContext == nsContentUtils::GetSafeJSContext());
scope = xpc::GetSafeJSContextGlobal();
scope = xpc::UnprivilegedJunkScope(); // Usage approved by bholley
}
JSAutoCompartment ac(aContext, scope);
JS_ReportPendingException(aContext);

View File

@ -81,6 +81,13 @@ GetPluginMimeTypes(const nsTArray<nsRefPtr<nsPluginElement> >& aPlugins,
}
}
static bool
operator<(const nsRefPtr<nsMimeType>& lhs, const nsRefPtr<nsMimeType>& rhs)
{
// Sort MIME types alphabetically by type name.
return lhs->Type() < rhs->Type();
}
void
nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes,
nsTArray<nsRefPtr<nsMimeType> >& aHiddenMimeTypes)
@ -96,6 +103,10 @@ nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes,
GetPluginMimeTypes(mPlugins, aMimeTypes);
GetPluginMimeTypes(mHiddenPlugins, aHiddenMimeTypes);
// Alphabetize the enumeration order of non-hidden MIME types to reduce
// fingerprintable entropy based on plugins' installation file times.
aMimeTypes.Sort();
}
nsPluginElement*
@ -297,6 +308,14 @@ IsPluginEnumerable(const nsTArray<nsCString>& enumerableNames,
return false; // hide plugin!
}
static bool
operator<(const nsRefPtr<nsPluginElement>& lhs,
const nsRefPtr<nsPluginElement>& rhs)
{
// Sort plugins alphabetically by name.
return lhs->PluginTag()->mName < rhs->PluginTag()->mName;
}
void
nsPluginArray::EnsurePlugins()
{
@ -345,6 +364,10 @@ nsPluginArray::EnsurePlugins()
pluginArray.AppendElement(new nsPluginElement(mWindow, pluginTag));
}
// Alphabetize the enumeration order of non-hidden plugins to reduce
// fingerprintable entropy based on plugins' installation file times.
mPlugins.Sort();
}
// nsPluginElement implementation.

View File

@ -11104,7 +11104,7 @@ class CGDictionary(CGThing):
AutoJSAPI jsapi;
jsapi.Init();
JSContext *cx = jsapi.cx();
JSAutoCompartment ac(cx, xpc::GetSafeJSContextGlobal()); // Usage approved by bholley
JSAutoCompartment ac(cx, xpc::UnprivilegedJunkScope()); // Usage approved by bholley
JS::Rooted<JS::Value> obj(cx);
return ToObjectInternal(cx, &obj) && StringifyToJSON(cx, &obj, aJSON);
"""))
@ -11892,7 +11892,7 @@ class CGBindingRoot(CGThing):
bindingHeaders["WrapperFactory.h"] = descriptors
bindingHeaders["mozilla/dom/DOMJSClass.h"] = descriptors
bindingHeaders["mozilla/dom/ScriptSettings.h"] = dictionaries # AutoJSAPI
bindingHeaders["xpcpublic.h"] = dictionaries ## xpc::GetSafeJSContextGlobal
bindingHeaders["xpcpublic.h"] = dictionaries ## xpc::UnprivilegedJunkScope
# Do codegen for all the dictionaries. We have to be a bit careful
# here, because we have to generate these in order from least derived

View File

@ -495,7 +495,7 @@ SmsRequestParent::DoRequest(const SendMessageRequest& aRequest)
// jsval to ::Send. Only system code should be looking at the result here,
// so we just create it in the System-Principaled Junk Scope.
AutoJSContext cx;
JSAutoCompartment ac(cx, xpc::GetJunkScope());
JSAutoCompartment ac(cx, xpc::PrivilegedJunkScope());
JS::Rooted<JS::Value> params(cx);
const SendMmsMessageRequest &req = aRequest.get_SendMmsMessageRequest();
if (!GetParamsFromSendMmsMessageRequest(cx,

View File

@ -13,6 +13,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=667388
<![CDATA[
// Setup.
const Cu = Components.utils;
SimpleTest.waitForExplicitFinish();
window.testObject = { myNumber: 42,
myDomain: window.location.domain };
@ -25,34 +26,34 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=667388
// Mark this frame as loaded.
framesLoaded[id] = true;
// Allow it to call |is|.
// Allow it to call various helpers.
window.frames[id].wrappedJSObject.is = is;
window.frames[id].wrappedJSObject.ok = ok;
window.frames[id].wrappedJSObject.info = info;
// If all the frames are loaded, start the test.
if (framesLoaded[1] && framesLoaded[2] && framesLoaded[3])
startTest();
}
function reject(e) {
ok(false, "Rejected Promise: " + e);
SimpleTest.finish();
}
function startTest() {
// Test interaction between chrome and content.
runChromeContentTest(window.frames[1]);
// Try same origin.
runContentContentTest(window.frames[1], window.frames[2],
true, "Should be able to clone same-origin");
// Try cross-origin.
runContentContentTest(window.frames[2], window.frames[3],
false, "Should not be able to clone cross-origin");
// Colaborate with document.domain, then try again.
frames[2].document.domain = 'example.org';
frames[3].document.domain = 'example.org';
runContentContentTest(window.frames[2], window.frames[3],
true, "Should be able to clone cross-origin with document.domain")
SimpleTest.finish();
runChromeContentTest(window.frames[1]).then(
runContentContentTest.bind(null, window.frames[1], window.frames[2],
true, "Should be able to clone same-origin"), reject).then(
runContentContentTest.bind(null, window.frames[2], window.frames[3],
false, "Should not be able to clone cross-origin"), reject).then(function() {
// Colaborate with document.domain, then try again.
frames[2].document.domain = 'example.org';
frames[3].document.domain = 'example.org';
return runContentContentTest(window.frames[2], window.frames[3],
true, "Should be able to clone cross-origin with document.domain")
}, reject).then(SimpleTest.finish.bind(SimpleTest), reject);
}
// Tests cloning between chrome and content.
@ -63,12 +64,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=667388
true,
"Chrome should be able to clone content object");
// Content should not be able to clone a chrome object.
//
// Note that because we're using |wrappedJSObject| here, the subject
// principal is clamed to the principal of the iframe, which is what we want.
contentWin.wrappedJSObject.tryToClone(window.testObject, false,
"Content should not be able to clone chrome object");
// COWs without __exposedProps__ silently deny property gets. So Content
// should be able to clone a COW, but the result of the clone should be empty.
var p = contentWin.wrappedJSObject.tryToClone(window.testObject, true,
"Content should be able to clone COW");
return new Promise(function(resolve) {
p.then(function(cloneResult) {
is(Cu.waiveXrays(cloneResult).toSource(), "({})", "Empty COW clone");
resolve();
});
});
}
// Test cloning between content and content.
@ -81,24 +86,19 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=667388
// long as the security wrappers check documentDomainMakesSameOrigin directly
// for the puncture case rather than checking IsTransparent(), but it still
// gives rise to a situation that wouldn't really happen in practice.
//
// A more serious issues is that we don't/can't test the Xray wrapper path,
// because the only native objects that we successfully send through
// structured clone don't force a parent in PreCreate, and so we _can't_
// have security wrappers around them (we get a new XPCWN in each
// compartment). Since the case can't happen, we can't write tests for it.
// But when it can happen (ie, we fix PreCreate for File, FileList, Blob, etc),
// we want tests right away, because this stuff is very security-sensitive.
// So we set this test up to fail when things are fixed, so that the someone
// will notice and properly augment this test to cover native objects.
function runContentContentTest(win1, win2, shouldSucceed, msg) {
win1.wrappedJSObject.tryToClone(win2.wrappedJSObject.testObject,
shouldSucceed, msg);
var fixMsg = "If this fails, you fixed PreCreate. That's a good thing, ";
fixMsg += "but now we need some test coverage. See the above comment.";
win1.wrappedJSObject.tryToClone(win2.wrappedJSObject.blob, true, fixMsg);
win1.wrappedJSObject.tryToClone(win2.wrappedJSObject.filelist, true, fixMsg);
var p = win1.wrappedJSObject.tryToClone(win2.wrappedJSObject.testObject,
shouldSucceed, msg);
if (!shouldSucceed)
return;
return new Promise(function(resolve) {
p.then(function(cloneResult) {
is(Cu.waiveXrays(cloneResult).toSource(), win2.wrappedJSObject.testObject.toSource(),
"Clone should create an identical object");
resolve();
});
});
}
function tryToClone(obj, shouldSucceed, message) {

View File

@ -3,27 +3,34 @@
<head>
<script type="application/javascript">
function waitForMessage() {
return new Promise(function(resolve) {
window.addEventListener('message', function l(evt) {
window.removeEventListener('message', l);
resolve(evt.data);
});
});
}
// Set up the objects for cloning.
function setup() {
window.testObject = { myNumber: 42,
myDomain: window.location.domain };
window.blob = new Blob([], { type: 'text/plain' });
window.fileList = document.getElementById('fileinput').files;
myString: "hello",
myImageData: new ImageData(10, 10) };
}
// Called by the chrome parent window.
function tryToClone(obj, shouldSucceed, message) {
var success = false;
var sink = window.frames[0];
try { sink.postMessage(obj, '*'); success = true; }
try { window.postMessage(obj, '*'); success = true; }
catch (e) { message = message + ' (threw: ' + e.message + ')'; }
is(success, shouldSucceed, message);
return (success && shouldSucceed) ? waitForMessage() : Promise.resolve();
}
</script>
</head>
<body onload="setup()">
<input id="fileinput" type="file"></input>
<iframe id="sink">
</body>
</html>

View File

@ -143,7 +143,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=633602
parent.addEventListener("click", parentClickTest);
child.addEventListener("click", childClickTest);
SimpleTest.executeSoon(function () {
synthesizeMouseAtCenter(child, {type: "click"}, window);
synthesizeMouseAtCenter(child, {}, window);
});
};

View File

@ -35,3 +35,6 @@ interface AnalyserNode : AudioNode {
};
// Mozilla extension
AnalyserNode implements AudioNodePassThrough;

View File

@ -48,4 +48,9 @@ partial interface AudioNode {
[ChromeOnly]
readonly attribute unsigned long id;
};
[NoInterfaceObject]
interface AudioNodePassThrough {
[ChromeOnly]
attribute boolean passThrough;
};

View File

@ -35,3 +35,6 @@ interface BiquadFilterNode : AudioNode {
};
// Mozilla extension
BiquadFilterNode implements AudioNodePassThrough;

View File

@ -18,3 +18,6 @@ interface ConvolverNode : AudioNode {
};
// Mozilla extension
ConvolverNode implements AudioNodePassThrough;

View File

@ -16,3 +16,6 @@ interface DelayNode : AudioNode {
};
// Mozilla extension
DelayNode implements AudioNodePassThrough;

View File

@ -21,3 +21,6 @@ interface DynamicsCompressorNode : AudioNode {
};
// Mozilla extension
DynamicsCompressorNode implements AudioNodePassThrough;

View File

@ -16,3 +16,6 @@ interface GainNode : AudioNode {
};
// Mozilla extension
GainNode implements AudioNodePassThrough;

View File

@ -44,3 +44,6 @@ interface PannerNode : AudioNode {
};
// Mozilla extension
PannerNode implements AudioNodePassThrough;

View File

@ -18,3 +18,6 @@ interface ScriptProcessorNode : AudioNode {
};
// Mozilla extension
ScriptProcessorNode implements AudioNodePassThrough;

View File

@ -23,3 +23,6 @@ interface WaveShaperNode : AudioNode {
};
// Mozilla extension
WaveShaperNode implements AudioNodePassThrough;

View File

@ -9,6 +9,7 @@
#include "nsIDocument.h"
#include "nsIServiceWorkerManager.h"
#include "nsPIDOMWindow.h"
#include "mozilla/Services.h"
#include "nsCycleCollectionParticipant.h"
#include "nsServiceManagerUtils.h"
@ -60,10 +61,9 @@ ServiceWorkerContainer::Register(const nsAString& aScriptURL,
{
nsCOMPtr<nsISupports> promise;
nsresult rv;
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (!swm) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
@ -83,10 +83,9 @@ ServiceWorkerContainer::Unregister(const nsAString& aScope,
{
nsCOMPtr<nsISupports> promise;
nsresult rv;
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (!swm) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
@ -138,8 +137,8 @@ ServiceWorkerContainer::GetController()
{
if (!mControllerWorker) {
nsresult rv;
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (!swm) {
return nullptr;
}
@ -177,7 +176,7 @@ ServiceWorkerContainer::GetReady(ErrorResult& aRv)
void
ServiceWorkerContainer::StartListeningForEvents()
{
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (swm) {
swm->AddContainerEventListener(mWindow->GetDocumentURI(), this);
}
@ -186,7 +185,7 @@ ServiceWorkerContainer::StartListeningForEvents()
void
ServiceWorkerContainer::StopListeningForEvents()
{
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (swm) {
swm->RemoveContainerEventListener(mWindow->GetDocumentURI(), this);
}
@ -212,8 +211,8 @@ already_AddRefed<workers::ServiceWorker>
ServiceWorkerContainer::GetWorkerReference(WhichServiceWorker aWhichOne)
{
nsresult rv;
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (!swm) {
return nullptr;
}
@ -254,10 +253,9 @@ ServiceWorkerContainer::GetScopeForUrl(const nsAString& aUrl,
nsString& aScope,
ErrorResult& aRv)
{
nsresult rv;
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (!swm) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}

View File

@ -607,8 +607,7 @@ ServiceWorkerManager::Unregister(nsIDOMWindow* aWindow, const nsAString& aScope,
already_AddRefed<ServiceWorkerManager>
ServiceWorkerManager::GetInstance()
{
nsCOMPtr<nsIServiceWorkerManager> swm =
do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
nsRefPtr<ServiceWorkerManager> concrete = do_QueryObject(swm);
return concrete.forget();
}

View File

@ -359,7 +359,6 @@ void
AssertInCompilationScope()
{
AutoJSContext cx;
// Note - Inverting the order of these operands is a rooting hazard.
MOZ_ASSERT(xpc::GetCompilationScope() == JS::CurrentGlobalOrNull(cx));
MOZ_ASSERT(xpc::CompilationScope() == JS::CurrentGlobalOrNull(cx));
}
#endif

View File

@ -240,8 +240,7 @@ nsXBLProtoImpl::CompilePrototypeMembers(nsXBLPrototypeBinding* aBinding)
// bind the prototype to a real xbl instance, we'll clone the pre-compiled JS into the real instance's
// context.
AutoSafeJSContext cx;
JS::Rooted<JSObject*> compilationGlobal(cx, xpc::GetCompilationScope());
NS_ENSURE_TRUE(compilationGlobal, NS_ERROR_UNEXPECTED);
JS::Rooted<JSObject*> compilationGlobal(cx, xpc::CompilationScope());
JSAutoCompartment ac(cx, compilationGlobal);
mPrecompiledMemberHolder = JS_NewObjectWithGivenProto(cx, nullptr, JS::NullPtr(), compilationGlobal);

View File

@ -911,8 +911,7 @@ nsXBLPrototypeBinding::Read(nsIObjectInputStream* aStream,
}
AutoSafeJSContext cx;
JS::Rooted<JSObject*> compilationGlobal(cx, xpc::GetCompilationScope());
NS_ENSURE_TRUE(compilationGlobal, NS_ERROR_UNEXPECTED);
JS::Rooted<JSObject*> compilationGlobal(cx, xpc::CompilationScope());
JSAutoCompartment ac(cx, compilationGlobal);
bool isFirstBinding = aFlags & XBLBinding_Serialize_IsFirstBinding;
@ -1064,8 +1063,7 @@ nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream)
// computed on demand.
AutoSafeJSContext cx;
JS::Rooted<JSObject*> compilationGlobal(cx, xpc::GetCompilationScope());
NS_ENSURE_TRUE(compilationGlobal, NS_ERROR_UNEXPECTED);
JS::Rooted<JSObject*> compilationGlobal(cx, xpc::CompilationScope());
JSAutoCompartment ac(cx, compilationGlobal);
uint8_t flags = mInheritStyle ? XBLBinding_Serialize_InheritStyle : 0;

View File

@ -2,8 +2,6 @@
# 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 libeditor/html/crashtests/crashtests.list
include libeditor/crashtests/crashtests.list
include libeditor/text/crashtests/crashtests.list
include composer/crashtests/crashtests.list
include txmgr/tests/crashtests/crashtests.list

Some files were not shown because too many files have changed in this diff Show More