mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 10:00:54 +00:00
Merge mozilla-central to b2g-inbound
This commit is contained in:
commit
45230b6414
@ -97,3 +97,5 @@ if CONFIG['MOZ_ENABLE_GTK']:
|
||||
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -57,3 +57,5 @@ else:
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -43,3 +43,5 @@ else:
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -38,3 +38,5 @@ LOCAL_INCLUDES += [
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -48,3 +48,5 @@ else:
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -725,6 +725,8 @@ var CustomEventManager = {
|
||||
CaptivePortalLoginHelper.handleEvent(detail);
|
||||
break;
|
||||
case 'inputmethod-update-layouts':
|
||||
case 'inputregistry-add':
|
||||
case 'inputregistry-remove':
|
||||
KeyboardHelper.handleEvent(detail);
|
||||
break;
|
||||
case 'do-command':
|
||||
@ -868,7 +870,17 @@ let IndexedDBPromptHelper = {
|
||||
|
||||
let KeyboardHelper = {
|
||||
handleEvent: function keyboard_handleEvent(detail) {
|
||||
Keyboard.setLayouts(detail.layouts);
|
||||
switch (detail.type) {
|
||||
case 'inputmethod-update-layouts':
|
||||
Keyboard.setLayouts(detail.layouts);
|
||||
|
||||
break;
|
||||
case 'inputregistry-add':
|
||||
case 'inputregistry-remove':
|
||||
Keyboard.inputRegistryGlue.returnMessage(detail);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -979,7 +979,7 @@ chatbox:-moz-full-screen-ancestor > .chat-titlebar {
|
||||
|
||||
/* Combobox dropdown renderer */
|
||||
#ContentSelectDropdown {
|
||||
max-height: 400px;
|
||||
-moz-binding: url("chrome://global/content/bindings/popup.xml#popup-scrollbars");
|
||||
}
|
||||
|
||||
.contentSelectDropdown-optgroup {
|
||||
|
@ -490,5 +490,4 @@ skip-if = e10s # Bug 1100687 - test directly manipulates content (content.docume
|
||||
skip-if = e10s # bug 1100687 - test directly manipulates content (content.document.getElementById)
|
||||
[browser_mcb_redirect.js]
|
||||
skip-if = e10s # bug 1084504 - [e10s] Mixed content detection does not take redirection into account
|
||||
[browser_updatecommands.js]
|
||||
[browser_windowactivation.js]
|
||||
|
@ -1,93 +0,0 @@
|
||||
let testPage = "data:text/html,<body><input id='input1' value='value'><select size=2><option val=1>One</select></body>";
|
||||
|
||||
let browser;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
gURLBar.focus();
|
||||
|
||||
var tab = gBrowser.addTab();
|
||||
browser = gBrowser.getBrowserForTab(tab);
|
||||
gBrowser.selectedTab = tab;
|
||||
|
||||
addEventListener("commandupdate", checkTest, false);
|
||||
|
||||
function runFirstTest(event) {
|
||||
browser.removeEventListener("load", runFirstTest, true);
|
||||
doTest();
|
||||
}
|
||||
|
||||
browser.addEventListener("load", runFirstTest, true);
|
||||
browser.contentWindow.location = testPage;
|
||||
}
|
||||
|
||||
let currentTest;
|
||||
|
||||
let tests = [
|
||||
// Switch focus to 'input1'. Paste and select all should be enabled.
|
||||
{ name: "focus input", test: function() { EventUtils.synthesizeKey("VK_TAB", {}) },
|
||||
commands: { "cmd_copy" : true, "cmd_paste": true, "cmd_selectAll" : true, "cmd_undo" : false, "cmd_redo": false } },
|
||||
|
||||
// Move cursor to end which will deselect the text. Copy should be disabled but paste and select all should still be enabled.
|
||||
{ name: "cursor right", test: function() { EventUtils.synthesizeKey("VK_RIGHT", {}) },
|
||||
commands: { "cmd_copy" : false, "cmd_paste": true, "cmd_selectAll" : true, "cmd_undo" : false, "cmd_redo": false } },
|
||||
|
||||
// Select all of the text. Copy should become enabled.
|
||||
{ name: "select all", test: function() { EventUtils.synthesizeKey("a", { accelKey: true }) },
|
||||
commands: { "cmd_copy" : true, "cmd_paste": true, "cmd_selectAll" : true, "cmd_undo" : false, "cmd_redo": false } },
|
||||
|
||||
// Replace the text with 'c'. Copy should now be disabled and undo enabled.
|
||||
{ name: "change value", test: function() { EventUtils.synthesizeKey("c", {}) },
|
||||
commands: { "cmd_copy" : false, "cmd_paste": true, "cmd_selectAll" : true, "cmd_undo" : true, "cmd_redo": false } },
|
||||
|
||||
// Undo. Undo should be disabled and redo enabled. The text is reselected so copy is enabled.
|
||||
{ name: "undo", test: function() { EventUtils.synthesizeKey("z", {accelKey: true }) },
|
||||
commands: { "cmd_copy" : true, "cmd_paste": true, "cmd_selectAll" : true, "cmd_undo" : false, "cmd_redo": true } },
|
||||
|
||||
// Switch focus to the select. Only select all should now be enabled.
|
||||
{ name: "focus select", test: function() { EventUtils.synthesizeKey("VK_TAB", {}) },
|
||||
commands: { "cmd_copy" : false, "cmd_paste": false, "cmd_selectAll" : true, "cmd_undo" : false, "cmd_redo": false } },
|
||||
];
|
||||
|
||||
function doTest()
|
||||
{
|
||||
if (!tests.length) {
|
||||
removeEventListener("commandupdate", checkTest, false);
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
currentTest = tests.shift();
|
||||
currentTest.test();
|
||||
}
|
||||
|
||||
function checkTest(event)
|
||||
{
|
||||
// Ignore commandupdates before the test starts
|
||||
if (document.activeElement != browser || !currentTest) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip events fired on command updaters other than the main edit menu one.
|
||||
if (event.target != document.getElementById("editMenuCommandSetAll")) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let command in currentTest.commands) {
|
||||
// Command updates can come several at a time, and, especially with multiple
|
||||
// processes, the updates can come asynchronously. Handle this by just waiting
|
||||
// until the command have the correct state. The test will timeout if the
|
||||
// correct command update never occurs.
|
||||
if ((document.getElementById(command).getAttribute("disabled") != "true") != currentTest.commands[command]) {
|
||||
return;
|
||||
}
|
||||
|
||||
is(document.getElementById(command).getAttribute("disabled") != "true", currentTest.commands[command],
|
||||
currentTest["name"] + " " + command);
|
||||
}
|
||||
|
||||
currentTest = null; // prevent the check from running again
|
||||
SimpleTest.executeSoon(doTest);
|
||||
}
|
@ -203,6 +203,17 @@ BrowserToolboxProcess.prototype = {
|
||||
dumpn("Running chrome debugging process.");
|
||||
let args = ["-no-remote", "-foreground", "-profile", this._dbgProfilePath, "-chrome", xulURI];
|
||||
|
||||
// During local development, incremental builds can trigger the main process
|
||||
// to clear its startup cache with the "flag file" .purgecaches, but this
|
||||
// file is removed during app startup time, so we aren't able to know if it
|
||||
// was present in order to also clear the child profile's startup cache as
|
||||
// well.
|
||||
//
|
||||
// As an approximation of "isLocalBuild", check for an unofficial build.
|
||||
if (!Services.appinfo.isOfficial) {
|
||||
args.push("-purgecaches");
|
||||
}
|
||||
|
||||
process.runwAsync(args, args.length, { observe: () => this.close() });
|
||||
|
||||
this._telemetry.toolOpened("jsbrowserdebugger");
|
||||
|
@ -205,11 +205,23 @@ this.ContentSearch = {
|
||||
"searchString",
|
||||
"whence",
|
||||
]);
|
||||
let browserWin = msg.target.ownerDocument.defaultView;
|
||||
let engine = Services.search.getEngineByName(data.engineName);
|
||||
browserWin.BrowserSearch.recordSearchInHealthReport(engine, data.whence, data.selection);
|
||||
let submission = engine.getSubmission(data.searchString, "", data.whence);
|
||||
browserWin.loadURI(submission.uri.spec, null, submission.postData);
|
||||
let browser = msg.target;
|
||||
try {
|
||||
browser.loadURIWithFlags(submission.uri.spec,
|
||||
Ci.nsIWebNavigation.LOAD_FLAGS_NONE, null, null,
|
||||
submission.postData);
|
||||
}
|
||||
catch (err) {
|
||||
// The browser may have been closed between the time its content sent the
|
||||
// message and the time we handle it. In that case, trying to call any
|
||||
// method on it will throw.
|
||||
return Promise.resolve();
|
||||
}
|
||||
let win = browser.ownerDocument.defaultView;
|
||||
win.BrowserSearch.recordSearchInHealthReport(engine, data.whence,
|
||||
data.selection || null);
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
|
@ -102,24 +102,34 @@ add_task(function* search() {
|
||||
});
|
||||
let submissionURL =
|
||||
engine.getSubmission(data.searchString, "", data.whence).uri.spec;
|
||||
let deferred = Promise.defer();
|
||||
let listener = {
|
||||
onStateChange: function (webProg, req, flags, status) {
|
||||
let url = req.originalURI.spec;
|
||||
info("onStateChange " + url);
|
||||
let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
|
||||
Ci.nsIWebProgressListener.STATE_START;
|
||||
if ((flags & docStart) && webProg.isTopLevel && url == submissionURL) {
|
||||
gBrowser.removeProgressListener(listener);
|
||||
ok(true, "Search URL loaded");
|
||||
req.cancel(Components.results.NS_ERROR_FAILURE);
|
||||
deferred.resolve();
|
||||
}
|
||||
}
|
||||
yield waitForLoadAndStopIt(gBrowser.selectedBrowser, submissionURL);
|
||||
});
|
||||
|
||||
add_task(function* searchInBackgroundTab() {
|
||||
// This test is like search(), but it opens a new tab after starting a search
|
||||
// in another. In other words, it performs a search in a background tab. The
|
||||
// search page should be loaded in the same tab that performed the search, in
|
||||
// the background tab.
|
||||
yield addTab();
|
||||
let searchBrowser = gBrowser.selectedBrowser;
|
||||
let engine = Services.search.currentEngine;
|
||||
let data = {
|
||||
engineName: engine.name,
|
||||
searchString: "ContentSearchTest",
|
||||
whence: "ContentSearchTest",
|
||||
};
|
||||
gBrowser.addProgressListener(listener);
|
||||
info("Waiting for search URL to load: " + submissionURL);
|
||||
yield deferred.promise;
|
||||
gMsgMan.sendAsyncMessage(TEST_MSG, {
|
||||
type: "Search",
|
||||
data: data,
|
||||
});
|
||||
|
||||
let newTab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = newTab;
|
||||
registerCleanupFunction(() => gBrowser.removeTab(newTab));
|
||||
|
||||
let submissionURL =
|
||||
engine.getSubmission(data.searchString, "", data.whence).uri.spec;
|
||||
yield waitForLoadAndStopIt(searchBrowser, submissionURL);
|
||||
});
|
||||
|
||||
add_task(function* badImage() {
|
||||
@ -319,6 +329,33 @@ function waitForNewEngine(basename, numImages) {
|
||||
return Promise.all([addDeferred.promise].concat(eventPromises));
|
||||
}
|
||||
|
||||
function waitForLoadAndStopIt(browser, expectedURL) {
|
||||
let deferred = Promise.defer();
|
||||
let listener = {
|
||||
onStateChange: function (webProg, req, flags, status) {
|
||||
if (req instanceof Ci.nsIChannel) {
|
||||
let url = req.originalURI.spec;
|
||||
info("onStateChange " + url);
|
||||
let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
|
||||
Ci.nsIWebProgressListener.STATE_START;
|
||||
if ((flags & docStart) && webProg.isTopLevel && url == expectedURL) {
|
||||
browser.removeProgressListener(listener);
|
||||
ok(true, "Expected URL loaded");
|
||||
req.cancel(Components.results.NS_ERROR_FAILURE);
|
||||
deferred.resolve();
|
||||
}
|
||||
}
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference,
|
||||
]),
|
||||
};
|
||||
browser.addProgressListener(listener);
|
||||
info("Waiting for URL to load: " + expectedURL);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function addTab() {
|
||||
let deferred = Promise.defer();
|
||||
let tab = gBrowser.addTab();
|
||||
|
@ -507,7 +507,7 @@ class Automation(object):
|
||||
env['NS_TRACE_MALLOC_DISABLE_STACKS'] = '1'
|
||||
|
||||
# Set WebRTC logging in case it is not set yet
|
||||
env.setdefault('NSPR_LOG_MODULES', 'signaling:5,mtransport:5,datachannel:5')
|
||||
env.setdefault('NSPR_LOG_MODULES', 'signaling:5,mtransport:5,datachannel:5,jsep:5,MediaPipelineFactory:5')
|
||||
env.setdefault('R_LOG_LEVEL', '6')
|
||||
env.setdefault('R_LOG_DESTINATION', 'stderr')
|
||||
env.setdefault('R_LOG_VERBOSE', '1')
|
||||
|
@ -410,7 +410,7 @@ def environment(xrePath, env=None, crashreporter=True, debugger=False, dmdPath=N
|
||||
env.setdefault('MOZ_DISABLE_NONLOCAL_CONNECTIONS', '1')
|
||||
|
||||
# Set WebRTC logging in case it is not set yet
|
||||
env.setdefault('NSPR_LOG_MODULES', 'signaling:5,mtransport:5,datachannel:5')
|
||||
env.setdefault('NSPR_LOG_MODULES', 'signaling:5,mtransport:5,datachannel:5,jsep:5,MediaPipelineFactory:5')
|
||||
env.setdefault('R_LOG_LEVEL', '6')
|
||||
env.setdefault('R_LOG_DESTINATION', 'stderr')
|
||||
env.setdefault('R_LOG_VERBOSE', '1')
|
||||
|
@ -38,3 +38,4 @@ LOCAL_INCLUDES += [
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -42,3 +42,5 @@ LOCAL_INCLUDES += [
|
||||
|
||||
if CONFIG['MOZ_ENABLE_GTK']:
|
||||
CXXFLAGS += CONFIG['TK_CFLAGS']
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsCaret.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsIXULWindow.h"
|
||||
#include "nsViewManager.h"
|
||||
#include "nsFrameSelection.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
@ -735,10 +734,7 @@ nsFocusManager::WindowRaised(nsIDOMWindow* aWindow)
|
||||
frameSelection->SetDragState(false);
|
||||
}
|
||||
|
||||
// If there is no nsIXULWindow, then this is an embedded or child process window.
|
||||
// Pass false for aWindowRaised so that commands get updated.
|
||||
nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(baseWindow));
|
||||
Focus(currentWindow, currentFocus, 0, true, false, xulWin != nullptr, true);
|
||||
Focus(currentWindow, currentFocus, 0, true, false, true, true);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -9270,36 +9270,6 @@ nsGlobalWindow::ShowModalDialog(const nsAString& aURI, nsIVariant *aArgs_,
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
|
||||
class ChildCommandDispatcher : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ChildCommandDispatcher(nsGlobalWindow* aWindow,
|
||||
nsITabChild* aTabChild,
|
||||
const nsAString& aAction)
|
||||
: mWindow(aWindow), mTabChild(aTabChild), mAction(aAction) {}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsCOMPtr<nsPIWindowRoot> root = mWindow->GetTopWindowRoot();
|
||||
if (!root) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsTArray<nsCString> enabledCommands, disabledCommands;
|
||||
root->GetEnabledDisabledCommands(enabledCommands, disabledCommands);
|
||||
if (enabledCommands.Length() || disabledCommands.Length()) {
|
||||
mTabChild->EnableDisableCommands(mAction, enabledCommands, disabledCommands);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<nsGlobalWindow> mWindow;
|
||||
nsCOMPtr<nsITabChild> mTabChild;
|
||||
nsString mAction;
|
||||
};
|
||||
|
||||
class CommandDispatcher : public nsRunnable
|
||||
{
|
||||
public:
|
||||
@ -9319,12 +9289,6 @@ public:
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::UpdateCommands(const nsAString& anAction, nsISelection* aSel, int16_t aReason)
|
||||
{
|
||||
// If this is a child process, redirect to the parent process.
|
||||
if (nsCOMPtr<nsITabChild> child = do_GetInterface(GetDocShell())) {
|
||||
nsContentUtils::AddScriptRunner(new ChildCommandDispatcher(this, child, anAction));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsPIDOMWindow *rootWindow = nsGlobalWindow::GetPrivateRoot();
|
||||
if (!rootWindow)
|
||||
return NS_OK;
|
||||
|
@ -15,8 +15,8 @@ class nsIControllers;
|
||||
class nsIController;
|
||||
|
||||
#define NS_IWINDOWROOT_IID \
|
||||
{ 0x728a2682, 0x55c0, 0x4860, \
|
||||
{ 0x82, 0x6b, 0x0c, 0x30, 0x0a, 0xac, 0xaa, 0x60 } }
|
||||
{ 0x3f71f50c, 0xa7e0, 0x43bc, \
|
||||
{ 0xac, 0x25, 0x4d, 0xbb, 0x88, 0x7b, 0x21, 0x09 } }
|
||||
|
||||
class nsPIWindowRoot : public mozilla::dom::EventTarget
|
||||
{
|
||||
@ -33,9 +33,6 @@ public:
|
||||
nsIController** aResult) = 0;
|
||||
virtual nsresult GetControllers(nsIControllers** aResult) = 0;
|
||||
|
||||
virtual void GetEnabledDisabledCommands(nsTArray<nsCString>& aEnabledCommands,
|
||||
nsTArray<nsCString>& aDisabledCommands) = 0;
|
||||
|
||||
virtual void SetParentTarget(mozilla::dom::EventTarget* aTarget) = 0;
|
||||
virtual mozilla::dom::EventTarget* GetParentTarget() = 0;
|
||||
virtual nsIDOMWindow* GetOwnerGlobal() MOZ_OVERRIDE = 0;
|
||||
|
@ -281,75 +281,6 @@ nsWindowRoot::GetControllerForCommand(const char * aCommand,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsWindowRoot::GetEnabledDisabledCommandsForControllers(nsIControllers* aControllers,
|
||||
nsTHashtable<nsCharPtrHashKey>& aCommandsHandled,
|
||||
nsTArray<nsCString>& aEnabledCommands,
|
||||
nsTArray<nsCString>& aDisabledCommands)
|
||||
{
|
||||
uint32_t controllerCount;
|
||||
aControllers->GetControllerCount(&controllerCount);
|
||||
for (uint32_t c = 0; c < controllerCount; c++) {
|
||||
nsCOMPtr<nsIController> controller;
|
||||
aControllers->GetControllerAt(c, getter_AddRefs(controller));
|
||||
|
||||
nsCOMPtr<nsICommandController> commandController(do_QueryInterface(controller));
|
||||
if (commandController) {
|
||||
uint32_t commandsCount;
|
||||
char** commands;
|
||||
if (NS_SUCCEEDED(commandController->GetSupportedCommands(&commandsCount, &commands))) {
|
||||
for (uint32_t e = 0; e < commandsCount; e++) {
|
||||
// Use a hash to determine which commands have already been handled by
|
||||
// earlier controllers, as the earlier controller's result should get
|
||||
// priority.
|
||||
if (!aCommandsHandled.Contains(commands[e])) {
|
||||
aCommandsHandled.PutEntry(commands[e]);
|
||||
|
||||
bool enabled = false;
|
||||
controller->IsCommandEnabled(commands[e], &enabled);
|
||||
|
||||
const nsDependentCSubstring commandStr(commands[e], strlen(commands[e]));
|
||||
if (enabled) {
|
||||
aEnabledCommands.AppendElement(commandStr);
|
||||
} else {
|
||||
aDisabledCommands.AppendElement(commandStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(commandsCount, commands);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsWindowRoot::GetEnabledDisabledCommands(nsTArray<nsCString>& aEnabledCommands,
|
||||
nsTArray<nsCString>& aDisabledCommands)
|
||||
{
|
||||
nsTHashtable<nsCharPtrHashKey> commandsHandled;
|
||||
|
||||
nsCOMPtr<nsIControllers> controllers;
|
||||
GetControllers(getter_AddRefs(controllers));
|
||||
if (controllers) {
|
||||
GetEnabledDisabledCommandsForControllers(controllers, commandsHandled,
|
||||
aEnabledCommands, aDisabledCommands);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> focusedWindow;
|
||||
nsFocusManager::GetFocusedDescendant(mWindow, true, getter_AddRefs(focusedWindow));
|
||||
while (focusedWindow) {
|
||||
focusedWindow->GetControllers(getter_AddRefs(controllers));
|
||||
if (controllers) {
|
||||
GetEnabledDisabledCommandsForControllers(controllers, commandsHandled,
|
||||
aEnabledCommands, aDisabledCommands);
|
||||
}
|
||||
|
||||
nsGlobalWindow* win = static_cast<nsGlobalWindow*>(focusedWindow.get());
|
||||
focusedWindow = win->GetPrivateParent();
|
||||
}
|
||||
}
|
||||
|
||||
nsIDOMNode*
|
||||
nsWindowRoot::GetPopupNode()
|
||||
{
|
||||
|
@ -23,8 +23,6 @@ class EventChainPreVisitor;
|
||||
#include "nsPIWindowRoot.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
class nsWindowRoot : public nsPIWindowRoot
|
||||
{
|
||||
@ -54,9 +52,6 @@ public:
|
||||
virtual nsresult GetControllerForCommand(const char * aCommand,
|
||||
nsIController** _retval) MOZ_OVERRIDE;
|
||||
|
||||
virtual void GetEnabledDisabledCommands(nsTArray<nsCString>& aEnabledCommands,
|
||||
nsTArray<nsCString>& aDisabledCommands) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsIDOMNode* GetPopupNode() MOZ_OVERRIDE;
|
||||
virtual void SetPopupNode(nsIDOMNode* aNode) MOZ_OVERRIDE;
|
||||
|
||||
@ -77,11 +72,6 @@ public:
|
||||
protected:
|
||||
virtual ~nsWindowRoot();
|
||||
|
||||
void GetEnabledDisabledCommandsForControllers(nsIControllers* aControllers,
|
||||
nsTHashtable<nsCharPtrHashKey>& aCommandsHandled,
|
||||
nsTArray<nsCString>& aEnabledCommands,
|
||||
nsTArray<nsCString>& aDisabledCommands);
|
||||
|
||||
// Members
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
// We own the manager, which owns event listeners attached to us.
|
||||
|
@ -278,9 +278,9 @@ nsresult TestIgnoreUpperLowerCasePolicies() {
|
||||
return runTestSuite(policies, policyCount, 1);
|
||||
}
|
||||
|
||||
// ============================= TestIgnorePaths ========================
|
||||
// ============================= TestPaths ========================
|
||||
|
||||
nsresult TestIgnorePaths() {
|
||||
nsresult TestPaths() {
|
||||
|
||||
static const PolicyTest policies[] =
|
||||
{
|
||||
@ -360,6 +360,12 @@ nsresult TestIgnorePaths() {
|
||||
"report-uri http://www.example.com:8888/path_1/path_2/report.sjs&301" },
|
||||
{ "report-uri /examplepath",
|
||||
"report-uri http://www.selfuri.com/examplepath" },
|
||||
{ "connect-src http://www.example.com/foo%3Bsessionid=12%2C34",
|
||||
"connect-src http://www.example.com/foo;sessionid=12,34" },
|
||||
{ "connect-src http://www.example.com/foo%3bsessionid=12%2c34",
|
||||
"connect-src http://www.example.com/foo;sessionid=12,34" },
|
||||
{ "connect-src http://test.com/pathIncludingAz19-._~!$&'()*+=:@",
|
||||
"connect-src http://test.com/pathincludingaz19-._~!$&'()*+=:@" },
|
||||
};
|
||||
|
||||
uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
|
||||
@ -492,6 +498,10 @@ nsresult TestPoliciesWithInvalidSrc() {
|
||||
"script-src 'none'" },
|
||||
{ "script-src http://www.example.com:*.",
|
||||
"script-src 'none'" },
|
||||
{ "connect-src http://www.example.com/foo%zz;",
|
||||
"connect-src 'none'" },
|
||||
{ "script-src https://foo.com/%$",
|
||||
"script-src 'none'" },
|
||||
};
|
||||
|
||||
uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
|
||||
@ -1083,7 +1093,7 @@ int main(int argc, char** argv) {
|
||||
if (NS_FAILED(TestDirectives())) { return 1; }
|
||||
if (NS_FAILED(TestKeywords())) { return 1; }
|
||||
if (NS_FAILED(TestIgnoreUpperLowerCasePolicies())) { return 1; }
|
||||
if (NS_FAILED(TestIgnorePaths())) { return 1; }
|
||||
if (NS_FAILED(TestPaths())) { return 1; }
|
||||
if (NS_FAILED(TestSimplePolicies())) { return 1; }
|
||||
if (NS_FAILED(TestPoliciesWithInvalidSrc())) { return 1; }
|
||||
if (NS_FAILED(TestBadPolicies())) { return 1; }
|
||||
|
@ -20,6 +20,8 @@ var tests = { "font-src": thisSite+page+"?testid=font-src&csp=1",
|
||||
"style-src": thisSite+page+"?testid=style-src&csp=1",
|
||||
"worker": thisSite+page+"?testid=worker&csp=1",
|
||||
"xhr-src": thisSite+page+"?testid=xhr-src&csp=1",
|
||||
"script-src-from-worker": thisSite+page+"?testid=script-src-from-worker&csp=1",
|
||||
"img-src-from-css": thisSite+page+"?testid=img-src-from-css&csp=1",
|
||||
};
|
||||
|
||||
var container = document.getElementById("container");
|
||||
|
@ -76,4 +76,21 @@ function handleRequest(request, response)
|
||||
response.write('<script src="'+resource+'?res=xhr"></script>');
|
||||
return;
|
||||
}
|
||||
|
||||
// for bug949706
|
||||
if (query["testid"] == "img-src-from-css") {
|
||||
// loads a stylesheet, which in turn loads an image that redirects.
|
||||
response.write('<link rel="stylesheet" type="text/css" href="'+resource+'?res=cssLoader&id=img-src-redir-from-css">');
|
||||
return;
|
||||
}
|
||||
|
||||
if (query["testid"] == "script-src-from-worker") {
|
||||
// loads a script; launches a worker; that worker uses importscript; which then gets redirected
|
||||
// So it's:
|
||||
// <script "res=loadWorkerThatImports">
|
||||
// .. loads Worker("res=importScriptWorker")
|
||||
// .. calls importScript("res=script")
|
||||
response.write('<script src="'+resource+'?res=loadWorkerThatImports&id=script-src-redir-from-worker"></script>');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -92,6 +92,34 @@ function handleRequest(request, response)
|
||||
return;
|
||||
}
|
||||
|
||||
// internal stylesheet that loads an image from an external site
|
||||
if (query["res"] == "cssLoader") {
|
||||
let bgURL = thisSite + resource + '?redir=other&res=image&id=' + query["id"];
|
||||
response.setHeader("Content-Type", "text/css", false);
|
||||
response.write("body { background:url('" + bgURL + "'); }");
|
||||
return;
|
||||
}
|
||||
|
||||
// script that loads an internal worker that uses importScripts on a redirect
|
||||
// to an external script.
|
||||
if (query["res"] == "loadWorkerThatImports") {
|
||||
// this creates a worker (same origin) that imports a redirecting script.
|
||||
let workerURL = thisSite + resource + '?res=importScriptWorker&id=' + query["id"];
|
||||
response.setHeader("Content-Type", "application/javascript", false);
|
||||
response.write("var w=new Worker('" + workerURL + "'); w.onmessage=function(event){ alert(event.data); }");
|
||||
return;
|
||||
}
|
||||
|
||||
// source for a worker that simply calls importScripts on a script that
|
||||
// redirects.
|
||||
if (query["res"] == "importScriptWorker") {
|
||||
// this is code for a worker that imports a redirected script.
|
||||
let scriptURL = thisSite + resource + "?redir=other&res=script&id=" + query["id"];
|
||||
response.setHeader("Content-Type", "application/javascript", false);
|
||||
response.write("importScripts('" + scriptURL + "');");
|
||||
return;
|
||||
}
|
||||
|
||||
// script that invokes XHR
|
||||
if (query["res"] == "xhr") {
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
|
9
dom/base/test/csp/file_worker_redirect.html
Normal file
9
dom/base/test/csp/file_worker_redirect.html
Normal file
@ -0,0 +1,9 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 949706 - CSP: Correct handling of web workers importing scripts that get redirected</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="file_worker_redirect.sjs?stage_0_script_loads_worker"></script>
|
||||
</body>
|
||||
</html>
|
37
dom/base/test/csp/file_worker_redirect.sjs
Normal file
37
dom/base/test/csp/file_worker_redirect.sjs
Normal file
@ -0,0 +1,37 @@
|
||||
// testserver customized for the needs of:
|
||||
// Bug 949706 - CSP: Correct handling of web workers importing scripts that get redirected
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
|
||||
var query = request.queryString;
|
||||
|
||||
if (query === "stage_0_script_loads_worker") {
|
||||
var newWorker =
|
||||
"var myWorker = new Worker(\"file_worker_redirect.sjs?stage_1_worker_import_scripts\");" +
|
||||
"myWorker.onmessage = function (event) { parent.checkResult(\"allowed\"); };" +
|
||||
"myWorker.onerror = function (event) { parent.checkResult(\"blocked\"); };";
|
||||
response.write(newWorker);
|
||||
return;
|
||||
}
|
||||
|
||||
if (query === "stage_1_worker_import_scripts") {
|
||||
response.write("importScripts(\"file_worker_redirect.sjs?stage_2_redirect_imported_script\");");
|
||||
return;
|
||||
}
|
||||
|
||||
if (query === "stage_2_redirect_imported_script") {
|
||||
var newLocation =
|
||||
"http://test1.example.com/tests/dom/base/test/csp/file_worker_redirect.sjs?stage_3_target_script";
|
||||
response.setStatusLine("1.1", 302, "Found");
|
||||
response.setHeader("Location", newLocation, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (query === "stage_3_target_script") {
|
||||
response.write("postMessage(\"imported script loaded\");");
|
||||
return;
|
||||
}
|
||||
}
|
@ -101,6 +101,8 @@ support-files =
|
||||
file_multi_policy_injection_bypass_2.html
|
||||
file_multi_policy_injection_bypass_2.html^headers^
|
||||
file_form-action.html
|
||||
file_worker_redirect.html
|
||||
file_worker_redirect.sjs
|
||||
|
||||
[test_base-uri.html]
|
||||
[test_connect-src.html]
|
||||
@ -147,3 +149,4 @@ skip-if = buildapp == 'b2g' # intermittent orange (bug 1028490)
|
||||
[test_subframe_run_js_if_allowed.html]
|
||||
[test_leading_wildcard.html]
|
||||
[test_multi_policy_injection_bypass.html]
|
||||
[test_worker_redirect.html]
|
||||
|
@ -86,6 +86,10 @@ var testExpectedResults = { "font-src": true,
|
||||
"worker-redir": false,
|
||||
"xhr-src": true,
|
||||
"xhr-src-redir": false,
|
||||
"script-src-from-worker": true, /* test runs */
|
||||
"script-src-redir-from-worker": false, /* redir is blocked */
|
||||
"img-src-from-css": true, /* test runs */
|
||||
"img-src-redir-from-css": false, /* redir is blocked */
|
||||
};
|
||||
|
||||
// takes the name of the test, the URL that was tested, and whether the
|
||||
|
76
dom/base/test/csp/test_worker_redirect.html
Normal file
76
dom/base/test/csp/test_worker_redirect.html
Normal file
@ -0,0 +1,76 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 949706 - CSP: Correct handling of web workers importing scripts that get redirected</title>
|
||||
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="content" style="visibility: hidden">
|
||||
<iframe style="width:100%;" id="testframe"></iframe>
|
||||
</div>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/* Description of the test:
|
||||
* We load a page that loads a script which then instantiates a web worker,
|
||||
* where that web worker then imports a script which gets redirected.
|
||||
* We verify that the CSP applies correctly after the imported script of
|
||||
* the worker gets redirected. More specifically, the test works as follows:
|
||||
*
|
||||
* test_worker_redirect.html
|
||||
* -> loads file_worker_redirect.html file into iframe
|
||||
* -> loads worker file_worker_redirect.sjs?stage_0_script_loads_worker
|
||||
* -> creates script file_worker_redirect.sjs?stage_1_worker_import_scripts
|
||||
* -> redirects script file_worker_redirect.sjs?stage_2_redirect_imported_script
|
||||
* -> loads target script file_worker_redirect.sjs?stage_3_target_script
|
||||
*
|
||||
* Please note that we have to use 'unsafe-eval' in the policy
|
||||
* so that workers are actually permitted by the CSP.
|
||||
*
|
||||
* The main test is loaded using:
|
||||
* http://mochi.test:8888
|
||||
* where the imported script gets redirected to:
|
||||
* http://test1.example.com
|
||||
*/
|
||||
|
||||
var tests = [
|
||||
{
|
||||
policy: "default-src 'self'; script-src 'self' 'unsafe-eval' http://test1.example.com;",
|
||||
expected: "allowed"
|
||||
},
|
||||
{
|
||||
policy: "default-src 'self'; script-src 'self' 'unsafe-eval';",
|
||||
expected: "blocked",
|
||||
},
|
||||
];
|
||||
|
||||
var counter = 0;
|
||||
var curTest;
|
||||
|
||||
function checkResult(aResult) {
|
||||
is(aResult, curTest.expected, "Should be (" + curTest.expected + ") in Test " + counter + "!");
|
||||
loadNextTest();
|
||||
}
|
||||
|
||||
function loadNextTest() {
|
||||
if (counter == tests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
curTest = tests[counter++];
|
||||
var src = "file_csp_testserver.sjs";
|
||||
// append the file that should be served
|
||||
src += "?file=" + escape("tests/dom/base/test/csp/file_worker_redirect.html");
|
||||
// append the CSP that should be used to serve the file
|
||||
src += "&csp=" + escape(curTest.policy);
|
||||
document.getElementById("testframe").src = src;
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
loadNextTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -862,7 +862,7 @@ DOMInterfaces = {
|
||||
},
|
||||
|
||||
'PeerConnectionImpl': {
|
||||
'nativeType': 'sipcc::PeerConnectionImpl',
|
||||
'nativeType': 'mozilla::PeerConnectionImpl',
|
||||
'headerFile': 'PeerConnectionImpl.h',
|
||||
'wrapperCache': False
|
||||
},
|
||||
|
@ -64,6 +64,7 @@ LOCAL_INCLUDES += [
|
||||
'/layout/style',
|
||||
'/layout/xul/tree',
|
||||
'/media/mtransport',
|
||||
'/media/webrtc/',
|
||||
'/media/webrtc/signaling/src/common/time_profiling',
|
||||
'/media/webrtc/signaling/src/peerconnection',
|
||||
]
|
||||
|
@ -19,6 +19,36 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
|
||||
"resource://gre/modules/SystemAppProxy.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "appsService", function() {
|
||||
return Cc["@mozilla.org/AppsService;1"].getService(Ci.nsIAppsService);
|
||||
});
|
||||
|
||||
let Utils = {
|
||||
getMMFromMessage: function u_getMMFromMessage(msg) {
|
||||
let mm;
|
||||
try {
|
||||
mm = msg.target.QueryInterface(Ci.nsIFrameLoaderOwner)
|
||||
.frameLoader.messageManager;
|
||||
} catch(e) {
|
||||
mm = msg.target;
|
||||
}
|
||||
|
||||
return mm;
|
||||
},
|
||||
checkPermissionForMM: function u_checkPermissionForMM(mm, permName) {
|
||||
let testing = false;
|
||||
try {
|
||||
testing = Services.prefs.getBoolPref("dom.mozInputMethod.testing");
|
||||
} catch (e) { }
|
||||
|
||||
if (testing) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return mm.assertPermission(permName);
|
||||
}
|
||||
};
|
||||
|
||||
this.Keyboard = {
|
||||
_formMM: null, // The current web page message manager.
|
||||
_keyboardMM: null, // The keyboard app message manager.
|
||||
@ -72,6 +102,8 @@ this.Keyboard = {
|
||||
for (let name of this._systemMessageName) {
|
||||
ppmm.addMessageListener('System:' + name, this);
|
||||
}
|
||||
|
||||
this.inputRegistryGlue = new InputRegistryGlue();
|
||||
},
|
||||
|
||||
observe: function keyboardObserve(subject, topic, data) {
|
||||
@ -122,12 +154,7 @@ this.Keyboard = {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mm = msg.target.QueryInterface(Ci.nsIFrameLoaderOwner)
|
||||
.frameLoader.messageManager;
|
||||
} catch(e) {
|
||||
mm = msg.target;
|
||||
}
|
||||
mm = Utils.getMMFromMessage(msg);
|
||||
|
||||
// That should never happen.
|
||||
if (!mm) {
|
||||
@ -135,16 +162,10 @@ this.Keyboard = {
|
||||
return;
|
||||
}
|
||||
|
||||
let testing = false;
|
||||
try {
|
||||
testing = Services.prefs.getBoolPref("dom.mozInputMethod.testing");
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
let perm = (msg.name.indexOf("Keyboard:") === 0) ? "input"
|
||||
: "input-manage";
|
||||
if (!isKeyboardRegistration && !testing &&
|
||||
!mm.assertPermission(perm)) {
|
||||
|
||||
if (!isKeyboardRegistration && !Utils.checkPermissionForMM(mm, perm)) {
|
||||
dump("Keyboard message " + msg.name +
|
||||
" from a content process with no '" + perm + "' privileges.");
|
||||
return;
|
||||
@ -364,4 +385,93 @@ this.Keyboard = {
|
||||
}
|
||||
};
|
||||
|
||||
function InputRegistryGlue() {
|
||||
this._messageId = 0;
|
||||
this._msgMap = new Map();
|
||||
|
||||
ppmm.addMessageListener('InputRegistry:Add', this);
|
||||
ppmm.addMessageListener('InputRegistry:Remove', this);
|
||||
};
|
||||
|
||||
InputRegistryGlue.prototype.receiveMessage = function(msg) {
|
||||
let mm = Utils.getMMFromMessage(msg);
|
||||
|
||||
if (!Utils.checkPermissionForMM(mm, 'input')) {
|
||||
dump("InputRegistryGlue message " + msg.name +
|
||||
" from a content process with no 'input' privileges.");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (msg.name) {
|
||||
case 'InputRegistry:Add':
|
||||
this.addInput(msg, mm);
|
||||
|
||||
break;
|
||||
|
||||
case 'InputRegistry:Remove':
|
||||
this.removeInput(msg, mm);
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
InputRegistryGlue.prototype.addInput = function(msg, mm) {
|
||||
let msgId = this._messageId++;
|
||||
this._msgMap.set(msgId, {
|
||||
mm: mm,
|
||||
requestId: msg.data.requestId
|
||||
});
|
||||
|
||||
let manifestURL = appsService.getManifestURLByLocalId(msg.data.appId);
|
||||
|
||||
SystemAppProxy.dispatchEvent({
|
||||
type: 'inputregistry-add',
|
||||
id: msgId,
|
||||
manifestURL: manifestURL,
|
||||
inputId: msg.data.inputId,
|
||||
inputManifest: msg.data.inputManifest
|
||||
});
|
||||
};
|
||||
|
||||
InputRegistryGlue.prototype.removeInput = function(msg, mm) {
|
||||
let msgId = this._messageId++;
|
||||
this._msgMap.set(msgId, {
|
||||
mm: mm,
|
||||
requestId: msg.data.requestId
|
||||
});
|
||||
|
||||
let manifestURL = appsService.getManifestURLByLocalId(msg.data.appId);
|
||||
|
||||
SystemAppProxy.dispatchEvent({
|
||||
type: 'inputregistry-remove',
|
||||
id: msgId,
|
||||
manifestURL: manifestURL,
|
||||
inputId: msg.data.inputId
|
||||
});
|
||||
};
|
||||
|
||||
InputRegistryGlue.prototype.returnMessage = function(detail) {
|
||||
if (!this._msgMap.has(detail.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let { mm, requestId } = this._msgMap.get(detail.id);
|
||||
this._msgMap.delete(detail.id);
|
||||
|
||||
if (Cu.isDeadWrapper(mm)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!('error' in detail)) {
|
||||
mm.sendAsyncMessage('InputRegistry:Result:OK', {
|
||||
requestId: requestId
|
||||
});
|
||||
} else {
|
||||
mm.sendAsyncMessage('InputRegistry:Result:Error', {
|
||||
error: detail.error,
|
||||
requestId: requestId
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.Keyboard.init();
|
||||
|
@ -149,6 +149,8 @@ MozInputMethodManager.prototype = {
|
||||
function MozInputMethod() { }
|
||||
|
||||
MozInputMethod.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
_inputcontext: null,
|
||||
_wrappedInputContext: null,
|
||||
_layouts: {},
|
||||
@ -196,6 +198,8 @@ MozInputMethod.prototype = {
|
||||
cpmm.addWeakMessageListener('Keyboard:SelectionChange', this);
|
||||
cpmm.addWeakMessageListener('Keyboard:GetContext:Result:OK', this);
|
||||
cpmm.addWeakMessageListener('Keyboard:LayoutsChange', this);
|
||||
cpmm.addWeakMessageListener('InputRegistry:Result:OK', this);
|
||||
cpmm.addWeakMessageListener('InputRegistry:Result:Error', this);
|
||||
},
|
||||
|
||||
uninit: function mozInputMethodUninit() {
|
||||
@ -210,21 +214,26 @@ MozInputMethod.prototype = {
|
||||
cpmm.removeWeakMessageListener('Keyboard:SelectionChange', this);
|
||||
cpmm.removeWeakMessageListener('Keyboard:GetContext:Result:OK', this);
|
||||
cpmm.removeWeakMessageListener('Keyboard:LayoutsChange', this);
|
||||
cpmm.removeWeakMessageListener('InputRegistry:Result:OK', this);
|
||||
cpmm.removeWeakMessageListener('InputRegistry:Result:Error', this);
|
||||
this.setActive(false);
|
||||
},
|
||||
|
||||
receiveMessage: function mozInputMethodReceiveMsg(msg) {
|
||||
if (!WindowMap.isActive(this._window)) {
|
||||
if (!msg.name.startsWith('InputRegistry') &&
|
||||
!WindowMap.isActive(this._window)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let json = msg.json;
|
||||
let data = msg.data;
|
||||
let resolver = ('requestId' in data) ?
|
||||
this.takePromiseResolver(data.requestId) : null;
|
||||
|
||||
switch(msg.name) {
|
||||
case 'Keyboard:FocusChange':
|
||||
if (json.type !== 'blur') {
|
||||
if (data.type !== 'blur') {
|
||||
// XXX Bug 904339 could receive 'text' event twice
|
||||
this.setInputContext(json);
|
||||
this.setInputContext(data);
|
||||
}
|
||||
else {
|
||||
this.setInputContext(null);
|
||||
@ -232,14 +241,24 @@ MozInputMethod.prototype = {
|
||||
break;
|
||||
case 'Keyboard:SelectionChange':
|
||||
if (this.inputcontext) {
|
||||
this._inputcontext.updateSelectionContext(json, false);
|
||||
this._inputcontext.updateSelectionContext(data, false);
|
||||
}
|
||||
break;
|
||||
case 'Keyboard:GetContext:Result:OK':
|
||||
this.setInputContext(json);
|
||||
this.setInputContext(data);
|
||||
break;
|
||||
case 'Keyboard:LayoutsChange':
|
||||
this._layouts = json;
|
||||
this._layouts = data;
|
||||
break;
|
||||
|
||||
case 'InputRegistry:Result:OK':
|
||||
resolver.resolve();
|
||||
|
||||
break;
|
||||
|
||||
case 'InputRegistry:Result:Error':
|
||||
resolver.reject(data.error);
|
||||
|
||||
break;
|
||||
}
|
||||
},
|
||||
@ -330,6 +349,31 @@ MozInputMethod.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
addInput: function(inputId, inputManifest) {
|
||||
return this._sendPromise(function(resolverId) {
|
||||
let appId = this._window.document.nodePrincipal.appId;
|
||||
|
||||
cpmm.sendAsyncMessage('InputRegistry:Add', {
|
||||
requestId: resolverId,
|
||||
inputId: inputId,
|
||||
inputManifest: inputManifest,
|
||||
appId: appId
|
||||
});
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
removeInput: function(inputId) {
|
||||
return this._sendPromise(function(resolverId) {
|
||||
let appId = this._window.document.nodePrincipal.appId;
|
||||
|
||||
cpmm.sendAsyncMessage('InputRegistry:Remove', {
|
||||
requestId: resolverId,
|
||||
inputId: inputId,
|
||||
appId: appId
|
||||
});
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
setValue: function(value) {
|
||||
this._ensureIsSystem();
|
||||
cpmm.sendAsyncMessage('System:SetValue', {
|
||||
@ -361,6 +405,14 @@ MozInputMethod.prototype = {
|
||||
throw new this._window.DOMError("Security",
|
||||
"Should have 'input-manage' permssion.");
|
||||
}
|
||||
},
|
||||
|
||||
_sendPromise: function(callback) {
|
||||
let self = this;
|
||||
return this.createPromise(function(resolve, reject) {
|
||||
let resolverId = self.getPromiseResolverId({ resolve: resolve, reject: reject });
|
||||
callback(resolverId);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -31,7 +31,6 @@ XPIDL_SOURCES += [
|
||||
'nsIFrameRequestCallback.idl',
|
||||
'nsIIdleObserver.idl',
|
||||
'nsIQueryContentEventResult.idl',
|
||||
'nsIRemoteBrowser.idl',
|
||||
'nsIServiceWorkerManager.idl',
|
||||
'nsIStructuredCloneContainer.idl',
|
||||
'nsITabChild.idl',
|
||||
|
@ -1,26 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(C8379366-F79F-4D25-89A6-22BEC0A93D16)]
|
||||
interface nsIRemoteBrowser : nsISupports
|
||||
{
|
||||
/*
|
||||
* Called by the child to inform the parent that a command update has occurred
|
||||
* and the supplied set of commands are now enabled and disabled.
|
||||
*
|
||||
* @param action command updater action
|
||||
* @param enabledLength length of enabledCommands array
|
||||
* @param enabledCommands commands to enable
|
||||
* @param disabledLength length of disabledCommands array
|
||||
* @param disabledCommand commands to disable
|
||||
*/
|
||||
void enableDisableCommands(in AString action,
|
||||
in unsigned long enabledLength,
|
||||
[array, size_is(enabledLength)] in string enabledCommands,
|
||||
in unsigned long disabledLength,
|
||||
[array, size_is(disabledLength)] in string disabledCommands);
|
||||
};
|
||||
|
@ -7,10 +7,7 @@
|
||||
interface nsIContentFrameMessageManager;
|
||||
interface nsIWebBrowserChrome3;
|
||||
|
||||
native CommandsArray(nsTArray<nsCString>);
|
||||
[ref] native CommandsArrayRef(nsTArray<nsCString>);
|
||||
|
||||
[scriptable, uuid(7227bac4-b6fe-4090-aeb4-bc288b790925)]
|
||||
[scriptable, uuid(2eb3bc54-78bf-40f2-b301-a5b5b70f7da0)]
|
||||
interface nsITabChild : nsISupports
|
||||
{
|
||||
readonly attribute nsIContentFrameMessageManager messageManager;
|
||||
@ -18,9 +15,5 @@ interface nsITabChild : nsISupports
|
||||
attribute nsIWebBrowserChrome3 webBrowserChrome;
|
||||
|
||||
[notxpcom] void sendRequestFocus(in boolean canFocus);
|
||||
|
||||
[noscript, notxpcom] void enableDisableCommands(in AString action,
|
||||
in CommandsArrayRef enabledCommands,
|
||||
in CommandsArrayRef disabledCommands);
|
||||
};
|
||||
|
||||
|
@ -244,14 +244,6 @@ parent:
|
||||
*/
|
||||
RequestFocus(bool canRaise);
|
||||
|
||||
/**
|
||||
* Indicate, based on the current state, that some commands are enabled and
|
||||
* some are disabled.
|
||||
*/
|
||||
EnableDisableCommands(nsString action,
|
||||
nsCString[] enabledCommands,
|
||||
nsCString[] disabledCommands);
|
||||
|
||||
prio(urgent) sync GetInputContext() returns (int32_t IMEEnabled,
|
||||
int32_t IMEOpen,
|
||||
intptr_t NativeIMEContext);
|
||||
|
@ -3226,15 +3226,6 @@ TabChild::SendRequestFocus(bool aCanFocus)
|
||||
PBrowserChild::SendRequestFocus(aCanFocus);
|
||||
}
|
||||
|
||||
void
|
||||
TabChild::EnableDisableCommands(const nsAString& aAction,
|
||||
nsTArray<nsCString>& aEnabledCommands,
|
||||
nsTArray<nsCString>& aDisabledCommands)
|
||||
{
|
||||
PBrowserChild::SendEnableDisableCommands(PromiseFlatString(aAction),
|
||||
aEnabledCommands, aDisabledCommands);
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::DoSendBlockingMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
|
@ -47,7 +47,6 @@
|
||||
#include "nsIWindowCreator2.h"
|
||||
#include "nsIXULBrowserWindow.h"
|
||||
#include "nsIXULWindow.h"
|
||||
#include "nsIRemoteBrowser.h"
|
||||
#include "nsViewManager.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsIWindowWatcher.h"
|
||||
@ -1468,37 +1467,6 @@ TabParent::RecvRequestFocus(const bool& aCanRaise)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvEnableDisableCommands(const nsString& aAction,
|
||||
const nsTArray<nsCString>& aEnabledCommands,
|
||||
const nsTArray<nsCString>& aDisabledCommands)
|
||||
{
|
||||
nsCOMPtr<nsIRemoteBrowser> remoteBrowser = do_QueryInterface(mFrameElement);
|
||||
if (remoteBrowser) {
|
||||
nsAutoArrayPtr<const char*> enabledCommands, disabledCommands;
|
||||
|
||||
if (aEnabledCommands.Length()) {
|
||||
enabledCommands = new const char* [aEnabledCommands.Length()];
|
||||
for (uint32_t c = 0; c < aEnabledCommands.Length(); c++) {
|
||||
enabledCommands[c] = aEnabledCommands[c].get();
|
||||
}
|
||||
}
|
||||
|
||||
if (aDisabledCommands.Length()) {
|
||||
disabledCommands = new const char* [aDisabledCommands.Length()];
|
||||
for (uint32_t c = 0; c < aDisabledCommands.Length(); c++) {
|
||||
disabledCommands[c] = aDisabledCommands[c].get();
|
||||
}
|
||||
}
|
||||
|
||||
remoteBrowser->EnableDisableCommands(aAction,
|
||||
aEnabledCommands.Length(), enabledCommands,
|
||||
aDisabledCommands.Length(), disabledCommands);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsIntPoint
|
||||
TabParent::GetChildProcessOffset()
|
||||
{
|
||||
|
@ -191,9 +191,6 @@ public:
|
||||
const int32_t& aCause,
|
||||
const int32_t& aFocusChange) MOZ_OVERRIDE;
|
||||
virtual bool RecvRequestFocus(const bool& aCanRaise) MOZ_OVERRIDE;
|
||||
virtual bool RecvEnableDisableCommands(const nsString& aAction,
|
||||
const nsTArray<nsCString>& aEnabledCommands,
|
||||
const nsTArray<nsCString>& aDisabledCommands) MOZ_OVERRIDE;
|
||||
virtual bool RecvSetCursor(const uint32_t& aValue, const bool& aForce) MOZ_OVERRIDE;
|
||||
virtual bool RecvSetBackgroundColor(const nscolor& aValue) MOZ_OVERRIDE;
|
||||
virtual bool RecvSetStatus(const uint32_t& aType, const nsString& aStatus) MOZ_OVERRIDE;
|
||||
|
@ -20,8 +20,6 @@ class MediaData;
|
||||
template<class Target>
|
||||
class MediaDataDecodedListener : public RequestSampleCallback {
|
||||
public:
|
||||
using RequestSampleCallback::NotDecodedReason;
|
||||
|
||||
MediaDataDecodedListener(Target* aTarget,
|
||||
MediaTaskQueue* aTaskQueue)
|
||||
: mMonitor("MediaDataDecodedListener")
|
||||
@ -52,7 +50,8 @@ public:
|
||||
mTaskQueue->Dispatch(task);
|
||||
}
|
||||
|
||||
virtual void OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason) MOZ_OVERRIDE {
|
||||
virtual void OnNotDecoded(MediaData::Type aType,
|
||||
MediaDecoderReader::NotDecodedReason aReason) MOZ_OVERRIDE {
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
if (!mTarget || !mTaskQueue) {
|
||||
// We've been shutdown, abort.
|
||||
@ -133,7 +132,7 @@ private:
|
||||
class DeliverNotDecodedTask : public nsRunnable {
|
||||
public:
|
||||
DeliverNotDecodedTask(MediaData::Type aType,
|
||||
RequestSampleCallback::NotDecodedReason aReason,
|
||||
MediaDecoderReader::NotDecodedReason aReason,
|
||||
Target* aTarget)
|
||||
: mType(aType)
|
||||
, mReason(aReason)
|
||||
@ -153,7 +152,7 @@ private:
|
||||
}
|
||||
private:
|
||||
MediaData::Type mType;
|
||||
RequestSampleCallback::NotDecodedReason mReason;
|
||||
MediaDecoderReader::NotDecodedReason mReason;
|
||||
RefPtr<Target> mTarget;
|
||||
};
|
||||
|
||||
|
@ -461,7 +461,6 @@ MediaDecoder::MediaDecoder() :
|
||||
gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
|
||||
}
|
||||
#endif
|
||||
|
||||
mAudioChannel = AudioChannelService::GetDefaultAudioChannel();
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,16 @@ extern PRLogModuleInfo* gMediaDecoderLog;
|
||||
#define DECODER_LOG(x, ...)
|
||||
#endif
|
||||
|
||||
PRLogModuleInfo* gMediaPromiseLog;
|
||||
|
||||
void
|
||||
EnsureMediaPromiseLog()
|
||||
{
|
||||
if (!gMediaPromiseLog) {
|
||||
gMediaPromiseLog = PR_NewLogModule("MediaPromise");
|
||||
}
|
||||
}
|
||||
|
||||
class VideoQueueMemoryFunctor : public nsDequeFunctor {
|
||||
public:
|
||||
VideoQueueMemoryFunctor() : mSize(0) {}
|
||||
@ -69,6 +79,7 @@ MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
|
||||
, mShutdown(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MediaDecoderReader);
|
||||
EnsureMediaPromiseLog();
|
||||
}
|
||||
|
||||
MediaDecoderReader::~MediaDecoderReader()
|
||||
@ -204,7 +215,7 @@ MediaDecoderReader::RequestVideoData(bool aSkipToNextKeyframe,
|
||||
}
|
||||
GetCallback()->OnVideoDecoded(v);
|
||||
} else if (VideoQueue().IsFinished()) {
|
||||
GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, RequestSampleCallback::END_OF_STREAM);
|
||||
GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, END_OF_STREAM);
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,7 +248,7 @@ MediaDecoderReader::RequestAudioData()
|
||||
GetCallback()->OnAudioDecoded(a);
|
||||
return;
|
||||
} else if (AudioQueue().IsFinished()) {
|
||||
GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, RequestSampleCallback::END_OF_STREAM);
|
||||
GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, END_OF_STREAM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -307,12 +318,13 @@ AudioDecodeRendezvous::OnAudioDecoded(AudioData* aSample)
|
||||
}
|
||||
|
||||
void
|
||||
AudioDecodeRendezvous::OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason)
|
||||
AudioDecodeRendezvous::OnNotDecoded(MediaData::Type aType,
|
||||
MediaDecoderReader::NotDecodedReason aReason)
|
||||
{
|
||||
MOZ_ASSERT(aType == MediaData::AUDIO_DATA);
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mSample = nullptr;
|
||||
mStatus = aReason == DECODE_ERROR ? NS_ERROR_FAILURE : NS_OK;
|
||||
mStatus = aReason == MediaDecoderReader::DECODE_ERROR ? NS_ERROR_FAILURE : NS_OK;
|
||||
mHaveResult = true;
|
||||
mon.NotifyAll();
|
||||
}
|
||||
|
@ -30,6 +30,13 @@ class SharedDecoderManager;
|
||||
// be accessed on the decode task queue.
|
||||
class MediaDecoderReader {
|
||||
public:
|
||||
enum NotDecodedReason {
|
||||
END_OF_STREAM,
|
||||
DECODE_ERROR,
|
||||
WAITING_FOR_DATA,
|
||||
CANCELED
|
||||
};
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReader)
|
||||
|
||||
explicit MediaDecoderReader(AbstractMediaDecoder* aDecoder);
|
||||
@ -290,13 +297,6 @@ class RequestSampleCallback {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RequestSampleCallback)
|
||||
|
||||
enum NotDecodedReason {
|
||||
END_OF_STREAM,
|
||||
DECODE_ERROR,
|
||||
WAITING_FOR_DATA,
|
||||
CANCELED
|
||||
};
|
||||
|
||||
// Receives the result of a RequestAudioData() call.
|
||||
virtual void OnAudioDecoded(AudioData* aSample) = 0;
|
||||
|
||||
@ -305,7 +305,8 @@ public:
|
||||
|
||||
// Called when a RequestAudioData() or RequestVideoData() call can't be
|
||||
// fulfiled. The reason is passed as aReason.
|
||||
virtual void OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason) = 0;
|
||||
virtual void OnNotDecoded(MediaData::Type aType,
|
||||
MediaDecoderReader::NotDecodedReason aReason) = 0;
|
||||
|
||||
virtual void OnSeekCompleted(nsresult aResult) = 0;
|
||||
|
||||
@ -322,8 +323,6 @@ protected:
|
||||
// model of the MediaDecoderReader to a synchronous model.
|
||||
class AudioDecodeRendezvous : public RequestSampleCallback {
|
||||
public:
|
||||
using RequestSampleCallback::NotDecodedReason;
|
||||
|
||||
AudioDecodeRendezvous();
|
||||
~AudioDecodeRendezvous();
|
||||
|
||||
@ -331,7 +330,8 @@ public:
|
||||
// Note: aSample is null at end of stream.
|
||||
virtual void OnAudioDecoded(AudioData* aSample) MOZ_OVERRIDE;
|
||||
virtual void OnVideoDecoded(VideoData* aSample) MOZ_OVERRIDE {}
|
||||
virtual void OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason) MOZ_OVERRIDE;
|
||||
virtual void OnNotDecoded(MediaData::Type aType,
|
||||
MediaDecoderReader::NotDecodedReason aReason) MOZ_OVERRIDE;
|
||||
virtual void OnSeekCompleted(nsresult aResult) MOZ_OVERRIDE {};
|
||||
virtual void BreakCycles() MOZ_OVERRIDE {};
|
||||
void Reset();
|
||||
|
@ -805,7 +805,7 @@ MediaDecoderStateMachine::Push(VideoData* aSample)
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
||||
RequestSampleCallback::NotDecodedReason aReason)
|
||||
MediaDecoderReader::NotDecodedReason aReason)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
SAMPLE_LOG("OnNotDecoded (aType=%u, aReason=%u)", aType, aReason);
|
||||
@ -820,7 +820,7 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
||||
}
|
||||
|
||||
// If this is a decode error, delegate to the generic error path.
|
||||
if (aReason == RequestSampleCallback::DECODE_ERROR) {
|
||||
if (aReason == MediaDecoderReader::DECODE_ERROR) {
|
||||
DecodeError();
|
||||
return;
|
||||
}
|
||||
@ -828,7 +828,7 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
||||
// If the decoder is waiting for data, we need to make sure that the requests
|
||||
// are cleared, which happened above. Additionally, if we're out of decoded
|
||||
// samples, we need to switch to buffering mode.
|
||||
if (aReason == RequestSampleCallback::WAITING_FOR_DATA) {
|
||||
if (aReason == MediaDecoderReader::WAITING_FOR_DATA) {
|
||||
bool outOfSamples = isAudio ? !AudioQueue().GetSize() : !VideoQueue().GetSize();
|
||||
if (outOfSamples) {
|
||||
StartBuffering();
|
||||
@ -837,14 +837,14 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
||||
return;
|
||||
}
|
||||
|
||||
if (aReason == RequestSampleCallback::CANCELED) {
|
||||
if (aReason == MediaDecoderReader::CANCELED) {
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
// This is an EOS. Finish off the queue, and then handle things based on our
|
||||
// state.
|
||||
MOZ_ASSERT(aReason == RequestSampleCallback::END_OF_STREAM);
|
||||
MOZ_ASSERT(aReason == MediaDecoderReader::END_OF_STREAM);
|
||||
if (!isAudio && mState == DECODER_STATE_SEEKING &&
|
||||
mCurrentSeekTarget.IsValid() && mFirstVideoFrameAfterSeek) {
|
||||
// Null sample. Hit end of stream. If we have decoded a frame,
|
||||
|
@ -373,7 +373,7 @@ public:
|
||||
|
||||
void OnAudioDecoded(AudioData* aSample);
|
||||
void OnVideoDecoded(VideoData* aSample);
|
||||
void OnNotDecoded(MediaData::Type aType, RequestSampleCallback::NotDecodedReason aReason);
|
||||
void OnNotDecoded(MediaData::Type aType, MediaDecoderReader::NotDecodedReason aReason);
|
||||
void OnSeekCompleted(nsresult aResult);
|
||||
|
||||
private:
|
||||
|
27
dom/media/MediaPromise.cpp
Normal file
27
dom/media/MediaPromise.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MediaPromise.h"
|
||||
#include "MediaTaskQueue.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace detail {
|
||||
|
||||
nsresult
|
||||
DispatchMediaPromiseRunnable(MediaTaskQueue* aTaskQueue, nsIRunnable* aRunnable)
|
||||
{
|
||||
return aTaskQueue->ForceDispatch(aRunnable);
|
||||
}
|
||||
|
||||
nsresult
|
||||
DispatchMediaPromiseRunnable(nsIEventTarget* aEventTarget, nsIRunnable* aRunnable)
|
||||
{
|
||||
return aEventTarget->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace mozilla
|
394
dom/media/MediaPromise.h
Normal file
394
dom/media/MediaPromise.h
Normal file
@ -0,0 +1,394 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#if !defined(MediaPromise_h_)
|
||||
#define MediaPromise_h_
|
||||
|
||||
#include "prlog.h"
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
|
||||
/* Polyfill __func__ on MSVC for consumers to pass to the MediaPromise API. */
|
||||
#ifdef _MSC_VER
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
|
||||
class nsIEventTarget;
|
||||
namespace mozilla {
|
||||
|
||||
extern PRLogModuleInfo* gMediaPromiseLog;
|
||||
void EnsureMediaPromiseLog();
|
||||
|
||||
#define PROMISE_LOG(x, ...) \
|
||||
MOZ_ASSERT(gMediaPromiseLog); \
|
||||
PR_LOG(gMediaPromiseLog, PR_LOG_DEBUG, (x, ##__VA_ARGS__))
|
||||
|
||||
class MediaTaskQueue;
|
||||
namespace detail {
|
||||
|
||||
nsresult DispatchMediaPromiseRunnable(MediaTaskQueue* aQueue, nsIRunnable* aRunnable);
|
||||
nsresult DispatchMediaPromiseRunnable(nsIEventTarget* aTarget, nsIRunnable* aRunnable);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/*
|
||||
* A promise manages an asynchronous request that may or may not be able to be
|
||||
* fulfilled immediately. When an API returns a promise, the consumer may attach
|
||||
* callbacks to be invoked (asynchronously, on a specified thread) when the
|
||||
* request is either completed (resolved) or cannot be completed (rejected).
|
||||
*
|
||||
* By default, resolve and reject callbacks are always invoked on the same thread
|
||||
* where Then() was invoked.
|
||||
*/
|
||||
template<typename T> class MediaPromiseHolder;
|
||||
template<typename ResolveValueT, typename RejectValueT>
|
||||
class MediaPromise
|
||||
{
|
||||
public:
|
||||
typedef ResolveValueT ResolveValueType;
|
||||
typedef RejectValueT RejectValueType;
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaPromise)
|
||||
MediaPromise(const char* aCreationSite)
|
||||
: mCreationSite(aCreationSite)
|
||||
, mMutex("MediaPromise Mutex")
|
||||
{
|
||||
MOZ_COUNT_CTOR(MediaPromise);
|
||||
PROMISE_LOG("%s creating MediaPromise (%p)", mCreationSite, this);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/*
|
||||
* A ThenValue tracks a single consumer waiting on the promise. When a consumer
|
||||
* invokes promise->Then(...), a ThenValue is created. Once the Promise is
|
||||
* resolved or rejected, a {Resolve,Reject}Runnable is dispatched, which
|
||||
* invokes the resolve/reject method and then deletes the ThenValue.
|
||||
*/
|
||||
class ThenValueBase
|
||||
{
|
||||
public:
|
||||
class ResolveRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ResolveRunnable(ThenValueBase* aThenValue, ResolveValueType aResolveValue)
|
||||
: mThenValue(aThenValue)
|
||||
, mResolveValue(aResolveValue)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ResolveRunnable);
|
||||
}
|
||||
|
||||
~ResolveRunnable()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ResolveRunnable);
|
||||
MOZ_ASSERT(!mThenValue);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Run()
|
||||
{
|
||||
PROMISE_LOG("ResolveRunnable::Run() [this=%p]", this);
|
||||
mThenValue->DoResolve(mResolveValue);
|
||||
|
||||
delete mThenValue;
|
||||
mThenValue = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
ThenValueBase* mThenValue;
|
||||
ResolveValueType mResolveValue;
|
||||
};
|
||||
|
||||
class RejectRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
RejectRunnable(ThenValueBase* aThenValue, RejectValueType aRejectValue)
|
||||
: mThenValue(aThenValue)
|
||||
, mRejectValue(aRejectValue)
|
||||
{
|
||||
MOZ_COUNT_CTOR(RejectRunnable);
|
||||
}
|
||||
|
||||
~RejectRunnable()
|
||||
{
|
||||
MOZ_COUNT_DTOR(RejectRunnable);
|
||||
MOZ_ASSERT(!mThenValue);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Run()
|
||||
{
|
||||
PROMISE_LOG("RejectRunnable::Run() [this=%p]", this);
|
||||
mThenValue->DoReject(mRejectValue);
|
||||
|
||||
delete mThenValue;
|
||||
mThenValue = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
ThenValueBase* mThenValue;
|
||||
RejectValueType mRejectValue;
|
||||
};
|
||||
|
||||
ThenValueBase(const char* aCallSite) : mCallSite(aCallSite)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ThenValueBase);
|
||||
}
|
||||
|
||||
virtual void Dispatch(MediaPromise *aPromise) = 0;
|
||||
|
||||
protected:
|
||||
// This may only be deleted by {Resolve,Reject}Runnable::Run.
|
||||
virtual ~ThenValueBase() { MOZ_COUNT_DTOR(ThenValueBase); }
|
||||
|
||||
virtual void DoResolve(ResolveValueType aResolveValue) = 0;
|
||||
virtual void DoReject(RejectValueType aRejectValue) = 0;
|
||||
|
||||
const char* mCallSite;
|
||||
};
|
||||
|
||||
template<typename TargetType, typename ThisType,
|
||||
typename ResolveMethodType, typename RejectMethodType>
|
||||
class ThenValue : public ThenValueBase
|
||||
{
|
||||
public:
|
||||
ThenValue(TargetType* aResponseTarget, ThisType* aThisVal,
|
||||
ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod,
|
||||
const char* aCallSite)
|
||||
: ThenValueBase(aCallSite)
|
||||
, mResponseTarget(aResponseTarget)
|
||||
, mThisVal(aThisVal)
|
||||
, mResolveMethod(aResolveMethod)
|
||||
, mRejectMethod(aRejectMethod) {}
|
||||
|
||||
void Dispatch(MediaPromise *aPromise) MOZ_OVERRIDE
|
||||
{
|
||||
aPromise->mMutex.AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(!aPromise->IsPending());
|
||||
bool resolved = aPromise->mResolveValue.isSome();
|
||||
nsRefPtr<nsRunnable> runnable =
|
||||
resolved ? static_cast<nsRunnable*>(new (typename ThenValueBase::ResolveRunnable)(this, aPromise->mResolveValue.ref()))
|
||||
: static_cast<nsRunnable*>(new (typename ThenValueBase::RejectRunnable)(this, aPromise->mRejectValue.ref()));
|
||||
PROMISE_LOG("%s Then() call made from %s [Runnable=%p, Promise=%p, ThenValue=%p]",
|
||||
resolved ? "Resolving" : "Rejecting", ThenValueBase::mCallSite,
|
||||
runnable.get(), aPromise, this);
|
||||
DebugOnly<nsresult> rv = detail::DispatchMediaPromiseRunnable(mResponseTarget, runnable);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void DoResolve(ResolveValueType aResolveValue)
|
||||
{
|
||||
((*mThisVal).*mResolveMethod)(aResolveValue);
|
||||
}
|
||||
|
||||
virtual void DoReject(RejectValueType aRejectValue)
|
||||
{
|
||||
((*mThisVal).*mRejectMethod)(aRejectValue);
|
||||
}
|
||||
|
||||
virtual ~ThenValue() {}
|
||||
|
||||
private:
|
||||
nsRefPtr<TargetType> mResponseTarget;
|
||||
nsRefPtr<ThisType> mThisVal;
|
||||
ResolveMethodType mResolveMethod;
|
||||
RejectMethodType mRejectMethod;
|
||||
};
|
||||
public:
|
||||
|
||||
template<typename TargetType, typename ThisType,
|
||||
typename ResolveMethodType, typename RejectMethodType>
|
||||
void Then(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal,
|
||||
ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
ThenValueBase* thenValue = new ThenValue<TargetType, ThisType, ResolveMethodType,
|
||||
RejectMethodType>(aResponseTarget, aThisVal,
|
||||
aResolveMethod, aRejectMethod,
|
||||
aCallSite);
|
||||
PROMISE_LOG("%s invoking Then() [this=%p, thenValue=%p, aThisVal=%p, isPending=%d]",
|
||||
aCallSite, this, thenValue, aThisVal, (int) IsPending());
|
||||
if (!IsPending()) {
|
||||
thenValue->Dispatch(this);
|
||||
} else {
|
||||
mThenValues.AppendElement(thenValue);
|
||||
}
|
||||
}
|
||||
|
||||
void ChainTo(already_AddRefed<MediaPromise> aChainedPromise, const char* aCallSite)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
nsRefPtr<MediaPromise> chainedPromise = aChainedPromise;
|
||||
PROMISE_LOG("%s invoking Chain() [this=%p, chainedPromise=%p, isPending=%d]",
|
||||
aCallSite, this, chainedPromise.get(), (int) IsPending());
|
||||
if (!IsPending()) {
|
||||
ForwardTo(chainedPromise);
|
||||
} else {
|
||||
mChainedPromises.AppendElement(chainedPromise);
|
||||
}
|
||||
}
|
||||
|
||||
void Resolve(ResolveValueType aResolveValue, const char* aResolveSite)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(IsPending());
|
||||
PROMISE_LOG("%s resolving MediaPromise (%p created at %s)", aResolveSite, this, mCreationSite);
|
||||
mResolveValue.emplace(aResolveValue);
|
||||
DispatchAll();
|
||||
}
|
||||
|
||||
void Reject(RejectValueType aRejectValue, const char* aRejectSite)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(IsPending());
|
||||
PROMISE_LOG("%s rejecting MediaPromise (%p created at %s)", aRejectSite, this, mCreationSite);
|
||||
mRejectValue.emplace(aRejectValue);
|
||||
DispatchAll();
|
||||
}
|
||||
|
||||
protected:
|
||||
bool IsPending() { return mResolveValue.isNothing() && mRejectValue.isNothing(); }
|
||||
void DispatchAll()
|
||||
{
|
||||
mMutex.AssertCurrentThreadOwns();
|
||||
for (size_t i = 0; i < mThenValues.Length(); ++i)
|
||||
mThenValues[i]->Dispatch(this);
|
||||
mThenValues.Clear();
|
||||
|
||||
for (size_t i = 0; i < mChainedPromises.Length(); ++i) {
|
||||
ForwardTo(mChainedPromises[i]);
|
||||
}
|
||||
mChainedPromises.Clear();
|
||||
}
|
||||
|
||||
void ForwardTo(MediaPromise* aOther)
|
||||
{
|
||||
MOZ_ASSERT(!IsPending());
|
||||
if (mResolveValue.isSome()) {
|
||||
aOther->Resolve(mResolveValue.ref(), "<chained promise>");
|
||||
} else {
|
||||
aOther->Reject(mRejectValue.ref(), "<chained promise>");
|
||||
}
|
||||
}
|
||||
|
||||
~MediaPromise()
|
||||
{
|
||||
MOZ_COUNT_DTOR(MediaPromise);
|
||||
PROMISE_LOG("MediaPromise::~MediaPromise [this=%p]", this);
|
||||
MOZ_ASSERT(!IsPending());
|
||||
MOZ_ASSERT(mThenValues.IsEmpty());
|
||||
MOZ_ASSERT(mChainedPromises.IsEmpty());
|
||||
};
|
||||
|
||||
const char* mCreationSite; // For logging
|
||||
Mutex mMutex;
|
||||
Maybe<ResolveValueType> mResolveValue;
|
||||
Maybe<RejectValueType> mRejectValue;
|
||||
nsTArray<ThenValueBase*> mThenValues;
|
||||
nsTArray<nsRefPtr<MediaPromise>> mChainedPromises;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class to encapsulate a promise for a particular role. Use this as the member
|
||||
* variable for a class whose method returns a promise.
|
||||
*/
|
||||
template<typename PromiseType>
|
||||
class MediaPromiseHolder
|
||||
{
|
||||
public:
|
||||
MediaPromiseHolder()
|
||||
: mMonitor(nullptr) {}
|
||||
|
||||
~MediaPromiseHolder() { MOZ_ASSERT(!mPromise); }
|
||||
|
||||
already_AddRefed<PromiseType> Ensure(const char* aMethodName) {
|
||||
if (mMonitor) {
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
}
|
||||
if (!mPromise) {
|
||||
mPromise = new PromiseType(aMethodName);
|
||||
}
|
||||
nsRefPtr<PromiseType> p = mPromise;
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
// Provide a Monitor that should always be held when accessing this instance.
|
||||
void SetMonitor(Monitor* aMonitor) { mMonitor = aMonitor; }
|
||||
|
||||
bool IsEmpty()
|
||||
{
|
||||
if (mMonitor) {
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
}
|
||||
return !mPromise;
|
||||
}
|
||||
|
||||
already_AddRefed<PromiseType> Steal()
|
||||
{
|
||||
if (mMonitor) {
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
}
|
||||
|
||||
nsRefPtr<PromiseType> p = mPromise;
|
||||
mPromise = nullptr;
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
void Resolve(typename PromiseType::ResolveValueType aResolveValue,
|
||||
const char* aMethodName)
|
||||
{
|
||||
if (mMonitor) {
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
}
|
||||
MOZ_ASSERT(mPromise);
|
||||
mPromise->Resolve(aResolveValue, aMethodName);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void ResolveIfExists(typename PromiseType::ResolveValueType aResolveValue,
|
||||
const char* aMethodName)
|
||||
{
|
||||
if (!IsEmpty()) {
|
||||
Resolve(aResolveValue, aMethodName);
|
||||
}
|
||||
}
|
||||
|
||||
void Reject(typename PromiseType::RejectValueType aRejectValue,
|
||||
const char* aMethodName)
|
||||
{
|
||||
if (mMonitor) {
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
}
|
||||
MOZ_ASSERT(mPromise);
|
||||
mPromise->Reject(aRejectValue, aMethodName);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void RejectIfExists(typename PromiseType::RejectValueType aRejectValue,
|
||||
const char* aMethodName)
|
||||
{
|
||||
if (!IsEmpty()) {
|
||||
Reject(aRejectValue, aMethodName);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Monitor* mMonitor;
|
||||
nsRefPtr<PromiseType> mPromise;
|
||||
};
|
||||
|
||||
#undef PROMISE_LOG
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -34,6 +34,13 @@ MediaTaskQueue::Dispatch(TemporaryRef<nsIRunnable> aRunnable)
|
||||
return DispatchLocked(aRunnable, AbortIfFlushing);
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaTaskQueue::ForceDispatch(TemporaryRef<nsIRunnable> aRunnable)
|
||||
{
|
||||
MonitorAutoLock mon(mQueueMonitor);
|
||||
return DispatchLocked(aRunnable, Forced);
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaTaskQueue::DispatchLocked(TemporaryRef<nsIRunnable> aRunnable,
|
||||
DispatchMode aMode)
|
||||
@ -45,7 +52,7 @@ MediaTaskQueue::DispatchLocked(TemporaryRef<nsIRunnable> aRunnable,
|
||||
if (mIsShutdown) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mTasks.push(aRunnable);
|
||||
mTasks.push(TaskQueueEntry(aRunnable, aMode == Forced));
|
||||
if (mIsRunning) {
|
||||
return NS_OK;
|
||||
}
|
||||
@ -140,9 +147,7 @@ MediaTaskQueue::FlushAndDispatch(TemporaryRef<nsIRunnable> aRunnable)
|
||||
{
|
||||
MonitorAutoLock mon(mQueueMonitor);
|
||||
AutoSetFlushing autoFlush(this);
|
||||
while (!mTasks.empty()) {
|
||||
mTasks.pop();
|
||||
}
|
||||
FlushLocked();
|
||||
nsresult rv = DispatchLocked(aRunnable, IgnoreFlushing);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
AwaitIdleLocked();
|
||||
@ -154,10 +159,25 @@ MediaTaskQueue::Flush()
|
||||
{
|
||||
MonitorAutoLock mon(mQueueMonitor);
|
||||
AutoSetFlushing autoFlush(this);
|
||||
while (!mTasks.empty()) {
|
||||
FlushLocked();
|
||||
AwaitIdleLocked();
|
||||
}
|
||||
|
||||
void
|
||||
MediaTaskQueue::FlushLocked()
|
||||
{
|
||||
mQueueMonitor.AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(mIsFlushing);
|
||||
|
||||
// Clear the tasks, but preserve those with mForceDispatch by re-appending
|
||||
// them to the queue.
|
||||
size_t numTasks = mTasks.size();
|
||||
for (size_t i = 0; i < numTasks; ++i) {
|
||||
if (mTasks.front().mForceDispatch) {
|
||||
mTasks.push(mTasks.front());
|
||||
}
|
||||
mTasks.pop();
|
||||
}
|
||||
AwaitIdleLocked();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -191,7 +211,7 @@ MediaTaskQueue::Runner::Run()
|
||||
mon.NotifyAll();
|
||||
return NS_OK;
|
||||
}
|
||||
event = mQueue->mTasks.front();
|
||||
event = mQueue->mTasks.front().mRunnable;
|
||||
mQueue->mTasks.pop();
|
||||
}
|
||||
MOZ_ASSERT(event);
|
||||
|
@ -34,6 +34,10 @@ public:
|
||||
|
||||
nsresult Dispatch(TemporaryRef<nsIRunnable> aRunnable);
|
||||
|
||||
// This should only be used for things that absolutely can't afford to be
|
||||
// flushed. Normal operations should use Dispatch.
|
||||
nsresult ForceDispatch(TemporaryRef<nsIRunnable> aRunnable);
|
||||
|
||||
nsresult SyncDispatch(TemporaryRef<nsIRunnable> aRunnable);
|
||||
|
||||
nsresult FlushAndDispatch(TemporaryRef<nsIRunnable> aRunnable);
|
||||
@ -68,18 +72,27 @@ private:
|
||||
// mQueueMonitor must be held.
|
||||
void AwaitIdleLocked();
|
||||
|
||||
enum DispatchMode { AbortIfFlushing, IgnoreFlushing };
|
||||
enum DispatchMode { AbortIfFlushing, IgnoreFlushing, Forced };
|
||||
|
||||
nsresult DispatchLocked(TemporaryRef<nsIRunnable> aRunnable,
|
||||
DispatchMode aMode);
|
||||
void FlushLocked();
|
||||
|
||||
RefPtr<SharedThreadPool> mPool;
|
||||
|
||||
// Monitor that protects the queue and mIsRunning;
|
||||
Monitor mQueueMonitor;
|
||||
|
||||
struct TaskQueueEntry {
|
||||
RefPtr<nsIRunnable> mRunnable;
|
||||
bool mForceDispatch;
|
||||
|
||||
TaskQueueEntry(TemporaryRef<nsIRunnable> aRunnable, bool aForceDispatch = false)
|
||||
: mRunnable(aRunnable), mForceDispatch(aForceDispatch) {}
|
||||
};
|
||||
|
||||
// Queue of tasks to run.
|
||||
std::queue<RefPtr<nsIRunnable>> mTasks;
|
||||
std::queue<TaskQueueEntry> mTasks;
|
||||
|
||||
// The thread currently running the task queue. We store a reference
|
||||
// to this so that IsCurrentThreadIn() can tell if the current thread
|
||||
|
@ -25,7 +25,7 @@ const PC_STATIC_CONTRACT = "@mozilla.org/dom/peerconnectionstatic;1";
|
||||
const PC_SENDER_CONTRACT = "@mozilla.org/dom/rtpsender;1";
|
||||
const PC_RECEIVER_CONTRACT = "@mozilla.org/dom/rtpreceiver;1";
|
||||
|
||||
const PC_CID = Components.ID("{00e0e20d-1494-4776-8e0e-0f0acbea3c79}");
|
||||
const PC_CID = Components.ID("{bdc2e533-b308-4708-ac8e-a8bfade6d851}");
|
||||
const PC_OBS_CID = Components.ID("{d1748d4c-7f6a-4dc5-add6-d55b7678537e}");
|
||||
const PC_ICE_CID = Components.ID("{02b9970c-433d-4cc2-923d-f7028ac66073}");
|
||||
const PC_SESSION_CID = Components.ID("{1775081b-b62d-4954-8ffe-a067bbf508a7}");
|
||||
@ -849,7 +849,7 @@ RTCPeerConnection.prototype = {
|
||||
|
||||
this._impl.addIceCandidate(cand.candidate, cand.sdpMid || "",
|
||||
(cand.sdpMLineIndex === null) ? 0 :
|
||||
cand.sdpMLineIndex + 1);
|
||||
cand.sdpMLineIndex);
|
||||
},
|
||||
|
||||
addStream: function(stream) {
|
||||
@ -1122,7 +1122,7 @@ PeerConnectionObserver.prototype = {
|
||||
const reasonName = [
|
||||
"",
|
||||
"InternalError",
|
||||
"InternalError",
|
||||
"InvalidCandidateError",
|
||||
"InvalidParameter",
|
||||
"InvalidStateError",
|
||||
"InvalidSessionDescriptionError",
|
||||
@ -1221,7 +1221,7 @@ PeerConnectionObserver.prototype = {
|
||||
{
|
||||
candidate: candidate,
|
||||
sdpMid: mid,
|
||||
sdpMLineIndex: level - 1
|
||||
sdpMLineIndex: level
|
||||
}
|
||||
));
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
component {00e0e20d-1494-4776-8e0e-0f0acbea3c79} PeerConnection.js
|
||||
component {bdc2e533-b308-4708-ac8e-a8bfade6d851} PeerConnection.js
|
||||
component {d1748d4c-7f6a-4dc5-add6-d55b7678537e} PeerConnection.js
|
||||
component {02b9970c-433d-4cc2-923d-f7028ac66073} PeerConnection.js
|
||||
component {1775081b-b62d-4954-8ffe-a067bbf508a7} PeerConnection.js
|
||||
@ -9,7 +9,7 @@ component {0fb47c47-a205-4583-a9fc-cbadf8c95880} PeerConnection.js
|
||||
component {4fff5d46-d827-4cd4-a970-8fd53977440e} PeerConnection.js
|
||||
component {d974b814-8fde-411c-8c45-b86791b81030} PeerConnection.js
|
||||
|
||||
contract @mozilla.org/dom/peerconnection;1 {00e0e20d-1494-4776-8e0e-0f0acbea3c79}
|
||||
contract @mozilla.org/dom/peerconnection;1 {bdc2e533-b308-4708-ac8e-a8bfade6d851}
|
||||
contract @mozilla.org/dom/peerconnectionobserver;1 {d1748d4c-7f6a-4dc5-add6-d55b7678537e}
|
||||
contract @mozilla.org/dom/rtcicecandidate;1 {02b9970c-433d-4cc2-923d-f7028ac66073}
|
||||
contract @mozilla.org/dom/rtcsessiondescription;1 {1775081b-b62d-4954-8ffe-a067bbf508a7}
|
||||
|
@ -25,3 +25,5 @@ LOCAL_INCLUDES += [
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -59,6 +59,7 @@ interface IPeerConnection : nsISupports
|
||||
|
||||
/* Constants for 'name' in error callbacks */
|
||||
const unsigned long kNoError = 0; // Test driver only
|
||||
const unsigned long kInvalidCandidate = 2;
|
||||
const unsigned long kInvalidMediastreamTrack = 3;
|
||||
const unsigned long kInvalidState = 4;
|
||||
const unsigned long kInvalidSessionDescription = 5;
|
||||
|
@ -21,9 +21,9 @@ NS_DEFINE_NAMED_CID(NS_STUN_UDP_SOCKET_FILTER_HANDLER_CID)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsStunUDPSocketFilterHandler)
|
||||
|
||||
|
||||
namespace sipcc
|
||||
namespace mozilla
|
||||
{
|
||||
// Factory defined in sipcc::, defines sipcc::PeerConnectionImplConstructor
|
||||
// Factory defined in mozilla::, defines mozilla::PeerConnectionImplConstructor
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(PeerConnectionImpl)
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(PeerConnectionImpl)
|
||||
NS_DEFINE_NAMED_CID(PEERCONNECTION_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kCIDs[] = {
|
||||
{ &kPEERCONNECTION_CID, false, nullptr, sipcc::PeerConnectionImplConstructor },
|
||||
{ &kPEERCONNECTION_CID, false, nullptr, mozilla::PeerConnectionImplConstructor },
|
||||
{ &kNS_STUN_UDP_SOCKET_FILTER_HANDLER_CID, false, nullptr, nsStunUDPSocketFilterHandlerConstructor },
|
||||
{ nullptr }
|
||||
};
|
||||
|
@ -17,12 +17,12 @@ SOURCES += [
|
||||
LOCAL_INCLUDES += [
|
||||
'/ipc/chromium/src',
|
||||
'/media/mtransport',
|
||||
'/media/webrtc/signaling/include',
|
||||
'/media/mtransport',
|
||||
'/media/webrtc/',
|
||||
'/media/webrtc/signaling/src/common/time_profiling',
|
||||
'/media/webrtc/signaling/src/media-conduit',
|
||||
'/media/webrtc/signaling/src/mediapipeline',
|
||||
'/media/webrtc/signaling/src/peerconnection',
|
||||
'/media/webrtc/signaling/src/sipcc/include',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
@ -666,8 +666,7 @@ MP4Reader::ReturnOutput(MediaData* aData, TrackType aTrack)
|
||||
void
|
||||
MP4Reader::ReturnEOS(TrackType aTrack)
|
||||
{
|
||||
GetCallback()->OnNotDecoded(aTrack == kAudio ? MediaData::AUDIO_DATA : MediaData::VIDEO_DATA,
|
||||
RequestSampleCallback::END_OF_STREAM);
|
||||
GetCallback()->OnNotDecoded(aTrack == kAudio ? MediaData::AUDIO_DATA : MediaData::VIDEO_DATA, END_OF_STREAM);
|
||||
}
|
||||
|
||||
MP4Sample*
|
||||
@ -753,8 +752,7 @@ MP4Reader::Error(TrackType aTrack)
|
||||
MonitorAutoLock mon(data.mMonitor);
|
||||
data.mError = true;
|
||||
}
|
||||
GetCallback()->OnNotDecoded(aTrack == kVideo ? MediaData::VIDEO_DATA : MediaData::AUDIO_DATA,
|
||||
RequestSampleCallback::DECODE_ERROR);
|
||||
GetCallback()->OnNotDecoded(aTrack == kVideo ? MediaData::VIDEO_DATA : MediaData::AUDIO_DATA, DECODE_ERROR);
|
||||
}
|
||||
|
||||
void
|
||||
@ -784,8 +782,7 @@ MP4Reader::Flush(TrackType aTrack)
|
||||
data.mNumSamplesOutput = 0;
|
||||
data.mInputExhausted = false;
|
||||
if (data.mOutputRequested) {
|
||||
GetCallback()->OnNotDecoded(aTrack == kVideo ? MediaData::VIDEO_DATA : MediaData::AUDIO_DATA,
|
||||
RequestSampleCallback::CANCELED);
|
||||
GetCallback()->OnNotDecoded(aTrack == kVideo ? MediaData::VIDEO_DATA : MediaData::AUDIO_DATA, CANCELED);
|
||||
}
|
||||
data.mOutputRequested = false;
|
||||
data.mDiscontinuity = true;
|
||||
@ -810,8 +807,7 @@ MP4Reader::SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed
|
||||
nsAutoPtr<MP4Sample> compressed(PopSample(kVideo));
|
||||
if (!compressed) {
|
||||
// EOS, or error. Let the state machine know.
|
||||
GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA,
|
||||
RequestSampleCallback::END_OF_STREAM);
|
||||
GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, END_OF_STREAM);
|
||||
{
|
||||
MonitorAutoLock mon(mVideo.mMonitor);
|
||||
mVideo.mDemuxEOS = true;
|
||||
|
@ -18,4 +18,7 @@ UNIFIED_SOURCES += [
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'..',
|
||||
]
|
||||
]
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -100,7 +100,7 @@ MediaSourceReader::RequestAudioData()
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::RequestAudioData", this);
|
||||
if (!mAudioReader) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::RequestAudioData called with no audio reader", this);
|
||||
GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, RequestSampleCallback::DECODE_ERROR);
|
||||
GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, DECODE_ERROR);
|
||||
return;
|
||||
}
|
||||
mAudioIsSeeking = false;
|
||||
@ -139,7 +139,7 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
|
||||
this, aSkipToNextKeyframe, aTimeThreshold);
|
||||
if (!mVideoReader) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::RequestVideoData called with no video reader", this);
|
||||
GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, RequestSampleCallback::DECODE_ERROR);
|
||||
GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, DECODE_ERROR);
|
||||
return;
|
||||
}
|
||||
if (aSkipToNextKeyframe) {
|
||||
@ -177,17 +177,16 @@ MediaSourceReader::OnVideoDecoded(VideoData* aSample)
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnNotDecoded(MediaData::Type aType, RequestSampleCallback::NotDecodedReason aReason)
|
||||
MediaSourceReader::OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason)
|
||||
{
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnNotDecoded aType=%u aReason=%u IsEnded: %d", this, aType, aReason, IsEnded());
|
||||
if (aReason == RequestSampleCallback::DECODE_ERROR ||
|
||||
aReason == RequestSampleCallback::CANCELED) {
|
||||
if (aReason == DECODE_ERROR || aReason == CANCELED) {
|
||||
GetCallback()->OnNotDecoded(aType, aReason);
|
||||
return;
|
||||
}
|
||||
// End of stream. Force switching past this stream to another reader by
|
||||
// switching to the end of the buffered range.
|
||||
MOZ_ASSERT(aReason == RequestSampleCallback::END_OF_STREAM);
|
||||
MOZ_ASSERT(aReason == END_OF_STREAM);
|
||||
nsRefPtr<MediaDecoderReader> reader = aType == MediaData::AUDIO_DATA ?
|
||||
mAudioReader : mVideoReader;
|
||||
|
||||
@ -228,13 +227,13 @@ MediaSourceReader::OnNotDecoded(MediaData::Type aType, RequestSampleCallback::No
|
||||
|
||||
// If the entire MediaSource is done, generate an EndOfStream.
|
||||
if (IsEnded()) {
|
||||
GetCallback()->OnNotDecoded(aType, RequestSampleCallback::END_OF_STREAM);
|
||||
GetCallback()->OnNotDecoded(aType, END_OF_STREAM);
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't have the data the caller wants. Tell that we're waiting for JS to
|
||||
// give us more data.
|
||||
GetCallback()->OnNotDecoded(aType, RequestSampleCallback::WAITING_FOR_DATA);
|
||||
GetCallback()->OnNotDecoded(aType, WAITING_FOR_DATA);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
|
||||
void OnVideoDecoded(VideoData* aSample);
|
||||
|
||||
void OnNotDecoded(MediaData::Type aType, RequestSampleCallback::NotDecodedReason aReason);
|
||||
void OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason);
|
||||
|
||||
void OnSeekCompleted(nsresult aResult);
|
||||
|
||||
|
@ -67,7 +67,7 @@ private:
|
||||
nsRefPtr<SourceBufferDecoder> mDecoder;
|
||||
};
|
||||
|
||||
MOZ_STACK_CLASS class DecodersToInitialize MOZ_FINAL {
|
||||
class MOZ_STACK_CLASS DecodersToInitialize MOZ_FINAL {
|
||||
public:
|
||||
explicit DecodersToInitialize(TrackBuffer* aOwner)
|
||||
: mOwner(aOwner)
|
||||
|
@ -105,6 +105,7 @@ EXPORTS += [
|
||||
'MediaDecoderStateMachine.h',
|
||||
'MediaInfo.h',
|
||||
'MediaMetadataManager.h',
|
||||
'MediaPromise.h',
|
||||
'MediaQueue.h',
|
||||
'MediaRecorder.h',
|
||||
'MediaResource.h',
|
||||
@ -181,6 +182,7 @@ UNIFIED_SOURCES += [
|
||||
'MediaDecoderStateMachineScheduler.cpp',
|
||||
'MediaDevices.cpp',
|
||||
'MediaManager.cpp',
|
||||
'MediaPromise.cpp',
|
||||
'MediaRecorder.cpp',
|
||||
'MediaResource.cpp',
|
||||
'MediaShutdownManager.cpp',
|
||||
|
@ -488,7 +488,7 @@ MediaCodecReader::DecodeAudioDataTask()
|
||||
}
|
||||
}
|
||||
if (AudioQueue().AtEndOfStream()) {
|
||||
GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, RequestSampleCallback::END_OF_STREAM);
|
||||
GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, END_OF_STREAM);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -508,7 +508,7 @@ MediaCodecReader::DecodeVideoFrameTask(int64_t aTimeThreshold)
|
||||
}
|
||||
}
|
||||
if (VideoQueue().AtEndOfStream()) {
|
||||
GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, RequestSampleCallback::END_OF_STREAM);
|
||||
GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, END_OF_STREAM);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -40,3 +40,5 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -53,7 +53,7 @@ var fingerprintRegex = /^a=fingerprint:(\S+) (\S+)/m;
|
||||
var identityRegex = /^a=identity:(\S+)/m;
|
||||
|
||||
function fingerprintSdp(fingerprints) {
|
||||
return fingerprints.map(fp => "a=fInGeRpRiNt=" + fp.algorithm +
|
||||
return fingerprints.map(fp => "a=fInGeRpRiNt:" + fp.algorithm +
|
||||
" " + fp.digest + "\n").join("");
|
||||
}
|
||||
|
||||
@ -78,20 +78,20 @@ function testMultipleFingerprints() {
|
||||
|
||||
pcDouble.createOffer(function(offer) {
|
||||
ok(offer, "Got offer");
|
||||
var m = offer.sdp.match(fingerprintRegex);
|
||||
if (!m) {
|
||||
var fp = offer.sdp.match(fingerprintRegex);
|
||||
if (!fp) {
|
||||
finished(false, "No fingerprint in offer SDP");
|
||||
return;
|
||||
}
|
||||
|
||||
var fingerprints = makeFingerprints(m[1], m[2]);
|
||||
var fingerprints = makeFingerprints(fp[1], fp[2]);
|
||||
getIdentityAssertion(fingerprints, function(assertion) {
|
||||
ok(assertion, "Should have assertion");
|
||||
|
||||
var sdp = offer.sdp.slice(0, m.index) +
|
||||
var sdp = offer.sdp.slice(0, fp.index) +
|
||||
"a=identity:" + assertion + "\n" +
|
||||
fingerprintSdp(fingerprints.slice(1)) +
|
||||
offer.sdp.slice(m.index);
|
||||
offer.sdp.slice(fp.index);
|
||||
|
||||
var desc = new mozRTCSessionDescription({ type: "offer", sdp: sdp });
|
||||
pcStrict.setRemoteDescription(desc, function() {
|
||||
|
@ -128,5 +128,12 @@ skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabl
|
||||
[test_peerConnection_toJSON.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
|
||||
# multistream is not ready quite yet (bug 1056650)
|
||||
# [test_peerConnection_twoAudioStreams.html]
|
||||
# [test_peerConnection_twoAudioVideoStreams.html]
|
||||
# [test_peerConnection_twoAudioVideoStreamsCombined.html]
|
||||
# [test_peerConnection_twoVideoStreams.html]
|
||||
# [test_peerConnection_addSecondAudioStream.html]
|
||||
|
||||
# Bug 950317: Hack for making a cleanup hook after finishing all WebRTC cases
|
||||
[test_zmedia_cleanup.html]
|
||||
|
@ -1755,11 +1755,13 @@ PeerConnectionWrapper.prototype = {
|
||||
*
|
||||
* @param {function} onSuccess
|
||||
* Callback to execute if all media has been requested successfully
|
||||
* @param {array} constraintsList
|
||||
* Array of constraints for GUM calls
|
||||
*/
|
||||
getAllUserMedia : function PCW_GetAllUserMedia(onSuccess) {
|
||||
getAllUserMedia : function PCW_GetAllUserMedia(constraintsList, onSuccess) {
|
||||
var self = this;
|
||||
|
||||
function _getAllUserMedia(constraintsList, index) {
|
||||
function _getAllUserMedia(index) {
|
||||
if (index < constraintsList.length) {
|
||||
var constraints = constraintsList[index];
|
||||
|
||||
@ -1776,20 +1778,20 @@ PeerConnectionWrapper.prototype = {
|
||||
|
||||
self.attachMedia(stream, type, 'local');
|
||||
|
||||
_getAllUserMedia(constraintsList, index + 1);
|
||||
_getAllUserMedia(index + 1);
|
||||
}, generateErrorCallback());
|
||||
} else {
|
||||
onSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.constraints.length === 0) {
|
||||
if (constraintsList.length === 0) {
|
||||
info("Skipping GUM: no UserMedia requested");
|
||||
onSuccess();
|
||||
}
|
||||
else {
|
||||
info("Get " + this.constraints.length + " local streams");
|
||||
_getAllUserMedia(this.constraints, 0);
|
||||
info("Get " + constraintsList.length + " local streams");
|
||||
_getAllUserMedia(0);
|
||||
}
|
||||
},
|
||||
|
||||
@ -2174,13 +2176,13 @@ PeerConnectionWrapper.prototype = {
|
||||
if ((!constraints) || (constraints.length === 0)) {
|
||||
return 0;
|
||||
}
|
||||
var audioTracks = 0;
|
||||
var numAudioTracks = 0;
|
||||
for (var i = 0; i < constraints.length; i++) {
|
||||
if (constraints[i].audio) {
|
||||
audioTracks++;
|
||||
numAudioTracks++;
|
||||
}
|
||||
}
|
||||
return audioTracks;
|
||||
return numAudioTracks;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2223,13 +2225,13 @@ PeerConnectionWrapper.prototype = {
|
||||
if ((!constraints) || (constraints.length === 0)) {
|
||||
return 0;
|
||||
}
|
||||
var videoTracks = 0;
|
||||
var numVideoTracks = 0;
|
||||
for (var i = 0; i < constraints.length; i++) {
|
||||
if (constraints[i].video) {
|
||||
videoTracks++;
|
||||
numVideoTracks++;
|
||||
}
|
||||
}
|
||||
return videoTracks;
|
||||
return numVideoTracks;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2272,11 +2274,11 @@ PeerConnectionWrapper.prototype = {
|
||||
if (!streams || (streams.length === 0)) {
|
||||
return 0;
|
||||
}
|
||||
var audioTracks = 0;
|
||||
var numAudioTracks = 0;
|
||||
streams.forEach(function(st) {
|
||||
audioTracks += st.getAudioTracks().length;
|
||||
numAudioTracks += st.getAudioTracks().length;
|
||||
});
|
||||
return audioTracks;
|
||||
return numAudioTracks;
|
||||
},
|
||||
|
||||
/*
|
||||
@ -2290,11 +2292,11 @@ PeerConnectionWrapper.prototype = {
|
||||
if (!streams || (streams.length === 0)) {
|
||||
return 0;
|
||||
}
|
||||
var videoTracks = 0;
|
||||
var numVideoTracks = 0;
|
||||
streams.forEach(function(st) {
|
||||
videoTracks += st.getVideoTracks().length;
|
||||
numVideoTracks += st.getVideoTracks().length;
|
||||
});
|
||||
return videoTracks;
|
||||
return numVideoTracks;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2367,10 +2369,9 @@ PeerConnectionWrapper.prototype = {
|
||||
},
|
||||
|
||||
verifySdp : function PCW_verifySdp(desc, expectedType, offerConstraintsList,
|
||||
answerConstraintsList, offerOptions, trickleIceCallback) {
|
||||
offerOptions, trickleIceCallback) {
|
||||
info("Examining this SessionDescription: " + JSON.stringify(desc));
|
||||
info("offerConstraintsList: " + JSON.stringify(offerConstraintsList));
|
||||
info("answerConstraintsList: " + JSON.stringify(answerConstraintsList));
|
||||
info("offerOptions: " + JSON.stringify(offerOptions));
|
||||
ok(desc, "SessionDescription is not null");
|
||||
is(desc.type, expectedType, "SessionDescription type is " + expectedType);
|
||||
@ -2390,8 +2391,7 @@ PeerConnectionWrapper.prototype = {
|
||||
//TODO: how can we check for absence/presence of m=application?
|
||||
|
||||
var audioTracks =
|
||||
Math.max(this.countAudioTracksInMediaConstraint(offerConstraintsList),
|
||||
this.countAudioTracksInMediaConstraint(answerConstraintsList)) ||
|
||||
this.countAudioTracksInMediaConstraint(offerConstraintsList) ||
|
||||
this.audioInOfferOptions(offerOptions);
|
||||
|
||||
info("expected audio tracks: " + audioTracks);
|
||||
@ -2407,8 +2407,7 @@ PeerConnectionWrapper.prototype = {
|
||||
}
|
||||
|
||||
var videoTracks =
|
||||
Math.max(this.countVideoTracksInMediaConstraint(offerConstraintsList),
|
||||
this.countVideoTracksInMediaConstraint(answerConstraintsList)) ||
|
||||
this.countVideoTracksInMediaConstraint(offerConstraintsList) ||
|
||||
this.videoInOfferOptions(offerOptions);
|
||||
|
||||
info("expected video tracks: " + videoTracks);
|
||||
@ -2636,6 +2635,46 @@ PeerConnectionWrapper.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Compares amount of established ICE connection according to ICE candidate
|
||||
* pairs in the stats reporting with the expected amount of connection based
|
||||
* on the constraints.
|
||||
*
|
||||
* @param {object} stats
|
||||
* The stats to check for ICE candidate pairs
|
||||
* @param {object} counters
|
||||
* The counters for media and data tracks based on constraints
|
||||
* @param {object} answer
|
||||
* The SDP answer to check for SDP bundle support
|
||||
*/
|
||||
checkStatsIceConnections : function PCW_checkStatsIceConnections(stats,
|
||||
offerConstraintsList, offerOptions, numDataTracks, answer) {
|
||||
var numIceConnections = 0;
|
||||
Object.keys(stats).forEach(function(key) {
|
||||
if ((stats[key].type === "candidatepair") && stats[key].selected) {
|
||||
numIceConnections += 1;
|
||||
}
|
||||
});
|
||||
info("ICE connections according to stats: " + numIceConnections);
|
||||
if (answer.sdp.contains('a=group:BUNDLE')) {
|
||||
is(numIceConnections, 1, "stats reports exactly 1 ICE connection");
|
||||
} else {
|
||||
// This code assumes that no media sections have been rejected due to
|
||||
// codec mismatch or other unrecoverable negotiation failures.
|
||||
var numAudioTracks =
|
||||
this.countAudioTracksInMediaConstraint(offerConstraintsList) ||
|
||||
this.audioInOfferOptions(offerOptions);
|
||||
|
||||
var numVideoTracks =
|
||||
this.countVideoTracksInMediaConstraint(offerConstraintsList) ||
|
||||
this.videoInOfferOptions(offerOptions);
|
||||
|
||||
var numAudioVideoDataTracks = numAudioTracks + numVideoTracks + numDataTracks;
|
||||
info("expected audio + video + data tracks: " + numAudioVideoDataTracks);
|
||||
is(numAudioVideoDataTracks, numIceConnections, "stats ICE connections matches expected A/V tracks");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Property-matching function for finding a certain stat in passed-in stats
|
||||
*
|
||||
|
@ -111,7 +111,7 @@ var commandsPeerConnection = [
|
||||
[
|
||||
'PC_LOCAL_GUM',
|
||||
function (test) {
|
||||
test.pcLocal.getAllUserMedia(function () {
|
||||
test.pcLocal.getAllUserMedia(test.pcLocal.constraints, function () {
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
@ -119,7 +119,7 @@ var commandsPeerConnection = [
|
||||
[
|
||||
'PC_REMOTE_GUM',
|
||||
function (test) {
|
||||
test.pcRemote.getAllUserMedia(function () {
|
||||
test.pcRemote.getAllUserMedia(test.pcRemote.constraints, function () {
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
@ -232,7 +232,7 @@ var commandsPeerConnection = [
|
||||
'PC_LOCAL_SANE_LOCAL_SDP',
|
||||
function (test) {
|
||||
test.pcLocal.verifySdp(test._local_offer, "offer",
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._offer_options,
|
||||
function(trickle) {
|
||||
test.pcLocal.localRequiresTrickleIce = trickle;
|
||||
});
|
||||
@ -243,7 +243,7 @@ var commandsPeerConnection = [
|
||||
'PC_REMOTE_SANE_REMOTE_SDP',
|
||||
function (test) {
|
||||
test.pcRemote.verifySdp(test._local_offer, "offer",
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._offer_options,
|
||||
function (trickle) {
|
||||
test.pcRemote.remoteRequiresTrickleIce = trickle;
|
||||
});
|
||||
@ -356,7 +356,7 @@ var commandsPeerConnection = [
|
||||
'PC_REMOTE_SANE_LOCAL_SDP',
|
||||
function (test) {
|
||||
test.pcRemote.verifySdp(test._remote_answer, "answer",
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._offer_options,
|
||||
function (trickle) {
|
||||
test.pcRemote.localRequiresTrickleIce = trickle;
|
||||
});
|
||||
@ -367,7 +367,7 @@ var commandsPeerConnection = [
|
||||
'PC_LOCAL_SANE_REMOTE_SDP',
|
||||
function (test) {
|
||||
test.pcLocal.verifySdp(test._remote_answer, "answer",
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._offer_options,
|
||||
function (trickle) {
|
||||
test.pcLocal.remoteRequiresTrickleIce = trickle;
|
||||
});
|
||||
@ -522,6 +522,32 @@ var commandsPeerConnection = [
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_CHECK_ICE_CONNECTIONS',
|
||||
function (test) {
|
||||
test.pcLocal.getStats(null, function(stats) {
|
||||
test.pcLocal.checkStatsIceConnections(stats,
|
||||
test._offer_constraints,
|
||||
test._offer_options,
|
||||
0,
|
||||
test.originalAnswer);
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_CHECK_ICE_CONNECTIONS',
|
||||
function (test) {
|
||||
test.pcRemote.getStats(null, function(stats) {
|
||||
test.pcRemote.checkStatsIceConnections(stats,
|
||||
test._offer_constraints,
|
||||
test._offer_options,
|
||||
0,
|
||||
test.originalAnswer);
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_CHECK_GETSTATS_AUDIOTRACK_OUTBOUND',
|
||||
function (test) {
|
||||
@ -728,7 +754,7 @@ var commandsDataChannel = [
|
||||
[
|
||||
'PC_LOCAL_GUM',
|
||||
function (test) {
|
||||
test.pcLocal.getAllUserMedia(function () {
|
||||
test.pcLocal.getAllUserMedia(test.pcLocal.constraints, function () {
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
@ -752,7 +778,7 @@ var commandsDataChannel = [
|
||||
[
|
||||
'PC_REMOTE_GUM',
|
||||
function (test) {
|
||||
test.pcRemote.getAllUserMedia(function () {
|
||||
test.pcRemote.getAllUserMedia(test.pcRemote.constraints, function () {
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
@ -867,7 +893,7 @@ var commandsDataChannel = [
|
||||
'PC_LOCAL_SANE_LOCAL_SDP',
|
||||
function (test) {
|
||||
test.pcLocal.verifySdp(test._local_offer, "offer",
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._offer_options,
|
||||
function(trickle) {
|
||||
test.pcLocal.localRequiresTrickleIce = trickle;
|
||||
});
|
||||
@ -878,7 +904,7 @@ var commandsDataChannel = [
|
||||
'PC_REMOTE_SANE_REMOTE_SDP',
|
||||
function (test) {
|
||||
test.pcRemote.verifySdp(test._local_offer, "offer",
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._offer_options,
|
||||
function (trickle) {
|
||||
test.pcRemote.remoteRequiresTrickleIce = trickle;
|
||||
});
|
||||
@ -971,7 +997,7 @@ var commandsDataChannel = [
|
||||
'PC_REMOTE_SANE_LOCAL_SDP',
|
||||
function (test) {
|
||||
test.pcRemote.verifySdp(test._remote_answer, "answer",
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._offer_options,
|
||||
function (trickle) {
|
||||
test.pcRemote.localRequiresTrickleIce = trickle;
|
||||
});
|
||||
@ -982,7 +1008,7 @@ var commandsDataChannel = [
|
||||
'PC_LOCAL_SANE_REMOTE_SDP',
|
||||
function (test) {
|
||||
test.pcLocal.verifySdp(test._remote_answer, "answer",
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._offer_options,
|
||||
function (trickle) {
|
||||
test.pcLocal.remoteRequiresTrickleIce = trickle;
|
||||
});
|
||||
@ -1129,6 +1155,32 @@ var commandsDataChannel = [
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_CHECK_ICE_CONNECTIONS',
|
||||
function (test) {
|
||||
test.pcLocal.getStats(null, function(stats) {
|
||||
test.pcLocal.checkStatsIceConnections(stats,
|
||||
test._offer_constraints,
|
||||
test._offer_options,
|
||||
1,
|
||||
test.originalAnswer);
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_CHECK_ICE_CONNECTIONS',
|
||||
function (test) {
|
||||
test.pcRemote.getStats(null, function(stats) {
|
||||
test.pcRemote.checkStatsIceConnections(stats,
|
||||
test._offer_constraints,
|
||||
test._offer_options,
|
||||
1,
|
||||
test.originalAnswer);
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'SEND_MESSAGE',
|
||||
function (test) {
|
||||
|
@ -0,0 +1,102 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="templates.js"></script>
|
||||
<script type="application/javascript" src="turnConfig.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1091242",
|
||||
title: "Renegotiation: add second audio stream"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
test.chain.append([
|
||||
[
|
||||
'PC_LOCAL_SETUP_NEGOTIATION_CALLBACK',
|
||||
function (test) {
|
||||
test.pcLocal.onNegotiationneededFired = false;
|
||||
test.pcLocal._pc.onnegotiationneeded = function (anEvent) {
|
||||
info("pcLocal.onnegotiationneeded fired");
|
||||
test.pcLocal.onNegotiationneededFired = true;
|
||||
};
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_ADD_SECOND_STREAM',
|
||||
function (test) {
|
||||
test.pcLocal.getAllUserMedia([{audio: true}], function () {
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_CREATE_NEW_OFFER',
|
||||
function (test) {
|
||||
ok(test.pcLocal.onNegotiationneededFired, "onnegotiationneeded");
|
||||
test.createOffer(test.pcLocal, function (offer) {
|
||||
test._new_offer = offer;
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_SET_NEW_LOCAL_DESCRIPTION',
|
||||
function (test) {
|
||||
test.setLocalDescription(test.pcLocal, test._new_offer, HAVE_LOCAL_OFFER, function () {
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_SET_NEW_REMOTE_DESCRIPTION',
|
||||
function (test) {
|
||||
test.setRemoteDescription(test.pcRemote, test._new_offer, HAVE_REMOTE_OFFER, function () {
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_CREATE_NEW_ANSWER',
|
||||
function (test) {
|
||||
test.createAnswer(test.pcRemote, function (answer) {
|
||||
test._new_answer = answer;
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_SET_NEW_LOCAL_DESCRIPTION',
|
||||
function (test) {
|
||||
test.setLocalDescription(test.pcRemote, test._new_answer, STABLE, function () {
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_SET_NEW_REMOTE_DESCRIPTION',
|
||||
function (test) {
|
||||
test.setRemoteDescription(test.pcLocal, test._new_answer, STABLE, function () {
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
]
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
]);
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -18,7 +18,7 @@
|
||||
|
||||
runNetworkTest(function() {
|
||||
var test = new PeerConnectionTest();
|
||||
|
||||
test.setMediaConstraints([], [{audio: true}]);
|
||||
// TODO: Stop using old constraint-like RTCOptions soon (Bug 1064223).
|
||||
// Watch out for case-difference when fixing: { offerToReceiveAudio: true }
|
||||
test.setOfferOptions({ mandatory: { OfferToReceiveAudio: true } });
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
runNetworkTest(function() {
|
||||
var test = new PeerConnectionTest();
|
||||
test.setMediaConstraints([], [{video: true}]);
|
||||
// TODO: Stop using old constraint-like RTCOptions soon (Bug 1064223).
|
||||
// Watch out for case-difference when fixing: { offerToReceiveVideo: true }
|
||||
test.setOfferOptions({ optional: [{ OfferToReceiveVideo: true }] });
|
||||
|
@ -18,10 +18,8 @@
|
||||
|
||||
runNetworkTest(function() {
|
||||
var test = new PeerConnectionTest();
|
||||
test.setOfferOptions({
|
||||
offerToReceiveVideo: true,
|
||||
offerToReceiveAudio: true
|
||||
});
|
||||
test.setMediaConstraints([], [{audio: true, video: true}]);
|
||||
test.setOfferOptions({ offerToReceiveVideo: true, offerToReceiveAudio: true });
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
|
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="templates.js"></script>
|
||||
<script type="application/javascript" src="turnConfig.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1091242",
|
||||
title: "Multistream: Two audio streams"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
test.setMediaConstraints([{audio: true}, {audio: true}],
|
||||
[{audio: true}, {audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="templates.js"></script>
|
||||
<script type="application/javascript" src="turnConfig.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
createHTML({
|
||||
bug: "1091242",
|
||||
title: "Multistream: Two audio streams, two video streams"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
test.setMediaConstraints([{audio: true}, {video: true}, {audio: true},
|
||||
{video: true}],
|
||||
[{audio: true}, {video: true}, {audio: true},
|
||||
{video: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="templates.js"></script>
|
||||
<script type="application/javascript" src="turnConfig.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
createHTML({
|
||||
bug: "1091242",
|
||||
title: "Multistream: Two audio/video streams"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
test.setMediaConstraints([{audio: true, video: true},
|
||||
{audio: true, video: true}],
|
||||
[{audio: true, video: true},
|
||||
{audio: true, video: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="templates.js"></script>
|
||||
<script type="application/javascript" src="turnConfig.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1091242",
|
||||
title: "Multistream: Two video streams"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
test.setMediaConstraints([{video: true}, {video: true}],
|
||||
[{video: true}, {video: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -31,3 +31,5 @@ LOCAL_INCLUDES += [
|
||||
'/dom/media/webaudio',
|
||||
]
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -743,7 +743,7 @@ bool WebMReader::DecodeOpus(const unsigned char* aData, size_t aLength,
|
||||
// Discard padding should be used only on the final packet, so
|
||||
// decoding after a padding discard is invalid.
|
||||
LOG(PR_LOG_DEBUG, ("Opus error, discard padding on interstitial packet"));
|
||||
GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, RequestSampleCallback::DECODE_ERROR);
|
||||
GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, DECODE_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -797,7 +797,7 @@ bool WebMReader::DecodeOpus(const unsigned char* aData, size_t aLength,
|
||||
if (discardPadding < 0) {
|
||||
// Negative discard padding is invalid.
|
||||
LOG(PR_LOG_DEBUG, ("Opus error, negative discard padding"));
|
||||
GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, RequestSampleCallback::DECODE_ERROR);
|
||||
GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, DECODE_ERROR);
|
||||
return false;
|
||||
}
|
||||
if (discardPadding > 0) {
|
||||
@ -810,7 +810,7 @@ bool WebMReader::DecodeOpus(const unsigned char* aData, size_t aLength,
|
||||
if (discardFrames.value() > frames) {
|
||||
// Discarding more than the entire packet is invalid.
|
||||
LOG(PR_LOG_DEBUG, ("Opus error, discard padding larger than packet"));
|
||||
GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, RequestSampleCallback::DECODE_ERROR);
|
||||
GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, DECODE_ERROR);
|
||||
return false;
|
||||
}
|
||||
LOG(PR_LOG_DEBUG, ("Opus decoder discarding %d of %d frames",
|
||||
|
@ -43,3 +43,5 @@ LOCAL_INCLUDES += [
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -13,3 +13,5 @@ UNIFIED_SOURCES += [
|
||||
]
|
||||
|
||||
OS_LIBS += ['-framework Carbon']
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -45,6 +45,15 @@ static const char16_t OPEN_CURL = '{';
|
||||
static const char16_t CLOSE_CURL = '}';
|
||||
static const char16_t NUMBER_SIGN = '#';
|
||||
static const char16_t QUESTIONMARK = '?';
|
||||
static const char16_t PERCENT_SIGN = '%';
|
||||
static const char16_t EXCLAMATION = '!';
|
||||
static const char16_t DOLLAR = '$';
|
||||
static const char16_t AMPERSAND = '&';
|
||||
static const char16_t OPENBRACE = '(';
|
||||
static const char16_t CLOSINGBRACE = ')';
|
||||
static const char16_t COMMA = ',';
|
||||
static const char16_t EQUALS = '=';
|
||||
static const char16_t ATSYMBOL = '@';
|
||||
|
||||
static uint32_t kSubHostPathCharacterCutoff = 512;
|
||||
|
||||
@ -140,6 +149,14 @@ isNumberToken(char16_t aSymbol)
|
||||
return (aSymbol >= '0' && aSymbol <= '9');
|
||||
}
|
||||
|
||||
bool
|
||||
isValidHexDig(char16_t aHexDig)
|
||||
{
|
||||
return (isNumberToken(aHexDig) ||
|
||||
(aHexDig >= 'A' && aHexDig <= 'F') ||
|
||||
(aHexDig >= 'a' && aHexDig <= 'f'));
|
||||
}
|
||||
|
||||
void
|
||||
nsCSPParser::resetCurChar(const nsAString& aToken)
|
||||
{
|
||||
@ -157,14 +174,118 @@ nsCSPParser::atEndOfPath()
|
||||
return (atEnd() || peek(QUESTIONMARK) || peek(NUMBER_SIGN));
|
||||
}
|
||||
|
||||
void
|
||||
nsCSPParser::percentDecodeStr(const nsAString& aEncStr, nsAString& outDecStr)
|
||||
{
|
||||
outDecStr.Truncate();
|
||||
|
||||
// helper function that should not be visible outside this methods scope
|
||||
struct local {
|
||||
static inline char16_t convertHexDig(char16_t aHexDig) {
|
||||
if (isNumberToken(aHexDig)) {
|
||||
return aHexDig - '0';
|
||||
}
|
||||
if (aHexDig >= 'A' && aHexDig <= 'F') {
|
||||
return aHexDig - 'A' + 10;
|
||||
}
|
||||
// must be a lower case character
|
||||
// (aHexDig >= 'a' && aHexDig <= 'f')
|
||||
return aHexDig - 'a' + 10;
|
||||
}
|
||||
};
|
||||
|
||||
const char16_t *cur, *end, *hexDig1, *hexDig2;
|
||||
cur = aEncStr.BeginReading();
|
||||
end = aEncStr.EndReading();
|
||||
|
||||
while (cur != end) {
|
||||
// if it's not a percent sign then there is
|
||||
// nothing to do for that character
|
||||
if (*cur != PERCENT_SIGN) {
|
||||
outDecStr.Append(*cur);
|
||||
cur++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the two hexDigs following the '%'-sign
|
||||
hexDig1 = cur + 1;
|
||||
hexDig2 = cur + 2;
|
||||
|
||||
// if there are no hexdigs after the '%' then
|
||||
// there is nothing to do for us.
|
||||
if (hexDig1 == end || hexDig2 == end ||
|
||||
!isValidHexDig(*hexDig1) ||
|
||||
!isValidHexDig(*hexDig2)) {
|
||||
outDecStr.Append(PERCENT_SIGN);
|
||||
cur++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// decode "% hexDig1 hexDig2" into a character.
|
||||
char16_t decChar = (local::convertHexDig(*hexDig1) << 4) +
|
||||
local::convertHexDig(*hexDig2);
|
||||
outDecStr.Append(decChar);
|
||||
|
||||
// increment 'cur' to after the second hexDig
|
||||
cur = ++hexDig2;
|
||||
}
|
||||
}
|
||||
|
||||
// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
bool
|
||||
nsCSPParser::atValidPathChar()
|
||||
nsCSPParser::atValidUnreservedChar()
|
||||
{
|
||||
return (peek(isCharacterToken) || peek(isNumberToken) ||
|
||||
peek(DASH) || peek(DOT) ||
|
||||
peek(UNDERLINE) || peek(TILDE));
|
||||
}
|
||||
|
||||
// sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
// / "*" / "+" / "," / ";" / "="
|
||||
// Please note that even though ',' and ';' appear to be
|
||||
// valid sub-delims according to the RFC production of paths,
|
||||
// both can not appear here by itself, they would need to be
|
||||
// pct-encoded in order to be part of the path.
|
||||
bool
|
||||
nsCSPParser::atValidSubDelimChar()
|
||||
{
|
||||
return (peek(EXCLAMATION) || peek(DOLLAR) || peek(AMPERSAND) ||
|
||||
peek(SINGLEQUOTE) || peek(OPENBRACE) || peek(CLOSINGBRACE) ||
|
||||
peek(WILDCARD) || peek(PLUS) || peek(EQUALS));
|
||||
}
|
||||
|
||||
// pct-encoded = "%" HEXDIG HEXDIG
|
||||
bool
|
||||
nsCSPParser::atValidPctEncodedChar()
|
||||
{
|
||||
const char16_t* pctCurChar = mCurChar;
|
||||
|
||||
if ((pctCurChar + 2) >= mEndChar) {
|
||||
// string too short, can't be a valid pct-encoded char.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Any valid pct-encoding must follow the following format:
|
||||
// "% HEXDIG HEXDIG"
|
||||
if (PERCENT_SIGN != *pctCurChar ||
|
||||
!isValidHexDig(*(pctCurChar+1)) ||
|
||||
!isValidHexDig(*(pctCurChar+2))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
||||
// http://tools.ietf.org/html/rfc3986#section-3.3
|
||||
bool
|
||||
nsCSPParser::atValidPathChar()
|
||||
{
|
||||
return (atValidUnreservedChar() ||
|
||||
atValidSubDelimChar() ||
|
||||
atValidPctEncodedChar() ||
|
||||
peek(COLON) || peek(ATSYMBOL));
|
||||
}
|
||||
|
||||
void
|
||||
nsCSPParser::logWarningErrorToConsole(uint32_t aSeverityFlag,
|
||||
const char* aProperty,
|
||||
@ -253,10 +374,15 @@ nsCSPParser::subPath(nsCSPHostSrc* aCspHost)
|
||||
// is longer than 512 characters, or also to avoid endless loops
|
||||
// in case we are parsing unrecognized characters in the following loop.
|
||||
uint32_t charCounter = 0;
|
||||
nsString pctDecodedSubPath;
|
||||
|
||||
while (!atEndOfPath()) {
|
||||
if (peek(SLASH)) {
|
||||
aCspHost->appendPath(mCurValue);
|
||||
// before appendig any additional portion of a subpath we have to pct-decode
|
||||
// that portion of the subpath. atValidPathChar() already verified a correct
|
||||
// pct-encoding, now we can safely decode and append the decoded-sub path.
|
||||
percentDecodeStr(mCurValue, pctDecodedSubPath);
|
||||
aCspHost->appendPath(pctDecodedSubPath);
|
||||
// Resetting current value since we are appending parts of the path
|
||||
// to aCspHost, e.g; "http://www.example.com/path1/path2" then the
|
||||
// first part is "/path1", second part "/path2"
|
||||
@ -269,12 +395,23 @@ nsCSPParser::subPath(nsCSPHostSrc* aCspHost)
|
||||
params, ArrayLength(params));
|
||||
return false;
|
||||
}
|
||||
// potentially we have encountred a valid pct-encoded character in atValidPathChar();
|
||||
// if so, we have to account for "% HEXDIG HEXDIG" and advance the pointer past
|
||||
// the pct-encoded char.
|
||||
if (peek(PERCENT_SIGN)) {
|
||||
advance();
|
||||
advance();
|
||||
}
|
||||
advance();
|
||||
if (++charCounter > kSubHostPathCharacterCutoff) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
aCspHost->appendPath(mCurValue);
|
||||
// before appendig any additional portion of a subpath we have to pct-decode
|
||||
// that portion of the subpath. atValidPathChar() already verified a correct
|
||||
// pct-encoding, now we can safely decode and append the decoded-sub path.
|
||||
percentDecodeStr(mCurValue, pctDecodedSubPath);
|
||||
aCspHost->appendPath(pctDecodedSubPath);
|
||||
resetCurValue();
|
||||
return true;
|
||||
}
|
||||
@ -301,7 +438,9 @@ nsCSPParser::path(nsCSPHostSrc* aCspHost)
|
||||
if (atEndOfPath()) {
|
||||
// one slash right after host [port] is also considered a path, e.g.
|
||||
// www.example.com/ should result in www.example.com/
|
||||
aCspHost->appendPath(mCurValue);
|
||||
// please note that we do not have to perform any pct-decoding here
|
||||
// because we are just appending a '/' and not any actual chars.
|
||||
aCspHost->appendPath(NS_LITERAL_STRING("/"));
|
||||
return true;
|
||||
}
|
||||
// path can begin with "/" but not "//"
|
||||
|
@ -128,8 +128,13 @@ class nsCSPParser {
|
||||
bool path(nsCSPHostSrc* aCspHost);
|
||||
|
||||
bool subHost(); // helper function to parse subDomains
|
||||
bool atValidUnreservedChar(); // helper function to parse unreserved
|
||||
bool atValidSubDelimChar(); // helper function to parse sub-delims
|
||||
bool atValidPctEncodedChar(); // helper function to parse pct-encoded
|
||||
bool subPath(nsCSPHostSrc* aCspHost); // helper function to parse paths
|
||||
void reportURIList(nsTArray<nsCSPBaseSrc*>& outSrcs); // helper function to parse report-uris
|
||||
void percentDecodeStr(const nsAString& aEncStr, // helper function to percent-decode
|
||||
nsAString& outDecStr);
|
||||
|
||||
inline bool atEnd()
|
||||
{
|
||||
|
@ -29,6 +29,20 @@ interface MozInputMethod : EventTarget {
|
||||
// Activate or decactive current input method window.
|
||||
void setActive(boolean isActive);
|
||||
|
||||
// Add a dynamically declared input.
|
||||
//
|
||||
// The id must not be the same with any statically declared input in the app
|
||||
// manifest. If an input of the same id is already declared, the info of that
|
||||
// input will be updated.
|
||||
Promise<void> addInput(DOMString inputId, object inputManifest);
|
||||
|
||||
// Remove a dynamically declared input.
|
||||
//
|
||||
// The id must not be the same with any statically declared input in the app
|
||||
// manifest. Silently resolves if the input is not previously declared;
|
||||
// rejects if attempt to remove a statically declared input.
|
||||
Promise<void> removeInput(DOMString id);
|
||||
|
||||
// The following are internal methods for Firefox OS system app only.
|
||||
|
||||
// Set the value on the currently focused element. This has to be used
|
||||
|
@ -67,6 +67,7 @@ interface PeerConnectionImpl {
|
||||
boolean pluginCrash(unsigned long long pluginId, DOMString name, DOMString pluginDumpID);
|
||||
|
||||
/* Attributes */
|
||||
[Constant]
|
||||
readonly attribute DOMString fingerprint;
|
||||
readonly attribute DOMString localDescription;
|
||||
readonly attribute DOMString remoteDescription;
|
||||
@ -74,7 +75,6 @@ interface PeerConnectionImpl {
|
||||
readonly attribute PCImplIceConnectionState iceConnectionState;
|
||||
readonly attribute PCImplIceGatheringState iceGatheringState;
|
||||
readonly attribute PCImplSignalingState signalingState;
|
||||
readonly attribute PCImplSipccState sipccState;
|
||||
attribute DOMString id;
|
||||
|
||||
attribute DOMString peerIdentity;
|
||||
|
@ -38,3 +38,5 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -7,12 +7,12 @@
|
||||
|
||||
[scriptable, uuid(D5B61B82-1DA4-11d3-BF87-00105A1B0627)]
|
||||
interface nsIController : nsISupports {
|
||||
boolean isCommandEnabled(in string command);
|
||||
boolean supportsCommand(in string command);
|
||||
boolean isCommandEnabled(in string command);
|
||||
boolean supportsCommand(in string command);
|
||||
|
||||
void doCommand(in string command);
|
||||
void doCommand(in string command);
|
||||
|
||||
void onEvent(in string eventName);
|
||||
void onEvent(in string eventName);
|
||||
};
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ interface nsIController : nsISupports {
|
||||
|
||||
interface nsICommandParams;
|
||||
|
||||
[scriptable, uuid(EEC0B435-7F53-44FE-B00A-CF3EED65C01A)]
|
||||
[scriptable, uuid(EBE55080-C8A9-11D5-A73C-DD620D6E04BC)]
|
||||
interface nsICommandController : nsISupports
|
||||
{
|
||||
|
||||
@ -33,8 +33,6 @@ interface nsICommandController : nsISupports
|
||||
|
||||
void doCommandWithParams(in string command, in nsICommandParams aCommandParams);
|
||||
|
||||
void getSupportedCommands(out unsigned long count,
|
||||
[array, size_is(count), retval] out string commands);
|
||||
};
|
||||
|
||||
|
||||
|
@ -55,3 +55,5 @@ LOCAL_INCLUDES += [
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -98,12 +98,12 @@ skip-if(Android||B2G) needs-focus == 462758-grabbers-resizers.html 462758-grabbe
|
||||
== 388980-1.html 388980-1-ref.html
|
||||
needs-focus == spellcheck-superscript-1.html spellcheck-superscript-1-ref.html
|
||||
skip-if(B2G) fails-if(Android) needs-focus != spellcheck-superscript-2.html spellcheck-superscript-2-ref.html # bug 783658
|
||||
needs-focus == 824080-1.html 824080-1-ref.html
|
||||
needs-focus pref(selectioncaret.enabled,false) == 824080-1.html 824080-1-ref.html
|
||||
needs-focus == 824080-2.html 824080-2-ref.html
|
||||
needs-focus test-pref(selectioncaret.enabled,false) == 824080-3.html 824080-3-ref.html
|
||||
needs-focus pref(selectioncaret.enabled,false) == 824080-3.html 824080-3-ref.html
|
||||
needs-focus != 824080-2.html 824080-3.html
|
||||
needs-focus == 824080-4.html 824080-4-ref.html
|
||||
needs-focus test-pref(selectioncaret.enabled,false) == 824080-5.html 824080-5-ref.html
|
||||
needs-focus pref(selectioncaret.enabled,false) == 824080-4.html 824080-4-ref.html
|
||||
needs-focus pref(selectioncaret.enabled,false) == 824080-5.html 824080-5-ref.html
|
||||
needs-focus != 824080-4.html 824080-5.html
|
||||
needs-focus == 824080-6.html 824080-6-ref.html
|
||||
needs-focus pref(selectioncaret.enabled,false) == 824080-7.html 824080-7-ref.html
|
||||
|
@ -174,10 +174,3 @@ nsBaseCommandController::OnEvent(const char * aEventName)
|
||||
NS_ENSURE_ARG_POINTER(aEventName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseCommandController::GetSupportedCommands(uint32_t* aCount, char*** aCommands)
|
||||
{
|
||||
NS_ENSURE_STATE(mCommandTable);
|
||||
return mCommandTable->GetSupportedCommands(aCount, aCommands);
|
||||
}
|
||||
|
@ -188,30 +188,6 @@ nsControllerCommandTable::GetCommandState(const char *aCommandName, nsICommandPa
|
||||
return commandHandler->GetCommandStateParams(aCommandName, aParams, aCommandRefCon);
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
AddCommand(const nsACString& aKey, nsIControllerCommand* aData, void* aArg)
|
||||
{
|
||||
// aArg is a pointer to a array of strings. It gets incremented after
|
||||
// allocating each one so that it points to the next location for AddCommand
|
||||
// to assign a string to.
|
||||
char*** commands = static_cast<char***>(aArg);
|
||||
(**commands) = ToNewCString(aKey);
|
||||
(*commands)++;
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsControllerCommandTable::GetSupportedCommands(uint32_t* aCount,
|
||||
char*** aCommands)
|
||||
{
|
||||
char** commands =
|
||||
static_cast<char **>(NS_Alloc(sizeof(char *) * mCommandsTable.Count()));
|
||||
*aCount = mCommandsTable.Count();
|
||||
*aCommands = commands;
|
||||
|
||||
mCommandsTable.EnumerateRead(AddCommand, &commands);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewControllerCommandTable(nsIControllerCommandTable** aResult)
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
[scriptable, uuid(c847f90e-b8f3-49db-a4df-8867831f2800)]
|
||||
[scriptable, uuid(d1a47834-6ad4-11d7-bfad-000393636592)]
|
||||
interface nsIControllerCommandTable : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -82,9 +82,6 @@ interface nsIControllerCommandTable : nsISupports
|
||||
void doCommandParams(in string aCommandName, in nsICommandParams aParam, in nsISupports aCommandRefCon);
|
||||
|
||||
void getCommandState(in string aCommandName, in nsICommandParams aParam, in nsISupports aCommandRefCon);
|
||||
|
||||
void getSupportedCommands(out unsigned long count,
|
||||
[array, size_is(count), retval] out string commands);
|
||||
};
|
||||
|
||||
|
||||
|
@ -25,3 +25,5 @@ else:
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -27,3 +27,5 @@ MSVC_ENABLE_PGO = True
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -10,3 +10,5 @@ UNIFIED_SOURCES += [
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -12,3 +12,5 @@ UNIFIED_SOURCES += [
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -23,7 +23,7 @@ UNIFIED_SOURCES += [
|
||||
'TestTiledLayerBuffer.cpp',
|
||||
]
|
||||
|
||||
# Because of gkmedia on windows we wont find these
|
||||
# Because of gkmedia on windows we won't find these
|
||||
# symbols in xul.dll.
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'windows':
|
||||
UNIFIED_SOURCES += [ '%s/gfx/2d/unittest/%s' % (TOPSRCDIR, p) for p in [
|
||||
@ -48,3 +48,5 @@ LOCAL_INCLUDES += [
|
||||
FINAL_LIBRARY = 'xul-gtest'
|
||||
|
||||
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -70,3 +70,5 @@ if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['HAVE_ARM_NEON']:
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -216,7 +216,8 @@ DynamicImage::IsOpaque()
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DynamicImage::GetImageContainer(LayerManager* aManager, ImageContainer** _retval)
|
||||
DynamicImage::GetImageContainer(LayerManager* aManager,
|
||||
ImageContainer** _retval)
|
||||
{
|
||||
*_retval = nullptr;
|
||||
return NS_OK;
|
||||
@ -331,7 +332,9 @@ DynamicImage::SetAnimationStartTime(const mozilla::TimeStamp& aTime)
|
||||
{ }
|
||||
|
||||
nsIntSize
|
||||
DynamicImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame, GraphicsFilter aFilter, uint32_t aFlags)
|
||||
DynamicImage::OptimalImageSizeForDest(const gfxSize& aDest,
|
||||
uint32_t aWhichFrame,
|
||||
GraphicsFilter aFilter, uint32_t aFlags)
|
||||
{
|
||||
gfxIntSize size(mDrawable->Size());
|
||||
return nsIntSize(size.width, size.height);
|
||||
|
@ -14,7 +14,6 @@ namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
/**
|
||||
|
||||
* An Image that is dynamically created. The content of the image is provided by
|
||||
* a gfxDrawable. It's anticipated that most uses of DynamicImage will be
|
||||
* ephemeral.
|
||||
@ -36,8 +35,8 @@ public:
|
||||
|
||||
virtual already_AddRefed<ProgressTracker> GetProgressTracker() MOZ_OVERRIDE;
|
||||
virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
|
||||
|
||||
virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
|
||||
virtual size_t SizeOfSourceWithComputedFallback(
|
||||
MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
|
||||
virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation,
|
||||
MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user