зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
4aea0165dc
|
@ -425,14 +425,14 @@ private:
|
|||
enum Interfaces
|
||||
{
|
||||
HYPERTEXT = 1,
|
||||
HYPERLINK = 2,
|
||||
IMAGE = 4,
|
||||
VALUE = 8,
|
||||
TABLE = 16,
|
||||
TABLECELL = 32,
|
||||
DOCUMENT = 64,
|
||||
SELECTION = 128,
|
||||
ACTION = 256,
|
||||
HYPERLINK = 1 << 1,
|
||||
IMAGE = 1 << 2,
|
||||
VALUE = 1 << 3,
|
||||
TABLE = 1 << 4,
|
||||
TABLECELL = 1 << 5,
|
||||
DOCUMENT = 1 << 6,
|
||||
SELECTION = 1 << 7,
|
||||
ACTION = 1 << 8,
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -30,14 +30,12 @@
|
|||
#include "nsStringGlue.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
// we want a wmain entry point
|
||||
#ifdef MOZ_ASAN
|
||||
// ASAN requires firefox.exe to be built with -MD, and it's OK if we don't
|
||||
// support Windows XP SP2 in ASAN builds.
|
||||
#define XRE_DONT_SUPPORT_XPSP2
|
||||
#endif
|
||||
#define XRE_WANT_ENVIRON
|
||||
#include "nsWindowsWMain.cpp"
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1900)
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
@ -53,6 +51,12 @@
|
|||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/WindowsDllBlocklist.h"
|
||||
|
||||
#if !defined(MOZ_WIDGET_COCOA) && !defined(MOZ_WIDGET_ANDROID) \
|
||||
&& !(defined(XP_LINUX) && defined(MOZ_SANDBOX))
|
||||
#define MOZ_BROWSER_CAN_BE_CONTENTPROC
|
||||
#include "../../ipc/contentproc/plugin-container.cpp"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
|
@ -128,6 +132,10 @@ XRE_StartupTimelineRecordType XRE_StartupTimelineRecord;
|
|||
XRE_mainType XRE_main;
|
||||
XRE_StopLateWriteChecksType XRE_StopLateWriteChecks;
|
||||
XRE_XPCShellMainType XRE_XPCShellMain;
|
||||
XRE_GetProcessTypeType XRE_GetProcessType;
|
||||
XRE_SetProcessTypeType XRE_SetProcessType;
|
||||
XRE_InitChildProcessType XRE_InitChildProcess;
|
||||
XRE_EnableSameExecutableForContentProcType XRE_EnableSameExecutableForContentProc;
|
||||
|
||||
static const nsDynamicFunctionLoad kXULFuncs[] = {
|
||||
{ "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
|
||||
|
@ -138,6 +146,10 @@ static const nsDynamicFunctionLoad kXULFuncs[] = {
|
|||
{ "XRE_main", (NSFuncPtr*) &XRE_main },
|
||||
{ "XRE_StopLateWriteChecks", (NSFuncPtr*) &XRE_StopLateWriteChecks },
|
||||
{ "XRE_XPCShellMain", (NSFuncPtr*) &XRE_XPCShellMain },
|
||||
{ "XRE_GetProcessType", (NSFuncPtr*) &XRE_GetProcessType },
|
||||
{ "XRE_SetProcessType", (NSFuncPtr*) &XRE_SetProcessType },
|
||||
{ "XRE_InitChildProcess", (NSFuncPtr*) &XRE_InitChildProcess },
|
||||
{ "XRE_EnableSameExecutableForContentProc", (NSFuncPtr*) &XRE_EnableSameExecutableForContentProc },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
|
@ -296,6 +308,7 @@ sizeof(XPCOM_DLL) - 1))
|
|||
// This will set this thread as the main thread.
|
||||
NS_LogInit();
|
||||
|
||||
if (xreDirectory) {
|
||||
// chop XPCOM_DLL off exePath
|
||||
*lastSlash = '\0';
|
||||
#ifdef XP_MACOSX
|
||||
|
@ -309,12 +322,40 @@ sizeof(XPCOM_DLL) - 1))
|
|||
rv = NS_NewNativeLocalFile(nsDependentCString(exePath), false,
|
||||
xreDirectory);
|
||||
#endif
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[], char* envp[])
|
||||
{
|
||||
#ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
|
||||
// We are launching as a content process, delegate to the appropriate
|
||||
// main
|
||||
if (argc > 1 && IsArg(argv[1], "contentproc")) {
|
||||
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||
// We need to initialize the sandbox TargetServices before InitXPCOMGlue
|
||||
// because we might need the sandbox broker to give access to some files.
|
||||
if (!sandboxing::GetInitializedTargetServices()) {
|
||||
Output("Failed to initialize the sandbox target services.");
|
||||
return 255;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult rv = InitXPCOMGlue(argv[0], nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
return 255;
|
||||
}
|
||||
|
||||
int result = content_process_main(argc, argv);
|
||||
|
||||
// InitXPCOMGlue calls NS_LogInit, so we need to balance it here.
|
||||
NS_LogTerm();
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
mozilla::TimeStamp start = mozilla::TimeStamp::Now();
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
|
@ -379,6 +420,10 @@ int main(int argc, char* argv[], char* envp[])
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
|
||||
XRE_EnableSameExecutableForContentProc();
|
||||
#endif
|
||||
|
||||
int result = do_main(argc, argv, envp, xreDirectory);
|
||||
|
||||
NS_LogTerm();
|
||||
|
|
|
@ -1401,10 +1401,8 @@ pref("dom.push.enabled", true);
|
|||
pref("toolkit.pageThumbs.minWidth", 280);
|
||||
pref("toolkit.pageThumbs.minHeight", 190);
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// Enable speech synthesis, only Nightly for now
|
||||
// Enable speech synthesis
|
||||
pref("media.webspeech.synth.enabled", true);
|
||||
#endif
|
||||
|
||||
pref("browser.esedbreader.loglevel", "Error");
|
||||
|
||||
|
|
|
@ -576,15 +576,20 @@ Sanitizer.prototype = {
|
|||
|
||||
// Clear all push notification subscriptions
|
||||
try {
|
||||
yield new Promise((resolve, reject) => {
|
||||
let push = Cc["@mozilla.org/push/Service;1"]
|
||||
.getService(Ci.nsIPushService);
|
||||
push.clearForDomain("*", status => {
|
||||
if (!Components.isSuccessCode(status)) {
|
||||
dump("Error clearing Web Push data: " + status + "\n");
|
||||
if (Components.isSuccessCode(status)) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error("Error clearing push subscriptions: " +
|
||||
status));
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
dump("Web Push may not be available.\n");
|
||||
});
|
||||
} catch (ex) {
|
||||
seenException = ex;
|
||||
}
|
||||
|
||||
TelemetryStopwatch.finish("FX_SANITIZE_SITESETTINGS", refObj);
|
||||
|
|
|
@ -2891,10 +2891,16 @@
|
|||
let tabs = this.visibleTabs;
|
||||
|
||||
// count backwards for aIndex < 0
|
||||
if (aIndex < 0)
|
||||
if (aIndex < 0) {
|
||||
aIndex += tabs.length;
|
||||
// clamp at index 0 if still negative.
|
||||
if (aIndex < 0)
|
||||
aIndex = 0;
|
||||
} else if (aIndex >= tabs.length) {
|
||||
// clamp at right-most tab if out of range.
|
||||
aIndex = tabs.length - 1;
|
||||
}
|
||||
|
||||
if (aIndex >= 0 && aIndex < tabs.length)
|
||||
this.selectedTab = tabs[aIndex];
|
||||
|
||||
if (aEvent) {
|
||||
|
|
|
@ -1,22 +1,81 @@
|
|||
function test() {
|
||||
for (let i = 0; i < 9; i++)
|
||||
gBrowser.addTab();
|
||||
"use strict";
|
||||
|
||||
var isLinux = navigator.platform.indexOf("Linux") == 0;
|
||||
for (let i = 9; i >= 1; i--) {
|
||||
function test() {
|
||||
const isLinux = navigator.platform.indexOf("Linux") == 0;
|
||||
|
||||
function assertTab(expectedTab) {
|
||||
is(gBrowser.tabContainer.selectedIndex, expectedTab,
|
||||
`tab index ${expectedTab} should be selected`);
|
||||
}
|
||||
|
||||
function sendAccelKey(key) {
|
||||
// Make sure the keystroke goes to chrome.
|
||||
document.activeElement.blur();
|
||||
|
||||
EventUtils.synthesizeKey(i.toString(), { altKey: isLinux, accelKey: !isLinux });
|
||||
|
||||
is(gBrowser.tabContainer.selectedIndex, (i == 9 ? gBrowser.tabs.length : i) - 1,
|
||||
(isLinux ? "Alt" : "Accel") + "+" + i + " selects expected tab");
|
||||
EventUtils.synthesizeKey(key.toString(), { altKey: isLinux, accelKey: !isLinux });
|
||||
}
|
||||
|
||||
gBrowser.selectTabAtIndex(-3);
|
||||
is(gBrowser.tabContainer.selectedIndex, gBrowser.tabs.length - 3,
|
||||
"gBrowser.selectTabAtIndex(-3) selects expected tab");
|
||||
function createTabs(count) {
|
||||
for (let n = 0; n < count; n++)
|
||||
gBrowser.addTab();
|
||||
}
|
||||
|
||||
for (let i = 0; i < 9; i++)
|
||||
function testKey(key, expectedTab) {
|
||||
sendAccelKey(key);
|
||||
assertTab(expectedTab);
|
||||
}
|
||||
|
||||
function testIndex(index, expectedTab) {
|
||||
gBrowser.selectTabAtIndex(index);
|
||||
assertTab(expectedTab);
|
||||
}
|
||||
|
||||
// Create fewer tabs than our 9 number keys.
|
||||
is(gBrowser.tabs.length, 1, "should have 1 tab");
|
||||
createTabs(4);
|
||||
is(gBrowser.tabs.length, 5, "should have 5 tabs");
|
||||
|
||||
// Test keyboard shortcuts. Order tests so that no two test cases have the
|
||||
// same expected tab in a row. This ensures that tab selection actually
|
||||
// changed the selected tab.
|
||||
testKey(8, 4);
|
||||
testKey(1, 0);
|
||||
testKey(2, 1);
|
||||
testKey(4, 3);
|
||||
testKey(9, 4);
|
||||
|
||||
// Test index selection.
|
||||
testIndex(0, 0);
|
||||
testIndex(4, 4);
|
||||
testIndex(-5, 0);
|
||||
testIndex(5, 4);
|
||||
testIndex(-4, 1);
|
||||
testIndex(1, 1);
|
||||
testIndex(-1, 4);
|
||||
testIndex(9, 4);
|
||||
|
||||
// Create more tabs than our 9 number keys.
|
||||
createTabs(10);
|
||||
is(gBrowser.tabs.length, 15, "should have 15 tabs");
|
||||
|
||||
// Test keyboard shortcuts.
|
||||
testKey(2, 1);
|
||||
testKey(1, 0);
|
||||
testKey(4, 3);
|
||||
testKey(8, 7);
|
||||
testKey(9, 14);
|
||||
|
||||
// Test index selection.
|
||||
testIndex(-15, 0);
|
||||
testIndex(14, 14);
|
||||
testIndex(-14, 1);
|
||||
testIndex(15, 14);
|
||||
testIndex(-1, 14);
|
||||
testIndex(0, 0);
|
||||
testIndex(1, 1);
|
||||
testIndex(9, 9);
|
||||
|
||||
// Clean up tabs.
|
||||
for (let n = 15; n > 1; n--)
|
||||
gBrowser.removeTab(gBrowser.selectedTab, {skipPermitUnload: true});
|
||||
is(gBrowser.tabs.length, 1, "should have 1 tab");
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
// There should be one tab when we start the test
|
||||
let [origTab] = gBrowser.visibleTabs;
|
||||
|
@ -33,16 +35,18 @@ add_task(function* () {
|
|||
is(visible[1], testTab, "next is the test tab");
|
||||
is(gBrowser.tabs.length, 3, "3 tabs should still be open");
|
||||
|
||||
gBrowser.selectTabAtIndex(0);
|
||||
is(gBrowser.selectedTab, pinned, "first tab is pinned");
|
||||
gBrowser.selectTabAtIndex(1);
|
||||
is(gBrowser.selectedTab, testTab, "second tab is the test tab");
|
||||
gBrowser.selectTabAtIndex(0);
|
||||
is(gBrowser.selectedTab, pinned, "first tab is pinned");
|
||||
gBrowser.selectTabAtIndex(2);
|
||||
is(gBrowser.selectedTab, testTab, "no third tab, so no change");
|
||||
gBrowser.selectTabAtIndex(0);
|
||||
is(gBrowser.selectedTab, pinned, "switch back to the pinned");
|
||||
gBrowser.selectTabAtIndex(2);
|
||||
is(gBrowser.selectedTab, pinned, "no third tab, so no change");
|
||||
is(gBrowser.selectedTab, testTab, "no third tab, so select last tab");
|
||||
gBrowser.selectTabAtIndex(-2);
|
||||
is(gBrowser.selectedTab, pinned, "pinned tab is second from left (when orig tab is hidden)");
|
||||
gBrowser.selectTabAtIndex(-1);
|
||||
is(gBrowser.selectedTab, testTab, "last tab is the test tab");
|
||||
|
||||
|
@ -91,4 +95,3 @@ add_task(function* () {
|
|||
is(gBrowser.selectedTab, origTab, "got the orig tab");
|
||||
is(origTab.hidden, false, "and it's not hidden -- visible!");
|
||||
});
|
||||
|
||||
|
|
|
@ -422,12 +422,13 @@ function createUserContextMenu(event, addCommandAttribute = true) {
|
|||
menuitem.setAttribute("usercontextid", identity.userContextId);
|
||||
menuitem.setAttribute("label", bundle.getString(identity.label));
|
||||
menuitem.setAttribute("accesskey", bundle.getString(identity.accessKey));
|
||||
menuitem.classList.add("menuitem-iconic");
|
||||
|
||||
if (addCommandAttribute) {
|
||||
menuitem.setAttribute("command", "Browser:NewUserContextTab");
|
||||
}
|
||||
|
||||
menuitem.style.listStyleImage = "url(" + identity.icon + ")";
|
||||
menuitem.setAttribute("image", identity.icon);
|
||||
|
||||
docfrag.appendChild(menuitem);
|
||||
});
|
||||
|
|
|
@ -33,6 +33,11 @@ const NOTIFY_TAB_RESTORED = "sessionstore-debug-tab-restored"; // WARNING: debug
|
|||
// the browser.sessionstore.max_concurrent_tabs pref.
|
||||
const MAX_CONCURRENT_TAB_RESTORES = 3;
|
||||
|
||||
// Amount (in CSS px) by which we allow window edges to be off-screen
|
||||
// when restoring a window, before we override the saved position to
|
||||
// pull the window back within the available screen area.
|
||||
const SCREEN_EDGE_SLOP = 8;
|
||||
|
||||
// global notifications observed
|
||||
const OBSERVING = [
|
||||
"browser-window-before-show", "domwindowclosed",
|
||||
|
@ -2165,7 +2170,7 @@ var SessionStoreInternal = {
|
|||
|
||||
// create a new tab
|
||||
let tabbrowser = aWindow.gBrowser;
|
||||
let tab = tabbrowser.selectedTab = tabbrowser.addTab();
|
||||
let tab = tabbrowser.selectedTab = tabbrowser.addTab(null, state);
|
||||
|
||||
// restore tab content
|
||||
this.restoreTab(tab, state);
|
||||
|
@ -2923,12 +2928,26 @@ var SessionStoreInternal = {
|
|||
let numVisibleTabs = 0;
|
||||
|
||||
for (var t = 0; t < newTabCount; t++) {
|
||||
tabs.push(t < openTabCount ?
|
||||
tabbrowser.tabs[t] :
|
||||
tabbrowser.addTab("about:blank", {
|
||||
skipAnimation: true,
|
||||
// When trying to restore into existing tab, we also take the userContextId
|
||||
// into account if present.
|
||||
let userContextId = winData.tabs[t].userContextId;
|
||||
let reuseExisting = t < openTabCount &&
|
||||
(tabbrowser.tabs[t].getAttribute("usercontextid") == (userContextId || ""));
|
||||
let tab = reuseExisting ? tabbrowser.tabs[t] :
|
||||
tabbrowser.addTab("about:blank",
|
||||
{skipAnimation: true,
|
||||
forceNotRemote: true,
|
||||
}));
|
||||
userContextId});
|
||||
|
||||
// If we inserted a new tab because the userContextId didn't match with the
|
||||
// open tab, even though `t < openTabCount`, we need to remove that open tab
|
||||
// and put the newly added tab in its place.
|
||||
if (!reuseExisting && t < openTabCount) {
|
||||
tabbrowser.removeTab(tabbrowser.tabs[t]);
|
||||
tabbrowser.moveTabTo(tab, t);
|
||||
}
|
||||
|
||||
tabs.push(tab);
|
||||
|
||||
if (winData.tabs[t].pinned)
|
||||
tabbrowser.pinTab(tabs[t]);
|
||||
|
@ -3471,26 +3490,40 @@ var SessionStoreInternal = {
|
|||
// convert screen's device pixel dimensions to CSS px dimensions
|
||||
screen.GetAvailRect(screenLeft, screenTop, screenWidth, screenHeight);
|
||||
let cssToDevScale = screen.defaultCSSScaleFactor;
|
||||
let screenWidthCss = screenWidth.value / cssToDevScale;
|
||||
let screenHeightCss = screenHeight.value / cssToDevScale;
|
||||
// constrain the dimensions to the actual space available
|
||||
if (aWidth > screenWidthCss) {
|
||||
aWidth = screenWidthCss;
|
||||
}
|
||||
if (aHeight > screenHeightCss) {
|
||||
aHeight = screenHeightCss;
|
||||
}
|
||||
// and then pull the window within the screen's bounds
|
||||
if (aLeft < screenLeftCss) {
|
||||
let screenRightCss = screenLeftCss + screenWidth.value / cssToDevScale;
|
||||
let screenBottomCss = screenTopCss + screenHeight.value / cssToDevScale;
|
||||
|
||||
// Pull the window within the screen's bounds (allowing a little slop
|
||||
// for windows that may be deliberately placed with their border off-screen
|
||||
// as when Win10 "snaps" a window to the left/right edge -- bug 1276516).
|
||||
// First, ensure the left edge is large enough...
|
||||
if (aLeft < screenLeftCss - SCREEN_EDGE_SLOP) {
|
||||
aLeft = screenLeftCss;
|
||||
} else if (aLeft + aWidth > screenLeftCss + screenWidthCss) {
|
||||
aLeft = screenLeftCss + screenWidthCss - aWidth;
|
||||
}
|
||||
if (aTop < screenTopCss) {
|
||||
// Then check the resulting right edge, and reduce it if necessary.
|
||||
let right = aLeft + aWidth;
|
||||
if (right > screenRightCss + SCREEN_EDGE_SLOP) {
|
||||
right = screenRightCss;
|
||||
// See if we can move the left edge leftwards to maintain width.
|
||||
if (aLeft > screenLeftCss) {
|
||||
aLeft = Math.max(right - aWidth, screenLeftCss);
|
||||
}
|
||||
}
|
||||
// Finally, update aWidth to account for the adjusted left and right edges.
|
||||
aWidth = right - aLeft;
|
||||
|
||||
// And do the same in the vertical dimension.
|
||||
if (aTop < screenTopCss - SCREEN_EDGE_SLOP) {
|
||||
aTop = screenTopCss;
|
||||
} else if (aTop + aHeight > screenTopCss + screenHeightCss) {
|
||||
aTop = screenTopCss + screenHeightCss - aHeight;
|
||||
}
|
||||
let bottom = aTop + aHeight;
|
||||
if (bottom > screenBottomCss + SCREEN_EDGE_SLOP) {
|
||||
bottom = screenBottomCss;
|
||||
if (aTop > screenTopCss) {
|
||||
aTop = Math.max(bottom - aHeight, screenTopCss);
|
||||
}
|
||||
}
|
||||
aHeight = bottom - aTop;
|
||||
}
|
||||
|
||||
// only modify those aspects which aren't correct yet
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
requestLongerTimeout(3);
|
||||
|
||||
add_task(function* () {
|
||||
for (let i = 0; i < 3; ++i) {
|
||||
let tab = gBrowser.addTab("http://example.com/", { userContextId: i });
|
||||
|
@ -47,3 +49,138 @@ add_task(function* () {
|
|||
yield promiseRemoveTab(tab2);
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
let tab = gBrowser.addTab("http://example.com/", { userContextId: 1 });
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
yield promiseBrowserLoaded(browser);
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
let tab2 = ss.undoCloseTab(window, 0);
|
||||
Assert.equal(tab2.getAttribute("usercontextid"), 1);
|
||||
yield promiseTabRestored(tab2);
|
||||
yield ContentTask.spawn(tab2.linkedBrowser, { expectedId: 1 }, function* (args) {
|
||||
Assert.equal(docShell.getOriginAttributes().userContextId,
|
||||
args.expectedId,
|
||||
"The docShell has the correct userContextId");
|
||||
});
|
||||
|
||||
yield promiseRemoveTab(tab2);
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
let win = window.openDialog(location, "_blank", "chrome,all,dialog=no");
|
||||
yield promiseWindowLoaded(win);
|
||||
|
||||
// Create 4 tabs with different userContextId.
|
||||
for (let userContextId = 1; userContextId < 5; userContextId++) {
|
||||
let tab = win.gBrowser.addTab("http://example.com/", {userContextId});
|
||||
yield promiseBrowserLoaded(tab.linkedBrowser);
|
||||
yield TabStateFlusher.flush(tab.linkedBrowser);
|
||||
}
|
||||
|
||||
// Move the default tab of window to the end.
|
||||
// We want the 1st tab to have non-default userContextId, so later when we
|
||||
// restore into win2 we can test restore into an existing tab with different
|
||||
// userContextId.
|
||||
win.gBrowser.moveTabTo(win.gBrowser.tabs[0], win.gBrowser.tabs.length - 1);
|
||||
|
||||
let winState = JSON.parse(ss.getWindowState(win));
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
Assert.equal(winState.windows[0].tabs[i].userContextId, i + 1,
|
||||
"1st Window: tabs[" + i + "].userContextId should exist.");
|
||||
}
|
||||
|
||||
let win2 = window.openDialog(location, "_blank", "chrome,all,dialog=no");
|
||||
yield promiseWindowLoaded(win2);
|
||||
|
||||
// Create tabs with different userContextId, but this time we create them with
|
||||
// fewer tabs and with different order with win.
|
||||
for (let userContextId = 3; userContextId > 0; userContextId--) {
|
||||
let tab = win2.gBrowser.addTab("http://example.com/", {userContextId});
|
||||
yield promiseBrowserLoaded(tab.linkedBrowser);
|
||||
yield TabStateFlusher.flush(tab.linkedBrowser);
|
||||
}
|
||||
|
||||
ss.setWindowState(win2, JSON.stringify(winState), true);
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
let browser = win2.gBrowser.tabs[i].linkedBrowser;
|
||||
yield ContentTask.spawn(browser, { expectedId: i + 1 }, function* (args) {
|
||||
Assert.equal(docShell.getOriginAttributes().userContextId,
|
||||
args.expectedId,
|
||||
"The docShell has the correct userContextId");
|
||||
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.userContextId,
|
||||
args.expectedId,
|
||||
"The document has the correct userContextId");
|
||||
});
|
||||
}
|
||||
|
||||
// Test the last tab, which doesn't have userContextId.
|
||||
let browser = win2.gBrowser.tabs[4].linkedBrowser;
|
||||
yield ContentTask.spawn(browser, { expectedId: 0 }, function* (args) {
|
||||
Assert.equal(docShell.getOriginAttributes().userContextId,
|
||||
args.expectedId,
|
||||
"The docShell has the correct userContextId");
|
||||
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.userContextId,
|
||||
args.expectedId,
|
||||
"The document has the correct userContextId");
|
||||
});
|
||||
|
||||
yield BrowserTestUtils.closeWindow(win);
|
||||
yield BrowserTestUtils.closeWindow(win2);
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
let win = window.openDialog(location, "_blank", "chrome,all,dialog=no");
|
||||
yield promiseWindowLoaded(win);
|
||||
|
||||
let tab = win.gBrowser.addTab("http://example.com/", { userContextId: 1 });
|
||||
yield promiseBrowserLoaded(tab.linkedBrowser);
|
||||
yield TabStateFlusher.flush(tab.linkedBrowser);
|
||||
|
||||
// win should have 1 default tab, and 1 container tab.
|
||||
Assert.equal(win.gBrowser.tabs.length, 2, "win should have 2 tabs");
|
||||
|
||||
let winState = JSON.parse(ss.getWindowState(win));
|
||||
|
||||
for (let i = 0; i < 2; i++) {
|
||||
Assert.equal(winState.windows[0].tabs[i].userContextId, i,
|
||||
"1st Window: tabs[" + i + "].userContextId should be " + i);
|
||||
}
|
||||
|
||||
let win2 = window.openDialog(location, "_blank", "chrome,all,dialog=no");
|
||||
yield promiseWindowLoaded(win2);
|
||||
|
||||
let tab2 = win2.gBrowser.addTab("http://example.com/", { userContextId : 1 });
|
||||
yield promiseBrowserLoaded(tab2.linkedBrowser);
|
||||
yield TabStateFlusher.flush(tab2.linkedBrowser);
|
||||
|
||||
// Move the first normal tab to end, so the first tab of win2 will be a
|
||||
// container tab.
|
||||
win2.gBrowser.moveTabTo(win2.gBrowser.tabs[0], win2.gBrowser.tabs.length - 1);
|
||||
yield TabStateFlusher.flush(win2.gBrowser.tabs[0].linkedBrowser);
|
||||
|
||||
ss.setWindowState(win2, JSON.stringify(winState), true);
|
||||
|
||||
for (let i = 0; i < 2; i++) {
|
||||
let browser = win2.gBrowser.tabs[i].linkedBrowser;
|
||||
yield ContentTask.spawn(browser, { expectedId: i }, function* (args) {
|
||||
Assert.equal(docShell.getOriginAttributes().userContextId,
|
||||
args.expectedId,
|
||||
"The docShell has the correct userContextId");
|
||||
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.userContextId,
|
||||
args.expectedId,
|
||||
"The document has the correct userContextId");
|
||||
});
|
||||
}
|
||||
|
||||
yield BrowserTestUtils.closeWindow(win);
|
||||
yield BrowserTestUtils.closeWindow(win2);
|
||||
});
|
||||
|
||||
|
|
|
@ -160,12 +160,10 @@ function makeContentReadable(obj, window) {
|
|||
return Cu.cloneInto(obj, window);
|
||||
}
|
||||
|
||||
function createNewChannel(uri, node, principal) {
|
||||
function createNewChannel(uri) {
|
||||
return NetUtil.newChannel({
|
||||
uri: uri,
|
||||
loadingNode: node,
|
||||
loadingPrincipal: principal,
|
||||
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER,
|
||||
loadUsingSystemPrincipal: true
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -266,7 +264,7 @@ ChromeActions.prototype = {
|
|||
getService(Ci.nsIExternalHelperAppService);
|
||||
|
||||
var docIsPrivate = this.isInPrivateBrowsing();
|
||||
var netChannel = createNewChannel(blobUri, this.domWindow.document, null);
|
||||
var netChannel = createNewChannel(blobUri);
|
||||
if ('nsIPrivateBrowsingChannel' in Ci &&
|
||||
netChannel instanceof Ci.nsIPrivateBrowsingChannel) {
|
||||
netChannel.setPrivate(docIsPrivate);
|
||||
|
@ -293,6 +291,7 @@ ChromeActions.prototype = {
|
|||
}
|
||||
} catch (e) {}
|
||||
channel.setURI(originalUri);
|
||||
channel.loadInfo = netChannel.loadInfo;
|
||||
channel.contentStream = aInputStream;
|
||||
if ('nsIPrivateBrowsingChannel' in Ci &&
|
||||
channel instanceof Ci.nsIPrivateBrowsingChannel) {
|
||||
|
@ -328,7 +327,7 @@ ChromeActions.prototype = {
|
|||
}
|
||||
};
|
||||
|
||||
channel.asyncOpen(listener, null);
|
||||
channel.asyncOpen2(listener);
|
||||
});
|
||||
},
|
||||
getLocale: function() {
|
||||
|
@ -973,8 +972,7 @@ PdfStreamConverter.prototype = {
|
|||
.createInstance(Ci.nsIBinaryInputStream);
|
||||
|
||||
// Create a new channel that is viewer loaded as a resource.
|
||||
var systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
var channel = createNewChannel(PDF_VIEWER_WEB_PAGE, null, systemPrincipal);
|
||||
var channel = createNewChannel(PDF_VIEWER_WEB_PAGE);
|
||||
|
||||
var listener = this.listener;
|
||||
var dataListener = this.dataListener;
|
||||
|
@ -984,10 +982,11 @@ PdfStreamConverter.prototype = {
|
|||
// trigger an assertion.
|
||||
var proxy = {
|
||||
onStartRequest: function(request, context) {
|
||||
listener.onStartRequest(aRequest, context);
|
||||
listener.onStartRequest(aRequest, aContext);
|
||||
},
|
||||
onDataAvailable: function(request, context, inputStream, offset, count) {
|
||||
listener.onDataAvailable(aRequest, context, inputStream, offset, count);
|
||||
listener.onDataAvailable(aRequest, aContext, inputStream,
|
||||
offset, count);
|
||||
},
|
||||
onStopRequest: function(request, context, statusCode) {
|
||||
// We get the DOM window here instead of before the request since it
|
||||
|
@ -1010,7 +1009,7 @@ PdfStreamConverter.prototype = {
|
|||
var findEventManager = new FindEventManager(domWindow);
|
||||
findEventManager.bind();
|
||||
}
|
||||
listener.onStopRequest(aRequest, context, statusCode);
|
||||
listener.onStopRequest(aRequest, aContext, statusCode);
|
||||
|
||||
if (domWindow.frameElement) {
|
||||
var isObjectEmbed = domWindow.frameElement.tagName !== 'IFRAME' ||
|
||||
|
@ -1036,7 +1035,7 @@ PdfStreamConverter.prototype = {
|
|||
var resourcePrincipal;
|
||||
resourcePrincipal = ssm.createCodebasePrincipal(uri, attrs);
|
||||
aRequest.owner = resourcePrincipal;
|
||||
channel.asyncOpen(proxy, aContext);
|
||||
channel.asyncOpen2(proxy);
|
||||
},
|
||||
|
||||
// nsIRequestObserver::onStopRequest
|
||||
|
|
|
@ -53,8 +53,6 @@ PluginContent.prototype = {
|
|||
global.addMessageListener("BrowserPlugins:NPAPIPluginProcessCrashed", this);
|
||||
global.addMessageListener("BrowserPlugins:CrashReportSubmitted", this);
|
||||
global.addMessageListener("BrowserPlugins:Test:ClearCrashData", this);
|
||||
|
||||
Services.obs.addObserver(this, "Plugin::HiddenPluginTouched", false);
|
||||
},
|
||||
|
||||
uninit: function() {
|
||||
|
@ -77,8 +75,6 @@ PluginContent.prototype = {
|
|||
global.removeMessageListener("BrowserPlugins:Test:ClearCrashData", this);
|
||||
delete this.global;
|
||||
delete this.content;
|
||||
|
||||
Services.obs.removeObserver(this, "Plugin::HiddenPluginTouched");
|
||||
},
|
||||
|
||||
receiveMessage: function (msg) {
|
||||
|
@ -120,15 +116,6 @@ PluginContent.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
let pluginTag = aSubject;
|
||||
if (aTopic == "Plugin::HiddenPluginTouched") {
|
||||
this._showClickToPlayNotification(pluginTag, false);
|
||||
} else {
|
||||
Cu.reportError("unknown topic observed: " + aTopic);
|
||||
}
|
||||
},
|
||||
|
||||
onPageShow: function (event) {
|
||||
// Ignore events that aren't from the main document.
|
||||
if (!this.content || event.target != this.content.document) {
|
||||
|
@ -207,45 +194,6 @@ PluginContent.prototype = {
|
|||
};
|
||||
},
|
||||
|
||||
_getPluginInfoForTag: function (pluginTag, tagMimetype, fallbackType) {
|
||||
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||
|
||||
let pluginName = gNavigatorBundle.GetStringFromName("pluginInfo.unknownPlugin");
|
||||
let permissionString = null;
|
||||
let blocklistState = null;
|
||||
|
||||
if (pluginTag) {
|
||||
pluginName = BrowserUtils.makeNicePluginName(pluginTag.name);
|
||||
|
||||
permissionString = pluginHost.getPermissionStringForTag(pluginTag);
|
||||
blocklistState = pluginTag.blocklistState;
|
||||
|
||||
// Convert this from nsIPluginTag so it can be serialized.
|
||||
let properties = ["name", "description", "filename", "version", "enabledState", "niceName"];
|
||||
let pluginTagCopy = {};
|
||||
for (let prop of properties) {
|
||||
pluginTagCopy[prop] = pluginTag[prop];
|
||||
}
|
||||
pluginTag = pluginTagCopy;
|
||||
|
||||
// Make state-softblocked == state-notblocked for our purposes,
|
||||
// they have the same UI. STATE_OUTDATED should not exist for plugin
|
||||
// items, but let's alias it anyway, just in case.
|
||||
if (blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED ||
|
||||
blocklistState == Ci.nsIBlocklistService.STATE_OUTDATED) {
|
||||
blocklistState = Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
return { mimetype: tagMimetype,
|
||||
pluginName: pluginName,
|
||||
pluginTag: pluginTag,
|
||||
permissionString: permissionString,
|
||||
fallbackType: fallbackType,
|
||||
blocklistState: blocklistState,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the visibility of the plugin overlay.
|
||||
*/
|
||||
|
|
|
@ -1960,3 +1960,7 @@ notification.pluginVulnerable > .notification-inner > .messageCloseButton:not(:h
|
|||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.menuitem-iconic[command="Browser:NewUserContextTab"] > .menu-iconic-left > .menu-iconic-icon {
|
||||
visibility: visible;
|
||||
}
|
||||
|
|
|
@ -186,6 +186,42 @@ public:
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Overlaps(const OriginAttributesPattern& aOther) const
|
||||
{
|
||||
if (mAppId.WasPassed() && aOther.mAppId.WasPassed() &&
|
||||
mAppId.Value() != aOther.mAppId.Value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mInIsolatedMozBrowser.WasPassed() &&
|
||||
aOther.mInIsolatedMozBrowser.WasPassed() &&
|
||||
mInIsolatedMozBrowser.Value() != aOther.mInIsolatedMozBrowser.Value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mAddonId.WasPassed() && aOther.mAddonId.WasPassed() &&
|
||||
mAddonId.Value() != aOther.mAddonId.Value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mUserContextId.WasPassed() && aOther.mUserContextId.WasPassed() &&
|
||||
mUserContextId.Value() != aOther.mUserContextId.Value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSignedPkg.WasPassed() && aOther.mSignedPkg.WasPassed() &&
|
||||
mSignedPkg.Value() != aOther.mSignedPkg.Value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mPrivateBrowsingId.WasPassed() && aOther.mPrivateBrowsingId.WasPassed() &&
|
||||
mPrivateBrowsingId.Value() != aOther.mPrivateBrowsingId.Value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -169,8 +169,7 @@ devtools.jar:
|
|||
skin/images/filetypes/dir-open.svg (themes/images/filetypes/dir-open.svg)
|
||||
skin/images/filetypes/globe.svg (themes/images/filetypes/globe.svg)
|
||||
skin/images/filetypes/store.svg (themes/images/filetypes/store.svg)
|
||||
skin/images/commandline-icon.png (themes/images/commandline-icon.png)
|
||||
skin/images/commandline-icon@2x.png (themes/images/commandline-icon@2x.png)
|
||||
skin/images/commandline-icon.svg (themes/images/commandline-icon.svg)
|
||||
skin/images/alerticon-warning.png (themes/images/alerticon-warning.png)
|
||||
skin/images/alerticon-warning@2x.png (themes/images/alerticon-warning@2x.png)
|
||||
skin/rules.css (themes/rules.css)
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
--gcli-border-color: #dde1e4; /* --theme-splitter-color */
|
||||
--selection-background: #4c9ed9; /* --theme-selection-background */
|
||||
--selection-color: #f5f7fa; /* --theme-selection-color */
|
||||
--command-line-image: url(chrome://devtools/skin/images/commandline-icon.svg#light-theme); /* --theme-command-line-image */
|
||||
--command-line-image-focus: url(chrome://devtools/skin/images/commandline-icon.svg#light-theme-focus); /* --theme-command-line-image-focus */
|
||||
}
|
||||
|
||||
:root[devtoolstheme="dark"] #developer-toolbar {
|
||||
|
@ -27,6 +29,8 @@
|
|||
--gcli-border-color: #454d5d; /* --theme-splitter-color */
|
||||
--selection-background: #5675b9; /* --theme-selection-background */
|
||||
--selection-color: #f5f7fa; /* --theme-selection-color */
|
||||
--command-line-image: url(chrome://devtools/skin/images/commandline-icon.svg#dark-theme); /* --theme-command-line-image */
|
||||
--command-line-image-focus: url(chrome://devtools/skin/images/commandline-icon.svg#dark-theme-focus); /* --theme-command-line-image-focus */
|
||||
}
|
||||
|
||||
#developer-toolbar {
|
||||
|
@ -160,19 +164,11 @@ html|*#gcli-output-frame {
|
|||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 2px;
|
||||
background-image: url("chrome://devtools/skin/images/commandline-icon.png");
|
||||
background-position: 0 center;
|
||||
background-size: 32px 16px;
|
||||
background-image: var(--command-line-image);
|
||||
}
|
||||
|
||||
.gclitoolbar-input-node[focused="true"]::before {
|
||||
background-position: -16px center;
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
.gclitoolbar-input-node::before {
|
||||
background-image: url("chrome://devtools/skin/images/commandline-icon@2x.png");
|
||||
}
|
||||
background-image: var(--command-line-image-focus);
|
||||
}
|
||||
|
||||
.gclitoolbar-input-node > .textbox-input-box > html|*.textbox-input::-moz-selection {
|
||||
|
|
|
@ -350,21 +350,12 @@
|
|||
}
|
||||
|
||||
.dbg-expression-arrow {
|
||||
background-image: url(images/commandline-icon.png);
|
||||
background-position: -16px 0;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 32px 16px;
|
||||
background-image: var(--theme-command-line-image-focus);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
.dbg-expression-arrow {
|
||||
background-image: url(images/commandline-icon@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.dbg-expression-input {
|
||||
color: inherit;
|
||||
}
|
||||
|
|
Двоичные данные
devtools/client/themes/images/commandline-icon.png
Двоичные данные
devtools/client/themes/images/commandline-icon.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 254 B |
|
@ -0,0 +1,42 @@
|
|||
<!-- 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/. -->
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<style>
|
||||
g {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#light-theme:target,
|
||||
#light-theme-focus:target ~ #light-theme,
|
||||
#dark-theme:target,
|
||||
#dark-theme-focus:target ~ #dark-theme {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#light-theme-focus:target ~ #light-theme {
|
||||
fill: #4A90E2;
|
||||
}
|
||||
#dark-theme-focus:target ~ #dark-theme {
|
||||
fill: #00FF7F;
|
||||
}
|
||||
|
||||
/* Unfocused states */
|
||||
#light-theme,
|
||||
#dark-theme {
|
||||
fill: rgba(128, 128, 128, .5);
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g id="light-theme-focus"/>
|
||||
<g id="light-theme">
|
||||
<path d="M7.29 13.907l7-5a.5.5 0 0 0 .033-.789l-6.5-5.5a.5.5 0 1 0-.646.764l6.5 5.5.032-.789-7 5a.5.5 0 1 0 .582.814z"/>
|
||||
<path d="M2.29 13.907l7-5a.5.5 0 0 0 .033-.789l-6.5-5.5a.5.5 0 1 0-.646.764l6.5 5.5.032-.789-7 5a.5.5 0 1 0 .582.814z"/>
|
||||
</g>
|
||||
<g id="dark-theme-focus"/>
|
||||
<g id="dark-theme">
|
||||
<path d="M7.29 13.907l7-5a.5.5 0 0 0 .033-.789l-6.5-5.5a.5.5 0 1 0-.646.764l6.5 5.5.032-.789-7 5a.5.5 0 1 0 .582.814z"/>
|
||||
<path d="M2.29 13.907l7-5a.5.5 0 0 0 .033-.789l-6.5-5.5a.5.5 0 1 0-.646.764l6.5 5.5.032-.789-7 5a.5.5 0 1 0 .582.814z"/>
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 1.4 KiB |
Двоичные данные
devtools/client/themes/images/commandline-icon@2x.png
Двоичные данные
devtools/client/themes/images/commandline-icon@2x.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 586 B |
|
@ -3,6 +3,14 @@
|
|||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14">
|
||||
<defs>
|
||||
<style>
|
||||
path {
|
||||
opacity: 0.5;
|
||||
}
|
||||
path:target {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
<linearGradient id="b">
|
||||
<stop offset="0" stop-color="#234ccd"/>
|
||||
<stop offset="1" stop-color="#5d7de3"/>
|
||||
|
@ -14,5 +22,5 @@
|
|||
<linearGradient x1="2.002" y1="12.252" x2="-.099" y2="6.755" id="d" xlink:href="#a" gradientUnits="userSpaceOnUse" gradientTransform="translate(5.841 1034.646)"/>
|
||||
<linearGradient x1="3.309" y1="11.177" x2="1.468" y2="6.456" id="c" xlink:href="#b" gradientUnits="userSpaceOnUse" gradientTransform="translate(5.841 1034.646)"/>
|
||||
</defs>
|
||||
<path d="M6.841 1040.052l-.437.406 2.469 3.688-2.47 3.687.438.407 3.438-4.094z" fill="url(#c)" stroke="url(#d)" stroke-width=".4" stroke-linecap="round" stroke-linejoin="round" transform="translate(-1.341 -1037.146)"/>
|
||||
<path id="focus" d="M6.841 1040.052l-.437.406 2.469 3.688-2.47 3.687.438.407 3.438-4.094z" fill="url(#c)" stroke="url(#d)" stroke-width=".4" stroke-linecap="round" stroke-linejoin="round" transform="translate(-1.341 -1037.146)"/>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 1.2 KiB После Ширина: | Высота: | Размер: 1.3 KiB |
|
@ -68,6 +68,10 @@
|
|||
--theme-tooltip-border: #d9e1e8;
|
||||
--theme-tooltip-background: rgba(255, 255, 255, .9);
|
||||
--theme-tooltip-shadow: rgba(155, 155, 155, 0.26);
|
||||
|
||||
/* Command line */
|
||||
--theme-command-line-image: url(chrome://devtools/skin/images/commandline-icon.svg#light-theme);
|
||||
--theme-command-line-image-focus: url(chrome://devtools/skin/images/commandline-icon.svg#light-theme-focus);
|
||||
}
|
||||
|
||||
:root.theme-dark {
|
||||
|
@ -124,6 +128,10 @@
|
|||
--theme-tooltip-border: #434850;
|
||||
--theme-tooltip-background: rgba(19, 28, 38, .9);
|
||||
--theme-tooltip-shadow: rgba(25, 25, 25, 0.76);
|
||||
|
||||
/* Command line */
|
||||
--theme-command-line-image: url(chrome://devtools/skin/images/commandline-icon.svg#dark-theme);
|
||||
--theme-command-line-image-focus: url(chrome://devtools/skin/images/commandline-icon.svg#dark-theme-focus);
|
||||
}
|
||||
|
||||
:root.theme-firebug {
|
||||
|
@ -178,6 +186,10 @@
|
|||
--theme-header-background: #F0F0F0 linear-gradient(to top,
|
||||
rgba(0, 0, 0, 0.1),
|
||||
transparent) repeat-x;
|
||||
|
||||
/* Command line */
|
||||
--theme-command-line-image: url(chrome://devtools/skin/images/firebug/commandline-icon.svg);
|
||||
--theme-command-line-image-focus: url(chrome://devtools/skin/images/firebug/commandline-icon.svg#focus);
|
||||
}
|
||||
|
||||
:root {
|
||||
|
@ -188,6 +200,4 @@
|
|||
* should improve keyboard navigation usability. */
|
||||
--theme-focus-outline: 1px dotted var(--theme-focus-outline-color);
|
||||
--theme-focus-box-shadow-textbox: 0 0 0 1px var(--theme-textbox-box-shadow);
|
||||
--theme-focus-box-shadow-inset-bottom: 0 -2px 1px var(--theme-textbox-box-shadow) inset,
|
||||
0px -2px var(--theme-highlight-blue) inset;
|
||||
}
|
||||
|
|
|
@ -3,21 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* Webconsole specific theme variables */
|
||||
|
||||
.theme-dark {
|
||||
--command-line-image: -moz-image-rect(url("chrome://devtools/skin/images/commandline-icon.png"), 0, 32, 16, 16);
|
||||
--command-line-image-2x: -moz-image-rect(url('chrome://devtools/skin/images/commandline-icon@2x.png'), 0, 64, 32, 32);
|
||||
}
|
||||
|
||||
.theme-light {
|
||||
--command-line-image: -moz-image-rect(url("chrome://devtools/skin/images/commandline-icon.png"), 0, 32, 16, 16);
|
||||
--command-line-image-2x: -moz-image-rect(url('chrome://devtools/skin/images/commandline-icon@2x.png'), 0, 64, 32, 32);
|
||||
}
|
||||
|
||||
.theme-firebug {
|
||||
--command-line-image: url(chrome://devtools/skin/images/firebug/commandline-icon.svg);
|
||||
--command-line-image-2x: url(chrome://devtools/skin/images/firebug/commandline-icon.svg);
|
||||
|
||||
--error-color: #FF0000;
|
||||
--error-background-color: #FFEBEB;
|
||||
--warning-background-color: #FFFFC8;
|
||||
|
@ -414,9 +400,7 @@ a {
|
|||
}
|
||||
|
||||
.jsterm-input-node[focused="true"] {
|
||||
outline: var(--theme-focus-outline);
|
||||
outline-offset: -1px;
|
||||
transition: none;
|
||||
background-image: var(--theme-command-line-image-focus);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
@ -428,19 +412,13 @@ a {
|
|||
/* Always allow scrolling on input - it auto expands in js by setting height,
|
||||
but don't want it to get bigger than the window. 24px = toolbar height. */
|
||||
max-height: calc(90vh - 24px);
|
||||
background-image: var(--command-line-image);
|
||||
background-image: var(--theme-command-line-image);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 16px 16px;
|
||||
background-position: 4px 50%;
|
||||
color: var(--theme-content-color1);
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
.jsterm-input-node {
|
||||
background-image: var(--command-line-image-2x);
|
||||
}
|
||||
}
|
||||
|
||||
:-moz-any(.jsterm-input-node,
|
||||
.jsterm-complete-node) > .textbox-input-box > .textbox-textarea {
|
||||
overflow-x: hidden;
|
||||
|
|
|
@ -141,6 +141,7 @@ support-files =
|
|||
test_bug1092055_shouldwarn.js^headers^
|
||||
test_bug1092055_shouldwarn.js
|
||||
test_bug1092055_shouldwarn.html
|
||||
test_bug_1247459_violation.html
|
||||
!/devtools/client/framework/test/shared-head.js
|
||||
!/devtools/client/netmonitor/test/sjs_cors-test-server.sjs
|
||||
!/image/test/mochitest/blue.png
|
||||
|
@ -295,6 +296,8 @@ skip-if = os != "mac"
|
|||
skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug intermittent)
|
||||
[browser_webconsole_bug_1010953_cspro.js]
|
||||
skip-if = e10s && (os == 'win' || os == 'mac') # Bug 1243967
|
||||
[browser_webconsole_bug_1247459_violation.js]
|
||||
skip-if = e10s && (os == 'win') # Bug 1264955
|
||||
[browser_webconsole_certificate_messages.js]
|
||||
skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
|
||||
[browser_webconsole_show_subresource_security_errors.js]
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that the Web Console CSP messages for two META policies
|
||||
// are correctly displayed.
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf8,Web Console CSP violation test";
|
||||
const TEST_VIOLATION = "https://example.com/browser/devtools/client/" +
|
||||
"webconsole/test/test_bug_1247459_violation.html";
|
||||
const CSP_VIOLATION_MSG = "Content Security Policy: The page\u2019s settings " +
|
||||
"blocked the loading of a resource at " +
|
||||
"http://some.example.com/test.png (\u201cimg-src " +
|
||||
"https://example.com\u201d).";
|
||||
|
||||
add_task(function* () {
|
||||
let { browser } = yield loadTab(TEST_URI);
|
||||
|
||||
let hud = yield openConsole();
|
||||
|
||||
hud.jsterm.clearOutput();
|
||||
|
||||
let loaded = loadBrowser(browser);
|
||||
BrowserTestUtils.loadURI(browser, TEST_VIOLATION);
|
||||
yield loaded;
|
||||
|
||||
yield waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [
|
||||
{
|
||||
name: "CSP policy URI warning displayed successfully",
|
||||
text: CSP_VIOLATION_MSG,
|
||||
repeats: 2
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Security-Policy" content="img-src https://example.com"></meta>
|
||||
<meta http-equiv="Content-Security-Policy" content="img-src https://example.com"></meta>
|
||||
<meta charset="UTF-8">
|
||||
<title>Test for Bug 1247459 - policy violations for header and META are displayed separately</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1247459">Mozilla Bug 1247459</a>
|
||||
<img src="http://some.example.com/test.png">
|
||||
</body>
|
||||
</html>
|
|
@ -9,15 +9,51 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const baseURL = "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/";
|
||||
|
||||
const ErrorDocs = {
|
||||
JSMSG_READ_ONLY: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Read-only",
|
||||
JSMSG_BAD_ARRAY_LENGTH: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Invalid_array_length",
|
||||
JSMSG_NEGATIVE_REPETITION_COUNT: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Negative_repetition_count",
|
||||
JSMSG_RESULTING_STRING_TOO_LARGE: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Resulting_string_too_large",
|
||||
JSMSG_BAD_RADIX: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Bad_radix",
|
||||
JSMSG_PRECISION_RANGE: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Precision_range",
|
||||
JSMSG_BAD_FORMAL: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Malformed_formal_parameter",
|
||||
JSMSG_STMT_AFTER_RETURN: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Stmt_after_return",
|
||||
JSMSG_READ_ONLY: "Read-only",
|
||||
JSMSG_BAD_ARRAY_LENGTH: "Invalid_array_length",
|
||||
JSMSG_NEGATIVE_REPETITION_COUNT: "Negative_repetition_count",
|
||||
JSMSG_RESULTING_STRING_TOO_LARGE: "Resulting_string_too_large",
|
||||
JSMSG_BAD_RADIX: "Bad_radix",
|
||||
JSMSG_PRECISION_RANGE: "Precision_range",
|
||||
JSMSG_BAD_FORMAL: "Malformed_formal_parameter",
|
||||
JSMSG_STMT_AFTER_RETURN: "Stmt_after_return",
|
||||
JSMSG_NOT_A_CODEPOINT: "Not_a_codepoint",
|
||||
JSMSG_BAD_SORT_ARG: "Array_sort_argument",
|
||||
JSMSG_UNEXPECTED_TYPE: "Unexpected_type",
|
||||
JSMSG_NOT_DEFINED: "Not_defined",
|
||||
JSMSG_NOT_FUNCTION: "Not_a_function",
|
||||
JSMSG_EQUAL_AS_ASSIGN: "Equal_as_assign",
|
||||
JSMSG_UNDEFINED_PROP: "Undefined_prop",
|
||||
JSMSG_DEPRECATED_PRAGMA: "Deprecated_source_map_pragma",
|
||||
JSMSG_DEPRECATED_USAGE: "Deprecated_caller_or_arguments_usage",
|
||||
JSMSG_CANT_DELETE: "Cant_delete",
|
||||
JSMSG_VAR_HIDES_ARG: "Var_hides_argument",
|
||||
JSMSG_JSON_BAD_PARSE: "JSON_bad_parse",
|
||||
JSMSG_UNDECLARED_VAR: "Undeclared_var",
|
||||
JSMSG_UNEXPECTED_TOKEN: "Unexpected_token",
|
||||
JSMSG_BAD_OCTAL: "Bad_octal",
|
||||
JSMSG_PROPERTY_ACCESS_DENIED: "Property_access_denied",
|
||||
JSMSG_NO_PROPERTIES: "No_properties",
|
||||
JSMSG_ALREADY_HAS_PRAGMA: "Already_has_pragma",
|
||||
JSMSG_BAD_RETURN_OR_YIELD: "Bad_return_or_yield",
|
||||
JSMSG_SEMI_BEFORE_STMNT: "Missing_semicolon_before_statement",
|
||||
JSMSG_OVER_RECURSED: "Too_much_recursion",
|
||||
JSMSG_BRACKET_AFTER_LIST: "Missing_bracket_after_list",
|
||||
JSMSG_PAREN_AFTER_ARGS: "Missing_parenthesis_after_argument_list",
|
||||
JSMSG_MORE_ARGS_NEEDED: "More_arguments_needed",
|
||||
JSMSG_BAD_LEFTSIDE_OF_ASS: "Invalid_assignment_left-hand_side",
|
||||
JSMSG_UNTERMINATED_STRING: "Unterminated_string_literal",
|
||||
JSMSG_NOT_CONSTRUCTOR: "Not_a_constructor",
|
||||
JSMSG_CURLY_AFTER_LIST: "Missing_curly_after_property_list",
|
||||
};
|
||||
|
||||
exports.GetURL = (errorName) => ErrorDocs[errorName];
|
||||
exports.GetURL = (errorName) => {
|
||||
let doc = ErrorDocs[errorName];
|
||||
if (doc) {
|
||||
return baseURL + doc;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -325,7 +325,7 @@ WebConsoleActor.prototype =
|
|||
// We are very explicitly examining the "console" property of
|
||||
// the non-Xrayed object here.
|
||||
let console = aWindow.wrappedJSObject.console;
|
||||
isNative = console instanceof aWindow.Console;
|
||||
isNative = new XPCNativeWrapper(console).IS_NATIVE_CONSOLE
|
||||
}
|
||||
catch (ex) { }
|
||||
return isNative;
|
||||
|
|
|
@ -589,6 +589,7 @@ private:
|
|||
|
||||
// State initialized during eInitial:
|
||||
quota::PersistenceType mPersistence;
|
||||
nsCString mSuffix;
|
||||
nsCString mGroup;
|
||||
nsCString mOrigin;
|
||||
RefPtr<DirectoryLock> mDirectoryLock;
|
||||
|
@ -685,8 +686,8 @@ ParentRunnable::InitOnMainThread()
|
|||
return rv;
|
||||
}
|
||||
|
||||
rv = QuotaManager::GetInfoFromPrincipal(principal, &mGroup, &mOrigin,
|
||||
&mIsApp);
|
||||
rv = QuotaManager::GetInfoFromPrincipal(principal, &mSuffix, &mGroup,
|
||||
&mOrigin, &mIsApp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
InitPersistenceType();
|
||||
|
@ -727,8 +728,8 @@ ParentRunnable::ReadMetadata()
|
|||
MOZ_ASSERT(qm, "We are on the QuotaManager's IO thread");
|
||||
|
||||
nsresult rv =
|
||||
qm->EnsureOriginIsInitialized(mPersistence, mGroup, mOrigin, mIsApp,
|
||||
getter_AddRefs(mDirectory));
|
||||
qm->EnsureOriginIsInitialized(mPersistence, mSuffix, mGroup, mOrigin,
|
||||
mIsApp, getter_AddRefs(mDirectory));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mResult = JS::AsmJSCache_StorageInitFailure;
|
||||
return rv;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "ScriptSettings.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
#include "WorkerScope.h"
|
||||
#include "xpcprivate.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDocShell.h"
|
||||
|
@ -832,7 +833,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
mConsole->ProfileMethod(aCx, mAction, arguments);
|
||||
mConsole->ProfileMethodInternal(aCx, mAction, arguments);
|
||||
}
|
||||
|
||||
virtual void
|
||||
|
@ -857,7 +858,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Console)
|
|||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsoleEventNotifier)
|
||||
tmp->Shutdown();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Console)
|
||||
|
@ -875,14 +875,12 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Console)
|
|||
tmp->mCallDataStoragePending[i]->Trace(aCallbacks, aClosure);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(Console)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(Console)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Console)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
|
@ -1027,17 +1025,11 @@ Console::ClearStorage()
|
|||
mCallDataStorage.Clear();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
Console::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return ConsoleBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
#define METHOD(name, string) \
|
||||
void \
|
||||
Console::name(JSContext* aCx, const Sequence<JS::Value>& aData) \
|
||||
/* static */ void \
|
||||
Console::name(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData) \
|
||||
{ \
|
||||
Method(aCx, Method##name, NS_LITERAL_STRING(string), aData); \
|
||||
Method(aGlobal, Method##name, NS_LITERAL_STRING(string), aData); \
|
||||
}
|
||||
|
||||
METHOD(Log, "log")
|
||||
|
@ -1049,13 +1041,11 @@ METHOD(Debug, "debug")
|
|||
METHOD(Table, "table")
|
||||
METHOD(Clear, "clear")
|
||||
|
||||
void
|
||||
Console::Trace(JSContext* aCx)
|
||||
/* static */ void
|
||||
Console::Trace(const GlobalObject& aGlobal)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
const Sequence<JS::Value> data;
|
||||
Method(aCx, MethodTrace, NS_LITERAL_STRING("trace"), data);
|
||||
Method(aGlobal, MethodTrace, NS_LITERAL_STRING("trace"), data);
|
||||
}
|
||||
|
||||
// Displays an interactive listing of all the properties of an object.
|
||||
|
@ -1066,79 +1056,87 @@ METHOD(Group, "group")
|
|||
METHOD(GroupCollapsed, "groupCollapsed")
|
||||
METHOD(GroupEnd, "groupEnd")
|
||||
|
||||
void
|
||||
Console::Time(JSContext* aCx, const JS::Handle<JS::Value> aTime)
|
||||
/* static */ void
|
||||
Console::Time(const GlobalObject& aGlobal, const JS::Handle<JS::Value> aTime)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
JSContext* cx = aGlobal.Context();
|
||||
|
||||
Sequence<JS::Value> data;
|
||||
SequenceRooter<JS::Value> rooter(aCx, &data);
|
||||
SequenceRooter<JS::Value> rooter(cx, &data);
|
||||
|
||||
if (!aTime.isUndefined() && !data.AppendElement(aTime, fallible)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Method(aCx, MethodTime, NS_LITERAL_STRING("time"), data);
|
||||
Method(aGlobal, MethodTime, NS_LITERAL_STRING("time"), data);
|
||||
}
|
||||
|
||||
void
|
||||
Console::TimeEnd(JSContext* aCx, const JS::Handle<JS::Value> aTime)
|
||||
/* static */ void
|
||||
Console::TimeEnd(const GlobalObject& aGlobal, const JS::Handle<JS::Value> aTime)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
JSContext* cx = aGlobal.Context();
|
||||
|
||||
Sequence<JS::Value> data;
|
||||
SequenceRooter<JS::Value> rooter(aCx, &data);
|
||||
SequenceRooter<JS::Value> rooter(cx, &data);
|
||||
|
||||
if (!aTime.isUndefined() && !data.AppendElement(aTime, fallible)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Method(aCx, MethodTimeEnd, NS_LITERAL_STRING("timeEnd"), data);
|
||||
Method(aGlobal, MethodTimeEnd, NS_LITERAL_STRING("timeEnd"), data);
|
||||
}
|
||||
|
||||
void
|
||||
Console::TimeStamp(JSContext* aCx, const JS::Handle<JS::Value> aData)
|
||||
/* static */ void
|
||||
Console::TimeStamp(const GlobalObject& aGlobal,
|
||||
const JS::Handle<JS::Value> aData)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
JSContext* cx = aGlobal.Context();
|
||||
|
||||
Sequence<JS::Value> data;
|
||||
SequenceRooter<JS::Value> rooter(aCx, &data);
|
||||
SequenceRooter<JS::Value> rooter(cx, &data);
|
||||
|
||||
if (aData.isString() && !data.AppendElement(aData, fallible)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Method(aCx, MethodTimeStamp, NS_LITERAL_STRING("timeStamp"), data);
|
||||
Method(aGlobal, MethodTimeStamp, NS_LITERAL_STRING("timeStamp"), data);
|
||||
}
|
||||
|
||||
void
|
||||
Console::Profile(JSContext* aCx, const Sequence<JS::Value>& aData)
|
||||
/* static */ void
|
||||
Console::Profile(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
ProfileMethod(aCx, NS_LITERAL_STRING("profile"), aData);
|
||||
ProfileMethod(aGlobal, NS_LITERAL_STRING("profile"), aData);
|
||||
}
|
||||
|
||||
void
|
||||
Console::ProfileEnd(JSContext* aCx, const Sequence<JS::Value>& aData)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
ProfileMethod(aCx, NS_LITERAL_STRING("profileEnd"), aData);
|
||||
}
|
||||
|
||||
void
|
||||
Console::ProfileMethod(JSContext* aCx, const nsAString& aAction,
|
||||
/* static */ void
|
||||
Console::ProfileEnd(const GlobalObject& aGlobal,
|
||||
const Sequence<JS::Value>& aData)
|
||||
{
|
||||
if (IsShuttingDown()) {
|
||||
ProfileMethod(aGlobal, NS_LITERAL_STRING("profileEnd"), aData);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
Console::ProfileMethod(const GlobalObject& aGlobal, const nsAString& aAction,
|
||||
const Sequence<JS::Value>& aData)
|
||||
{
|
||||
RefPtr<Console> console = GetConsole(aGlobal);
|
||||
if (!console) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = aGlobal.Context();
|
||||
console->ProfileMethodInternal(cx, aAction, aData);
|
||||
}
|
||||
|
||||
void
|
||||
Console::ProfileMethodInternal(JSContext* aCx, const nsAString& aAction,
|
||||
const Sequence<JS::Value>& aData)
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
// Here we are in a worker thread.
|
||||
RefPtr<ConsoleProfileRunnable> runnable =
|
||||
new ConsoleProfileRunnable(this, aAction, aData);
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
runnable->Dispatch(aCx);
|
||||
return;
|
||||
}
|
||||
|
@ -1184,28 +1182,25 @@ Console::ProfileMethod(JSContext* aCx, const nsAString& aAction,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Console::Assert(JSContext* aCx, bool aCondition,
|
||||
/* static */ void
|
||||
Console::Assert(const GlobalObject& aGlobal, bool aCondition,
|
||||
const Sequence<JS::Value>& aData)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (!aCondition) {
|
||||
Method(aCx, MethodAssert, NS_LITERAL_STRING("assert"), aData);
|
||||
Method(aGlobal, MethodAssert, NS_LITERAL_STRING("assert"), aData);
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(Count, "count")
|
||||
|
||||
void
|
||||
Console::NoopMethod()
|
||||
/* static */ void
|
||||
Console::NoopMethod(const GlobalObject& aGlobal)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
static
|
||||
namespace {
|
||||
|
||||
nsresult
|
||||
StackFrameToStackEntry(JSContext* aCx, nsIStackFrame* aStackFrame,
|
||||
ConsoleStackEntry& aStackEntry)
|
||||
|
@ -1241,7 +1236,6 @@ StackFrameToStackEntry(JSContext* aCx, nsIStackFrame* aStackFrame,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static
|
||||
nsresult
|
||||
ReifyStack(JSContext* aCx, nsIStackFrame* aStack,
|
||||
nsTArray<ConsoleStackEntry>& aRefiedStack)
|
||||
|
@ -1267,16 +1261,29 @@ ReifyStack(JSContext* aCx, nsIStackFrame* aStack,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// Queue a call to a console method. See the CALL_DELAY constant.
|
||||
/* static */ void
|
||||
Console::Method(const GlobalObject& aGlobal, MethodName aMethodName,
|
||||
const nsAString& aMethodString,
|
||||
const Sequence<JS::Value>& aData)
|
||||
{
|
||||
RefPtr<Console> console = GetConsole(aGlobal);
|
||||
if (!console) {
|
||||
return;
|
||||
}
|
||||
|
||||
console->MethodInternal(aGlobal.Context(), aMethodName, aMethodString,
|
||||
aData);
|
||||
}
|
||||
|
||||
void
|
||||
Console::Method(JSContext* aCx, MethodName aMethodName,
|
||||
Console::MethodInternal(JSContext* aCx, MethodName aMethodName,
|
||||
const nsAString& aMethodString,
|
||||
const Sequence<JS::Value>& aData)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
if (IsShuttingDown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<ConsoleCallData> callData(new ConsoleCallData());
|
||||
|
||||
|
@ -2416,5 +2423,71 @@ Console::IsShuttingDown() const
|
|||
return mStatus == eShuttingDown;
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Console>
|
||||
Console::GetConsole(const GlobalObject& aGlobal)
|
||||
{
|
||||
RefPtr<Console> console;
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsPIDOMWindowInner> innerWindow =
|
||||
do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (NS_WARN_IF(!innerWindow)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsGlobalWindow* window = nsGlobalWindow::Cast(innerWindow);
|
||||
|
||||
ErrorResult rv;
|
||||
console = window->GetConsole(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
JSContext* cx = aGlobal.Context();
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global =
|
||||
do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (NS_WARN_IF(!global)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WorkerGlobalScope* scope = workerPrivate->GlobalScope();
|
||||
MOZ_ASSERT(scope);
|
||||
|
||||
// Normal worker scope.
|
||||
ErrorResult rv;
|
||||
if (scope == global) {
|
||||
console = scope->GetConsole(rv);
|
||||
}
|
||||
|
||||
// Debugger worker scope
|
||||
else {
|
||||
WorkerDebuggerGlobalScope* debuggerScope =
|
||||
workerPrivate->DebuggerGlobalScope();
|
||||
MOZ_ASSERT(debuggerScope);
|
||||
MOZ_ASSERT(debuggerScope == global, "Which kind of global do we have?");
|
||||
|
||||
console = debuggerScope->GetConsole(rv);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(console);
|
||||
console->AssertIsOnOwningThread();
|
||||
|
||||
if (console->IsShuttingDown()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return console.forget();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "nsHashKeys.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsDOMNavigationTiming.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
|
@ -33,7 +32,6 @@ class ConsoleProfileRunnable;
|
|||
struct ConsoleStackEntry;
|
||||
|
||||
class Console final : public nsIObserver
|
||||
, public nsWrapperCache
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
|
@ -50,74 +48,72 @@ public:
|
|||
return mWindow;
|
||||
}
|
||||
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
static void
|
||||
Log(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Log(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
Info(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Info(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
Warn(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Warn(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
Error(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Error(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
Exception(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Exception(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
Debug(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Debug(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
Table(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Table(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
Trace(const GlobalObject& aGlobal);
|
||||
|
||||
void
|
||||
Trace(JSContext* aCx);
|
||||
static void
|
||||
Dir(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Dir(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
Dirxml(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Dirxml(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
Group(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Group(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
GroupCollapsed(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
GroupCollapsed(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
GroupEnd(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
GroupEnd(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
Time(const GlobalObject& aGlobal, const JS::Handle<JS::Value> aTime);
|
||||
|
||||
void
|
||||
Time(JSContext* aCx, const JS::Handle<JS::Value> aTime);
|
||||
static void
|
||||
TimeEnd(const GlobalObject& aGlobal, const JS::Handle<JS::Value> aTime);
|
||||
|
||||
void
|
||||
TimeEnd(JSContext* aCx, const JS::Handle<JS::Value> aTime);
|
||||
static void
|
||||
TimeStamp(const GlobalObject& aGlobal, const JS::Handle<JS::Value> aData);
|
||||
|
||||
void
|
||||
TimeStamp(JSContext* aCx, const JS::Handle<JS::Value> aData);
|
||||
static void
|
||||
Profile(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Profile(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
ProfileEnd(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
ProfileEnd(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
Assert(const GlobalObject& aGlobal, bool aCondition,
|
||||
const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Assert(JSContext* aCx, bool aCondition, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
Count(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Count(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
static void
|
||||
Clear(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Clear(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
NoopMethod();
|
||||
static void
|
||||
NoopMethod(const GlobalObject& aGlobal);
|
||||
|
||||
void
|
||||
ClearStorage();
|
||||
|
@ -162,10 +158,25 @@ private:
|
|||
MethodClear
|
||||
};
|
||||
|
||||
void
|
||||
Method(JSContext* aCx, MethodName aName, const nsAString& aString,
|
||||
static already_AddRefed<Console>
|
||||
GetConsole(const GlobalObject& aGlobal);
|
||||
|
||||
static void
|
||||
ProfileMethod(const GlobalObject& aGlobal, const nsAString& aAction,
|
||||
const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
ProfileMethodInternal(JSContext* aCx, const nsAString& aAction,
|
||||
const Sequence<JS::Value>& aData);
|
||||
|
||||
static void
|
||||
Method(const GlobalObject& aGlobal, MethodName aName,
|
||||
const nsAString& aString, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
MethodInternal(JSContext* aCx, MethodName aName,
|
||||
const nsAString& aString, const Sequence<JS::Value>& aData);
|
||||
|
||||
// This method must receive aCx and aArguments in the same JSCompartment.
|
||||
void
|
||||
ProcessCallData(JSContext* aCx,
|
||||
|
@ -305,10 +316,6 @@ private:
|
|||
ArgumentsToValueList(const Sequence<JS::Value>& aData,
|
||||
Sequence<JS::Value>& aSequence) const;
|
||||
|
||||
void
|
||||
ProfileMethod(JSContext* aCx, const nsAString& aAction,
|
||||
const Sequence<JS::Value>& aData);
|
||||
|
||||
// This method follows the same pattern as StartTimer: its runs on the owning
|
||||
// thread and populate aCountLabel, used by CreateCounterValue. Returns
|
||||
// MAX_PAGE_COUNTERS in case of error, otherwise the incremented counter
|
||||
|
|
|
@ -200,6 +200,7 @@ Navigator::Init()
|
|||
|
||||
Navigator::Navigator(nsPIDOMWindowInner* aWindow)
|
||||
: mWindow(aWindow)
|
||||
, mBatteryTelemetryReported(false)
|
||||
{
|
||||
MOZ_ASSERT(aWindow->IsInnerWindow(), "Navigator must get an inner window!");
|
||||
}
|
||||
|
@ -303,6 +304,7 @@ Navigator::Invalidate()
|
|||
}
|
||||
|
||||
mBatteryPromise = nullptr;
|
||||
mBatteryTelemetryReported = false;
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
if (mFMRadio) {
|
||||
|
@ -1589,6 +1591,10 @@ Navigator::GetBattery(ErrorResult& aRv)
|
|||
}
|
||||
mBatteryPromise = batteryPromise;
|
||||
|
||||
// We just initialized mBatteryPromise, so we know this is the first time
|
||||
// this page has accessed navigator.getBattery(). 1 = navigator.getBattery()
|
||||
Telemetry::Accumulate(Telemetry::BATTERY_STATUS_COUNT, 1);
|
||||
|
||||
if (!mBatteryManager) {
|
||||
mBatteryManager = new battery::BatteryManager(mWindow);
|
||||
mBatteryManager->Init();
|
||||
|
|
|
@ -403,6 +403,8 @@ private:
|
|||
|
||||
nsTArray<RefPtr<Promise> > mVRGetDevicesPromises;
|
||||
nsTArray<uint32_t> mRequestedVibrationPattern;
|
||||
|
||||
bool mBatteryTelemetryReported;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -422,11 +422,13 @@ TextInputProcessor::AppendClauseToPendingComposition(uint32_t aLength,
|
|||
{
|
||||
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
|
||||
RefPtr<TextEventDispatcher> kungfuDeathGrip(mDispatcher);
|
||||
TextRangeType textRangeType;
|
||||
switch (aAttribute) {
|
||||
case ATTR_RAW_CLAUSE:
|
||||
case ATTR_SELECTED_RAW_CLAUSE:
|
||||
case ATTR_CONVERTED_CLAUSE:
|
||||
case ATTR_SELECTED_CLAUSE:
|
||||
textRangeType = ToTextRangeType(aAttribute);
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
@ -435,7 +437,7 @@ TextInputProcessor::AppendClauseToPendingComposition(uint32_t aLength,
|
|||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
return mDispatcher->AppendClauseToPendingComposition(aLength, aAttribute);
|
||||
return mDispatcher->AppendClauseToPendingComposition(aLength, textRangeType);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -2911,7 +2911,8 @@ nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName, int64_t aId,
|
|||
|
||||
nsCString origin;
|
||||
nsresult rv =
|
||||
quota::QuotaManager::GetInfoFromWindow(window, nullptr, &origin, nullptr);
|
||||
quota::QuotaManager::GetInfoFromWindow(window, nullptr, nullptr, &origin,
|
||||
nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
IDBOpenDBOptions options;
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
#include "nsIWeakReference.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIDocument.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -68,8 +66,7 @@ NS_INTERFACE_MAP_END
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginArray,
|
||||
mWindow,
|
||||
mPlugins,
|
||||
mCTPPlugins)
|
||||
mPlugins)
|
||||
|
||||
static void
|
||||
GetPluginMimeTypes(const nsTArray<RefPtr<nsPluginElement> >& aPlugins,
|
||||
|
@ -149,7 +146,6 @@ nsPluginArray::Refresh(bool aReloadDocuments)
|
|||
}
|
||||
|
||||
mPlugins.Clear();
|
||||
mCTPPlugins.Clear();
|
||||
|
||||
nsCOMPtr<nsIDOMNavigator> navigator = mWindow->GetNavigator();
|
||||
|
||||
|
@ -225,13 +221,6 @@ nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
|
|||
|
||||
nsPluginElement* plugin = FindPlugin(mPlugins, aName);
|
||||
aFound = (plugin != nullptr);
|
||||
if (!aFound) {
|
||||
nsPluginElement* hiddenPlugin = FindPlugin(mCTPPlugins, aName);
|
||||
if (hiddenPlugin) {
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
obs->NotifyObservers(hiddenPlugin->PluginTag(), "Plugin::HiddenPluginTouched", nsString(aName).get());
|
||||
}
|
||||
}
|
||||
return plugin;
|
||||
}
|
||||
|
||||
|
@ -293,7 +282,7 @@ operator<(const RefPtr<nsPluginElement>& lhs,
|
|||
void
|
||||
nsPluginArray::EnsurePlugins()
|
||||
{
|
||||
if (!mPlugins.IsEmpty() || !mCTPPlugins.IsEmpty()) {
|
||||
if (!mPlugins.IsEmpty()) {
|
||||
// We already have an array of plugin elements.
|
||||
return;
|
||||
}
|
||||
|
@ -310,31 +299,7 @@ nsPluginArray::EnsurePlugins()
|
|||
// need to wrap each of these with a nsPluginElement, which is
|
||||
// scriptable.
|
||||
for (uint32_t i = 0; i < pluginTags.Length(); ++i) {
|
||||
nsCOMPtr<nsPluginTag> pluginTag = do_QueryInterface(pluginTags[i]);
|
||||
if (!pluginTag) {
|
||||
mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i]));
|
||||
} else if (pluginTag->IsActive()) {
|
||||
uint32_t permission = nsIPermissionManager::ALLOW_ACTION;
|
||||
if (pluginTag->IsClicktoplay()) {
|
||||
nsCString name;
|
||||
pluginTag->GetName(name);
|
||||
if (NS_LITERAL_CSTRING("Shockwave Flash").Equals(name)) {
|
||||
RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
|
||||
nsCString permString;
|
||||
nsresult rv = pluginHost->GetPermissionStringForTag(pluginTag, 0, permString);
|
||||
if (rv == NS_OK) {
|
||||
nsIPrincipal* principal = mWindow->GetExtantDoc()->NodePrincipal();
|
||||
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
|
||||
permMgr->TestPermissionFromPrincipal(principal, permString.get(), &permission);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (permission == nsIPermissionManager::ALLOW_ACTION) {
|
||||
mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i]));
|
||||
} else {
|
||||
mCTPPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Alphabetize the enumeration order of non-hidden plugins to reduce
|
||||
|
|
|
@ -60,10 +60,6 @@ private:
|
|||
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
nsTArray<RefPtr<nsPluginElement> > mPlugins;
|
||||
/* A separate list of click-to-play plugins that we don't tell content
|
||||
* about but keep track of so we can still prompt the user to click to play.
|
||||
*/
|
||||
nsTArray<RefPtr<nsPluginElement> > mCTPPlugins;
|
||||
};
|
||||
|
||||
class nsPluginElement final : public nsISupports,
|
||||
|
|
|
@ -866,8 +866,6 @@ ResolveRequestedModules(nsModuleLoadRequest* aRequest, nsCOMArray<nsIURI> &aUrls
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMArray<nsIURI> uris(length);
|
||||
MOZ_ASSERT(uris.Length() == 0);
|
||||
JS::Rooted<JS::Value> arrayValue(cx, JS::ObjectValue(*specifiers));
|
||||
JS::ForOfIterator iter(cx);
|
||||
if (!iter.init(arrayValue)) {
|
||||
|
|
|
@ -916,4 +916,6 @@ support-files = test_XHR_timeout.js
|
|||
[test_XHRDocURI.html]
|
||||
[test_XHRResponseURL.html]
|
||||
[test_XHRSendData.html]
|
||||
[test_console_binding.html]
|
||||
[test_unknown_url_origin.html]
|
||||
[test_console_proto.html]
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test Console binding</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript">
|
||||
|
||||
function consoleListener() {
|
||||
SpecialPowers.addObserver(this, "console-api-log-event", false);
|
||||
}
|
||||
|
||||
var order = 0;
|
||||
consoleListener.prototype = {
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aTopic == "console-api-log-event") {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
if (order+1 == parseInt(obj.arguments[0])) {
|
||||
ok(true, "Message received: " + obj.arguments[0]);
|
||||
order++;
|
||||
}
|
||||
|
||||
if (order == 3) {
|
||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cl = new consoleListener();
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
[1,2,3].forEach(console.log);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for console.__proto__</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript">
|
||||
|
||||
isnot(Object.getPrototypeOf(console), Object.prototype, "Foo");
|
||||
is(Object.getPrototypeOf(Object.getPrototypeOf(console)), Object.prototype, "Boo");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -309,8 +309,8 @@ DOMInterfaces = {
|
|||
'headerFile': 'mozilla/dom/workers/bindings/ServiceWorkerClients.h',
|
||||
},
|
||||
|
||||
'Console': {
|
||||
'implicitJSContext': [ 'trace', 'time', 'timeEnd', 'timeStamp' ],
|
||||
'console': {
|
||||
'nativeType': 'mozilla::dom::Console',
|
||||
},
|
||||
|
||||
'ConvolverNode': {
|
||||
|
|
|
@ -100,11 +100,12 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
|||
// global to get a context. Everything here is simple getters that cannot
|
||||
// GC, so just paper over the necessary dataflow inversion.
|
||||
JS::AutoSuppressGCAnalysis nogc;
|
||||
if (mIsMainThread) {
|
||||
|
||||
// Now get the global for this callback. Note that for the case of
|
||||
// JS-implemented WebIDL we never have a window here.
|
||||
nsGlobalWindow* win =
|
||||
aIsJSImplementedWebIDL ? nullptr : xpc::WindowGlobalOrNull(realCallback);
|
||||
nsGlobalWindow* win = mIsMainThread && !aIsJSImplementedWebIDL
|
||||
? xpc::WindowGlobalOrNull(realCallback)
|
||||
: nullptr;
|
||||
if (win) {
|
||||
MOZ_ASSERT(win->IsInnerWindow());
|
||||
// We don't want to run script in windows that have been navigated away
|
||||
|
@ -118,11 +119,6 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
|||
globalObject = win;
|
||||
} else {
|
||||
// No DOM Window. Store the global.
|
||||
JSObject* glob = js::GetGlobalForObjectCrossCompartment(realCallback);
|
||||
globalObject = xpc::NativeGlobal(glob);
|
||||
MOZ_ASSERT(globalObject);
|
||||
}
|
||||
} else {
|
||||
JSObject* global = js::GetGlobalForObjectCrossCompartment(realCallback);
|
||||
globalObject = xpc::NativeGlobal(global);
|
||||
MOZ_ASSERT(globalObject);
|
||||
|
|
|
@ -2286,6 +2286,10 @@ class MethodDefiner(PropertyDefiner):
|
|||
"returnsPromise": m.returnsPromise(),
|
||||
"hasIteratorAlias": "@@iterator" in m.aliases
|
||||
}
|
||||
|
||||
if m.isStatic():
|
||||
method["nativeName"] = CppKeywords.checkMethodName(IDLToCIdentifier(m.identifier.name))
|
||||
|
||||
if isChromeOnly(m):
|
||||
self.chrome.append(method)
|
||||
else:
|
||||
|
@ -6061,7 +6065,7 @@ def convertConstIDLValueToJSVal(value):
|
|||
if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]:
|
||||
return "JS::CanonicalizedDoubleValue(%s)" % numericValue(tag, value.value)
|
||||
if tag == IDLType.Tags.bool:
|
||||
return "JSVAL_TRUE" if value.value else "JSVAL_FALSE"
|
||||
return "JS::BooleanValue(true)" if value.value else "JS::BooleanValue(false)"
|
||||
if tag in [IDLType.Tags.float, IDLType.Tags.double]:
|
||||
return "JS::CanonicalizedDoubleValue(%s)" % (value.value)
|
||||
raise TypeError("Const value of unhandled type: %s" % value.type)
|
||||
|
@ -8613,7 +8617,7 @@ class CGStaticMethod(CGAbstractStaticBindingMethod):
|
|||
"""
|
||||
def __init__(self, descriptor, method):
|
||||
self.method = method
|
||||
name = IDLToCIdentifier(method.identifier.name)
|
||||
name = CppKeywords.checkMethodName(IDLToCIdentifier(method.identifier.name))
|
||||
CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
|
||||
|
||||
def generate_code(self):
|
||||
|
|
|
@ -795,6 +795,7 @@ public:
|
|||
static void StaticMethodWithContext(const GlobalObject&, JS::Value);
|
||||
static bool StaticAttribute(const GlobalObject&);
|
||||
static void SetStaticAttribute(const GlobalObject&, bool);
|
||||
static void Assert(const GlobalObject&, bool);
|
||||
|
||||
// Deprecated static methods and attributes
|
||||
static int8_t StaticDeprecatedAttribute(const GlobalObject&);
|
||||
|
|
|
@ -783,6 +783,9 @@ interface TestInterface {
|
|||
static void staticMethod(boolean arg);
|
||||
static void staticMethodWithContext(any arg);
|
||||
|
||||
// Testing static method with a reserved C++ keyword as the name
|
||||
static void assert(boolean arg);
|
||||
|
||||
// Deprecated static methods and attributes
|
||||
[Deprecated="GetAttributeNode"]
|
||||
static attribute byte staticDeprecatedAttribute;
|
||||
|
|
|
@ -26,3 +26,4 @@ skip-if = buildapp != 'mulet'
|
|||
[test_bfcache.html]
|
||||
[test_invalidState.html]
|
||||
[test_ordering.html]
|
||||
[test_dataCloning.html]
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for BroadcastChannel.postMessage invalid State</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="content"></div>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
|
||||
let c = new BroadcastChannel("foo");
|
||||
|
||||
try {
|
||||
c.postMessage(Symbol());
|
||||
ok(false, "This should throw!");
|
||||
} catch(e) {
|
||||
ok(true, "This should throw!");
|
||||
is(e.name, "DataCloneError", "Correct DataCloneError exception thrown");
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -377,6 +377,7 @@ Context::QuotaInitRunnable::Run()
|
|||
RefPtr<ManagerId> managerId = mManager->GetManagerId();
|
||||
nsCOMPtr<nsIPrincipal> principal = managerId->Principal();
|
||||
nsresult rv = QuotaManager::GetInfoFromPrincipal(principal,
|
||||
&mQuotaInfo.mSuffix,
|
||||
&mQuotaInfo.mGroup,
|
||||
&mQuotaInfo.mOrigin,
|
||||
&mQuotaInfo.mIsApp);
|
||||
|
@ -435,6 +436,7 @@ Context::QuotaInitRunnable::Run()
|
|||
QuotaManager* qm = QuotaManager::Get();
|
||||
MOZ_ASSERT(qm);
|
||||
nsresult rv = qm->EnsureOriginIsInitialized(PERSISTENCE_TYPE_DEFAULT,
|
||||
mQuotaInfo.mSuffix,
|
||||
mQuotaInfo.mGroup,
|
||||
mQuotaInfo.mOrigin,
|
||||
mQuotaInfo.mIsApp,
|
||||
|
|
|
@ -28,6 +28,7 @@ ManagerId::Create(nsIPrincipal* aPrincipal, ManagerId** aManagerIdOut)
|
|||
// order to interpret calls from QM correctly.
|
||||
nsCString quotaOrigin;
|
||||
nsresult rv = QuotaManager::GetInfoFromPrincipal(aPrincipal,
|
||||
nullptr, // suffix
|
||||
nullptr, // group
|
||||
"aOrigin,
|
||||
nullptr); // is app
|
||||
|
|
|
@ -31,6 +31,7 @@ struct QuotaInfo
|
|||
{
|
||||
QuotaInfo() : mIsApp(false) { }
|
||||
nsCOMPtr<nsIFile> mDir;
|
||||
nsCString mSuffix;
|
||||
nsCString mGroup;
|
||||
nsCString mOrigin;
|
||||
bool mIsApp;
|
||||
|
|
|
@ -275,15 +275,16 @@ public:
|
|||
mode = ExtendMode::REPEAT;
|
||||
}
|
||||
|
||||
Filter filter;
|
||||
SamplingFilter samplingFilter;
|
||||
if (state.imageSmoothingEnabled) {
|
||||
filter = Filter::GOOD;
|
||||
samplingFilter = SamplingFilter::GOOD;
|
||||
} else {
|
||||
filter = Filter::POINT;
|
||||
samplingFilter = SamplingFilter::POINT;
|
||||
}
|
||||
|
||||
mPattern.InitSurfacePattern(state.patternStyles[aStyle]->mSurface, mode,
|
||||
state.patternStyles[aStyle]->mTransform, filter);
|
||||
state.patternStyles[aStyle]->mTransform,
|
||||
samplingFilter);
|
||||
}
|
||||
|
||||
return *mPattern.GetPattern();
|
||||
|
@ -4711,12 +4712,12 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
|
|||
return;
|
||||
}
|
||||
|
||||
Filter filter;
|
||||
SamplingFilter samplingFilter;
|
||||
|
||||
if (CurrentState().imageSmoothingEnabled)
|
||||
filter = gfx::Filter::LINEAR;
|
||||
samplingFilter = gfx::SamplingFilter::LINEAR;
|
||||
else
|
||||
filter = gfx::Filter::POINT;
|
||||
samplingFilter = gfx::SamplingFilter::POINT;
|
||||
|
||||
gfx::Rect bounds;
|
||||
|
||||
|
@ -4739,7 +4740,7 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
|
|||
DrawSurface(srcSurf,
|
||||
gfx::Rect(aDx, aDy, aDw, aDh),
|
||||
sourceRect,
|
||||
DrawSurfaceOptions(filter),
|
||||
DrawSurfaceOptions(samplingFilter),
|
||||
DrawOptions(CurrentState().globalAlpha, UsedOperation()));
|
||||
} else {
|
||||
DrawDirectlyToCanvas(drawInfo, &bounds,
|
||||
|
@ -4806,7 +4807,7 @@ CanvasRenderingContext2D::DrawDirectlyToCanvas(
|
|||
auto result = aImage.mImgContainer->
|
||||
Draw(context, scaledImageSize,
|
||||
ImageRegion::Create(gfxRect(aSrc.x, aSrc.y, aSrc.width, aSrc.height)),
|
||||
aImage.mWhichFrame, Filter::GOOD, Some(svgContext), modifiedFlags);
|
||||
aImage.mWhichFrame, SamplingFilter::GOOD, Some(svgContext), modifiedFlags);
|
||||
|
||||
if (result != DrawResult::SUCCESS) {
|
||||
NS_WARNING("imgIContainer::Draw failed");
|
||||
|
@ -5041,7 +5042,7 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& aWindow, double aX,
|
|||
gfx::Rect destRect(0, 0, aW, aH);
|
||||
gfx::Rect sourceRect(0, 0, sw, sh);
|
||||
mTarget->DrawSurface(source, destRect, sourceRect,
|
||||
DrawSurfaceOptions(gfx::Filter::POINT),
|
||||
DrawSurfaceOptions(gfx::SamplingFilter::POINT),
|
||||
DrawOptions(GlobalAlpha(), UsedOperation(),
|
||||
AntialiasMode::NONE));
|
||||
mTarget->Flush();
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#include "WebGLQuery.h"
|
||||
#include "WebGLSampler.h"
|
||||
#include "WebGLShader.h"
|
||||
#include "WebGLTimerQuery.h"
|
||||
#include "WebGLTransformFeedback.h"
|
||||
#include "WebGLVertexArray.h"
|
||||
#include "WebGLVertexAttribData.h"
|
||||
|
@ -213,6 +214,15 @@ WebGLContext::~WebGLContext()
|
|||
mContextLossHandler = nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void
|
||||
ClearLinkedList(LinkedList<T>& list)
|
||||
{
|
||||
while (!list.isEmpty()) {
|
||||
list.getLast()->DeleteOnce();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::DestroyResourcesAndContext()
|
||||
{
|
||||
|
@ -247,26 +257,21 @@ WebGLContext::DestroyResourcesAndContext()
|
|||
mBoundTransformFeedbackBuffers.Clear();
|
||||
mBoundUniformBuffers.Clear();
|
||||
|
||||
while (!mTextures.isEmpty())
|
||||
mTextures.getLast()->DeleteOnce();
|
||||
while (!mVertexArrays.isEmpty())
|
||||
mVertexArrays.getLast()->DeleteOnce();
|
||||
while (!mBuffers.isEmpty())
|
||||
mBuffers.getLast()->DeleteOnce();
|
||||
while (!mRenderbuffers.isEmpty())
|
||||
mRenderbuffers.getLast()->DeleteOnce();
|
||||
while (!mFramebuffers.isEmpty())
|
||||
mFramebuffers.getLast()->DeleteOnce();
|
||||
while (!mShaders.isEmpty())
|
||||
mShaders.getLast()->DeleteOnce();
|
||||
while (!mPrograms.isEmpty())
|
||||
mPrograms.getLast()->DeleteOnce();
|
||||
while (!mQueries.isEmpty())
|
||||
mQueries.getLast()->DeleteOnce();
|
||||
while (!mSamplers.isEmpty())
|
||||
mSamplers.getLast()->DeleteOnce();
|
||||
while (!mTransformFeedbacks.isEmpty())
|
||||
mTransformFeedbacks.getLast()->DeleteOnce();
|
||||
//////
|
||||
|
||||
ClearLinkedList(mBuffers);
|
||||
ClearLinkedList(mFramebuffers);
|
||||
ClearLinkedList(mPrograms);
|
||||
ClearLinkedList(mQueries);
|
||||
ClearLinkedList(mRenderbuffers);
|
||||
ClearLinkedList(mSamplers);
|
||||
ClearLinkedList(mShaders);
|
||||
ClearLinkedList(mTextures);
|
||||
ClearLinkedList(mTimerQueries);
|
||||
ClearLinkedList(mTransformFeedbacks);
|
||||
ClearLinkedList(mVertexArrays);
|
||||
|
||||
//////
|
||||
|
||||
mFakeBlack_2D_0000 = nullptr;
|
||||
mFakeBlack_2D_0001 = nullptr;
|
||||
|
|
|
@ -101,6 +101,7 @@ class WebGLSampler;
|
|||
class WebGLShader;
|
||||
class WebGLShaderPrecisionFormat;
|
||||
class WebGLTexture;
|
||||
class WebGLTimerQuery;
|
||||
class WebGLTransformFeedback;
|
||||
class WebGLUniformLocation;
|
||||
class WebGLVertexArray;
|
||||
|
@ -1394,18 +1395,17 @@ protected:
|
|||
WebGLRefPtr<WebGLTransformFeedback> mBoundTransformFeedback;
|
||||
WebGLRefPtr<WebGLVertexArray> mBoundVertexArray;
|
||||
|
||||
LinkedList<WebGLTexture> mTextures;
|
||||
LinkedList<WebGLBuffer> mBuffers;
|
||||
LinkedList<WebGLFramebuffer> mFramebuffers;
|
||||
LinkedList<WebGLProgram> mPrograms;
|
||||
LinkedList<WebGLQuery> mQueries;
|
||||
LinkedList<WebGLShader> mShaders;
|
||||
LinkedList<WebGLRenderbuffer> mRenderbuffers;
|
||||
LinkedList<WebGLFramebuffer> mFramebuffers;
|
||||
LinkedList<WebGLVertexArray> mVertexArrays;
|
||||
|
||||
// TODO(djg): Does this need a rethink? Should it be WebGL2Context?
|
||||
LinkedList<WebGLSampler> mSamplers;
|
||||
LinkedList<WebGLShader> mShaders;
|
||||
LinkedList<WebGLTexture> mTextures;
|
||||
LinkedList<WebGLTimerQuery> mTimerQueries;
|
||||
LinkedList<WebGLTransformFeedback> mTransformFeedbacks;
|
||||
LinkedList<WebGLVertexArray> mVertexArrays;
|
||||
|
||||
WebGLRefPtr<WebGLTransformFeedback> mDefaultTransformFeedback;
|
||||
WebGLRefPtr<WebGLVertexArray> mDefaultVertexArray;
|
||||
|
|
|
@ -26,6 +26,7 @@ WebGLTimerQuery::WebGLTimerQuery(WebGLContext* webgl, GLuint name)
|
|||
, mTarget(LOCAL_GL_NONE)
|
||||
, mCanBeAvailable(false)
|
||||
{
|
||||
mContext->mTimerQueries.insertBack(this);
|
||||
}
|
||||
|
||||
WebGLTimerQuery::~WebGLTimerQuery()
|
||||
|
@ -45,8 +46,12 @@ WebGLTimerQuery::Create(WebGLContext* webgl)
|
|||
void
|
||||
WebGLTimerQuery::Delete()
|
||||
{
|
||||
mContext->MakeContextCurrent();
|
||||
mContext->gl->fDeleteQueries(1, &mGLName);
|
||||
gl::GLContext* gl = mContext->GL();
|
||||
|
||||
gl->MakeCurrent();
|
||||
gl->fDeleteQueries(1, &mGLName);
|
||||
|
||||
LinkedListElement<WebGLTimerQuery>::removeFrom(mContext->mTimerQueries);
|
||||
}
|
||||
|
||||
WebGLContext*
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace mozilla {
|
|||
class WebGLTimerQuery final
|
||||
: public nsWrapperCache
|
||||
, public WebGLRefCountedObject<WebGLTimerQuery>
|
||||
, public LinkedListElement<WebGLTimerQuery>
|
||||
, public WebGLContextBoundObject
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -151,7 +151,7 @@ static_assert(JS_STRUCTURED_CLONE_VERSION == 6,
|
|||
"Need to update the major schema version.");
|
||||
|
||||
// Major schema version. Bump for almost everything.
|
||||
const uint32_t kMajorSchemaVersion = 22;
|
||||
const uint32_t kMajorSchemaVersion = 23;
|
||||
|
||||
// Minor schema version. Should almost always be 0 (maybe bump on release
|
||||
// branches if we have to).
|
||||
|
@ -1055,6 +1055,13 @@ CreateTables(mozIStorageConnection* aConnection)
|
|||
js::ProfileEntry::Category::STORAGE);
|
||||
|
||||
// Table `database`
|
||||
|
||||
// There are two reasons for having the origin column.
|
||||
// First, we can ensure that we don't have collisions in the origin hash we
|
||||
// use for the path because when we open the db we can make sure that the
|
||||
// origins exactly match. Second, chrome code crawling through the idb
|
||||
// directory can figure out the origin of every db without having to
|
||||
// reverse-engineer our hash scheme.
|
||||
nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"CREATE TABLE database"
|
||||
"( name TEXT PRIMARY KEY"
|
||||
|
@ -4053,6 +4060,45 @@ UpgradeSchemaFrom21_0To22_0(mozIStorageConnection* aConnection)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
UpgradeSchemaFrom22_0To23_0(mozIStorageConnection* aConnection,
|
||||
const nsACString& aOrigin)
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(aConnection);
|
||||
MOZ_ASSERT(!aOrigin.IsEmpty());
|
||||
|
||||
PROFILER_LABEL("IndexedDB",
|
||||
"UpgradeSchemaFrom22_0To23_0",
|
||||
js::ProfileEntry::Category::STORAGE);
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"UPDATE database "
|
||||
"SET origin = :origin;"
|
||||
), getter_AddRefs(stmt));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("origin"), aOrigin);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->Execute();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = aConnection->SetSchemaVersion(MakeSchemaVersion(23, 0));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetDatabaseFileURL(nsIFile* aDatabaseFile,
|
||||
PersistenceType aPersistenceType,
|
||||
|
@ -4545,7 +4591,7 @@ CreateStorageConnection(nsIFile* aDBFile,
|
|||
}
|
||||
} else {
|
||||
// This logic needs to change next time we change the schema!
|
||||
static_assert(kSQLiteSchemaVersion == int32_t((22 << 4) + 0),
|
||||
static_assert(kSQLiteSchemaVersion == int32_t((23 << 4) + 0),
|
||||
"Upgrade function needed due to schema version increase.");
|
||||
|
||||
while (schemaVersion != kSQLiteSchemaVersion) {
|
||||
|
@ -4587,6 +4633,8 @@ CreateStorageConnection(nsIFile* aDBFile,
|
|||
rv = UpgradeSchemaFrom20_0To21_0(connection);
|
||||
} else if (schemaVersion == MakeSchemaVersion(21, 0)) {
|
||||
rv = UpgradeSchemaFrom21_0To22_0(connection);
|
||||
} else if (schemaVersion == MakeSchemaVersion(22, 0)) {
|
||||
rv = UpgradeSchemaFrom22_0To23_0(connection, aOrigin);
|
||||
} else {
|
||||
IDB_WARNING("Unable to open IndexedDB database, no upgrade path is "
|
||||
"available!");
|
||||
|
@ -7191,6 +7239,7 @@ protected:
|
|||
nsTArray<MaybeBlockedDatabaseInfo> mMaybeBlockedDatabases;
|
||||
|
||||
const CommonFactoryRequestParams mCommonParams;
|
||||
nsCString mSuffix;
|
||||
nsCString mGroup;
|
||||
nsCString mOrigin;
|
||||
nsCString mDatabaseId;
|
||||
|
@ -17634,6 +17683,10 @@ Maintenance::DirectoryWork()
|
|||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
MOZ_ASSERT(quotaManager);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(quotaManager->EnsureStorageIsInitialized()))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> storageDir = GetFileForPath(quotaManager->GetStoragePath());
|
||||
MOZ_ASSERT(storageDir);
|
||||
|
||||
|
@ -17799,10 +17852,12 @@ Maintenance::DirectoryWork()
|
|||
MOZ_ASSERT(origin.IsEmpty());
|
||||
|
||||
int64_t dummyTimeStamp;
|
||||
nsCString dummySuffix;
|
||||
bool dummyIsApp;
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
QuotaManager::GetDirectoryMetadata(originDir,
|
||||
quotaManager->GetDirectoryMetadata2(originDir,
|
||||
&dummyTimeStamp,
|
||||
dummySuffix,
|
||||
group,
|
||||
origin,
|
||||
&dummyIsApp)))) {
|
||||
|
@ -20154,7 +20209,7 @@ FactoryOp::CheckPermission(ContentParent* aContentParent,
|
|||
}
|
||||
|
||||
if (State::Initial == mState) {
|
||||
QuotaManager::GetInfoForChrome(&mGroup, &mOrigin, &mIsApp);
|
||||
QuotaManager::GetInfoForChrome(&mSuffix, &mGroup, &mOrigin, &mIsApp);
|
||||
|
||||
MOZ_ASSERT(!QuotaManager::IsFirstPromptRequired(persistenceType, mOrigin,
|
||||
mIsApp));
|
||||
|
@ -20176,10 +20231,15 @@ FactoryOp::CheckPermission(ContentParent* aContentParent,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsCString suffix;
|
||||
nsCString group;
|
||||
nsCString origin;
|
||||
bool isApp;
|
||||
rv = QuotaManager::GetInfoFromPrincipal(principal, &group, &origin, &isApp);
|
||||
rv = QuotaManager::GetInfoFromPrincipal(principal,
|
||||
&suffix,
|
||||
&group,
|
||||
&origin,
|
||||
&isApp);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -20221,6 +20281,7 @@ FactoryOp::CheckPermission(ContentParent* aContentParent,
|
|||
|
||||
if (permission != PermissionRequestBase::kPermissionDenied &&
|
||||
State::Initial == mState) {
|
||||
mSuffix = suffix;
|
||||
mGroup = group;
|
||||
mOrigin = origin;
|
||||
mIsApp = isApp;
|
||||
|
@ -20695,6 +20756,7 @@ OpenDatabaseOp::DoDatabaseWork()
|
|||
|
||||
nsresult rv =
|
||||
quotaManager->EnsureOriginIsInitialized(persistenceType,
|
||||
mSuffix,
|
||||
mGroup,
|
||||
mOrigin,
|
||||
mIsApp,
|
||||
|
@ -20859,7 +20921,7 @@ OpenDatabaseOp::LoadDatabaseInformation(mozIStorageConnection* aConnection)
|
|||
// Load version information.
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT name, version "
|
||||
"SELECT name, origin, version "
|
||||
"FROM database"
|
||||
), getter_AddRefs(stmt));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -20886,8 +20948,18 @@ OpenDatabaseOp::LoadDatabaseInformation(mozIStorageConnection* aConnection)
|
|||
return NS_ERROR_FILE_CORRUPTED;
|
||||
}
|
||||
|
||||
nsCString origin;
|
||||
rv = stmt->GetUTF8String(1, origin);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (mOrigin != origin) {
|
||||
NS_WARNING("Origins don't match!");
|
||||
}
|
||||
|
||||
int64_t version;
|
||||
rv = stmt->GetInt64(1, &version);
|
||||
rv = stmt->GetInt64(2, &version);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -1071,7 +1071,7 @@ IDBDatabase::GetQuotaInfo(nsACString& aOrigin,
|
|||
MOZ_CRASH("Is this needed?!");
|
||||
|
||||
case PrincipalInfo::TSystemPrincipalInfo:
|
||||
QuotaManager::GetInfoForChrome(nullptr, &aOrigin, nullptr);
|
||||
QuotaManager::GetInfoForChrome(nullptr, nullptr, &aOrigin, nullptr);
|
||||
return NS_OK;
|
||||
|
||||
case PrincipalInfo::TContentPrincipalInfo: {
|
||||
|
@ -1083,6 +1083,7 @@ IDBDatabase::GetQuotaInfo(nsACString& aOrigin,
|
|||
}
|
||||
|
||||
rv = QuotaManager::GetInfoFromPrincipal(principal,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&aOrigin,
|
||||
nullptr);
|
||||
|
|
|
@ -381,14 +381,14 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
|
|||
[test_webapp_clearBrowserData_inproc_inproc.html]
|
||||
# The clearBrowserData tests are only supposed to run in the main process.
|
||||
# They currently time out on android.
|
||||
skip-if = buildapp != 'mulet'
|
||||
skip-if = buildapp == 'b2g' || e10s || toolkit == 'android'
|
||||
[test_webapp_clearBrowserData_inproc_oop.html]
|
||||
# The clearBrowserData tests are only supposed to run in the main process.
|
||||
# They currently time out on android.
|
||||
skip-if = buildapp != 'mulet'
|
||||
skip-if = buildapp == 'b2g' || e10s || toolkit == 'android'
|
||||
[test_webapp_clearBrowserData_oop_inproc.html]
|
||||
# The clearBrowserData tests are only supposed to run in the main process.
|
||||
# They currently time out on android.
|
||||
skip-if = buildapp != 'mulet'
|
||||
skip-if = buildapp == 'b2g' || e10s || toolkit == 'android'
|
||||
[test_serviceworker.html]
|
||||
skip-if = buildapp == 'b2g'
|
||||
|
|
Двоичные данные
dom/indexedDB/test/unit/defaultStorageUpgrade_profile.zip
Двоичные данные
dom/indexedDB/test/unit/defaultStorageUpgrade_profile.zip
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -75,6 +75,30 @@ function testSteps()
|
|||
// This one lives in storage/default/file++++++index.html
|
||||
{ url: "file://///index.html", dbName: "dbS", dbVersion: 1 },
|
||||
|
||||
// This one lives in storage/permanent/resource+++fx-share-addon-at-mozilla-dot-org-fx-share-addon-data
|
||||
{ url: "resource://fx-share-addon-at-mozilla-dot-org-fx-share-addon-data",
|
||||
dbName: "dbU", dbOptions: { version: 1, storage: "persistent" } },
|
||||
|
||||
// This one lives in storage/temporary/http+++localhost+81
|
||||
// The .metadata file was intentionally removed for this origin directory
|
||||
// to test restoring during upgrade.
|
||||
{ url: "http://localhost:81", dbName: "dbV",
|
||||
dbOptions: { version: 1, storage: "temporary" } },
|
||||
|
||||
// This one lives in storage/temporary/http+++localhost+82
|
||||
// The .metadata file was intentionally truncated for this origin directory
|
||||
// to test restoring during upgrade.
|
||||
{ url: "http://localhost:82", dbName: "dbW",
|
||||
dbOptions: { version: 1, storage: "temporary" } },
|
||||
|
||||
// This one lives in storage/temporary/1007+f+app+++system.gaiamobile.org
|
||||
{ appId: 1007, inIsolatedMozBrowser: false, url: "app://system.gaiamobile.org",
|
||||
dbName: "dbX", dbOptions: { version: 1, storage: "temporary" } },
|
||||
|
||||
// This one lives in storage/temporary/1007+t+https+++developer.cdn.mozilla.net
|
||||
{ appId: 1007, inIsolatedMozBrowser: true, url: "https://developer.cdn.mozilla.net",
|
||||
dbName: "dbY", dbOptions: { version: 1, storage: "temporary" } },
|
||||
|
||||
// This one lives in storage/temporary/http+++localhost
|
||||
{ url: "http://localhost", dbName: "dbZ",
|
||||
dbOptions: { version: 1, storage: "temporary" } }
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
const openParams = [
|
||||
// This one lives in storage/default/http+++www.mozilla.org
|
||||
{ url: "http://www.mozilla.org", dbName: "dbB", dbVersion: 1 },
|
||||
|
||||
// This one lives in storage/default/1007+f+app+++system.gaiamobile.org
|
||||
{ appId: 1007, inIsolatedMozBrowser: false, url: "app://system.gaiamobile.org",
|
||||
dbName: "dbM", dbVersion: 1 },
|
||||
|
||||
// This one lives in storage/default/1007+t+https+++developer.cdn.mozilla.net
|
||||
{ appId: 1007, inIsolatedMozBrowser: true, url: "https://developer.cdn.mozilla.net",
|
||||
dbName: "dbN", dbVersion: 1 },
|
||||
];
|
||||
|
||||
let ios = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIIOService);
|
||||
|
||||
let ssm = SpecialPowers.Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(SpecialPowers.Ci.nsIScriptSecurityManager);
|
||||
|
||||
function openDatabase(params) {
|
||||
let uri = ios.newURI(params.url, null, null);
|
||||
let principal =
|
||||
ssm.createCodebasePrincipal(uri,
|
||||
{appId: params.appId || ssm.NO_APPID,
|
||||
inIsolatedMozBrowser: params.inIsolatedMozBrowser});
|
||||
let request = indexedDB.openForPrincipal(principal, params.dbName,
|
||||
params.dbVersion);
|
||||
return request;
|
||||
}
|
||||
|
||||
for (let i = 1; i <= 2; i++) {
|
||||
clearAllDatabases(continueToNextStepSync);
|
||||
yield undefined;
|
||||
|
||||
installPackagedProfile("idbSubdirUpgrade" + i + "_profile");
|
||||
|
||||
for (let params of openParams) {
|
||||
let request = openDatabase(params);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Correct event type");
|
||||
}
|
||||
|
||||
resetAllDatabases(continueToNextStepSync);
|
||||
yield undefined;
|
||||
|
||||
for (let params of openParams) {
|
||||
let request = openDatabase(params);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Correct event type");
|
||||
}
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
|
@ -0,0 +1,268 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
const openParams = [
|
||||
// This one lives in storage/permanent/chrome
|
||||
// The .metadata-v2 file was intentionally removed for this origin directory
|
||||
// to test restoring.
|
||||
{ dbName: "dbA",
|
||||
dbOptions: { version: 1, storage: "persistent" } },
|
||||
|
||||
// This one lives in storage/temporary/http+++localhost
|
||||
// The .metadata-v2 file was intentionally removed for this origin directory
|
||||
// to test restoring.
|
||||
{ url: "http://localhost", dbName: "dbB",
|
||||
dbOptions: { version: 1, storage: "temporary" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+81^userContextId=1
|
||||
// The .metadata-v2 file was intentionally removed for this origin directory
|
||||
// to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:81", dbName: "dbC",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+82^userContextId=1
|
||||
// The .metadata-v2 file was intentionally truncated for this origin directory
|
||||
// to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:82", dbName: "dbD",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+83^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// 4 bytes of the 64 bit timestamp
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:83", dbName: "dbE",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+84^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// the 64 bit timestamp
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:84", dbName: "dbF",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+85^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// the 64 bit timestamp and
|
||||
// the 8 bit persisted flag
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:85", dbName: "dbG",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+86^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// the 64 bit timestamp,
|
||||
// the 8 bit persisted flag and
|
||||
// 2 bytes of the 32 bit reserved data 1
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:86", dbName: "dbH",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+87^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// the 64 bit timestamp,
|
||||
// the 8 bit persisted flag and
|
||||
// the 32 bit reserved data 1
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:87", dbName: "dbI",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+88^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// the 64 bit timestamp,
|
||||
// the 8 bit persisted flag,
|
||||
// the 32 bit reserved data 1 and
|
||||
// 2 bytes of the 32 bit reserved data 2
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:88", dbName: "dbJ",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+89^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// the 64 bit timestamp,
|
||||
// the 8 bit persisted flag,
|
||||
// the 32 bit reserved data 1 and
|
||||
// the 32 bit reserved data 2
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:89", dbName: "dbK",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+90^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// the 64 bit timestamp,
|
||||
// the 8 bit persisted flag,
|
||||
// the 32 bit reserved data 1,
|
||||
// the 32 bit reserved data 2 and
|
||||
// 2 bytes of the 32 bit suffix length
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:90", dbName: "dbL",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+91^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// the 64 bit timestamp,
|
||||
// the 8 bit persisted flag,
|
||||
// the 32 bit reserved data 1,
|
||||
// the 32 bit reserved data 2,
|
||||
// the 32 bit suffix length and
|
||||
// first 5 chars of the suffix
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:91", dbName: "dbM",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+92^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// the 64 bit timestamp,
|
||||
// the 8 bit persisted flag,
|
||||
// the 32 bit reserved data 1,
|
||||
// the 32 bit reserved data 2,
|
||||
// the 32 bit suffix length and
|
||||
// the suffix
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:92", dbName: "dbN",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+93^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// the 64 bit timestamp,
|
||||
// the 8 bit persisted flag,
|
||||
// the 32 bit reserved data 1,
|
||||
// the 32 bit reserved data 2,
|
||||
// the 32 bit suffix length,
|
||||
// the suffix and
|
||||
// 2 bytes of the 32 bit group length
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:93", dbName: "dbO",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+94^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// the 64 bit timestamp,
|
||||
// the 8 bit persisted flag,
|
||||
// the 32 bit reserved data 1,
|
||||
// the 32 bit reserved data 2,
|
||||
// the 32 bit suffix length,
|
||||
// the suffix,
|
||||
// the 32 bit group length and
|
||||
// first 5 chars of the group
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:94", dbName: "dbP",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+95^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// the 64 bit timestamp,
|
||||
// the 8 bit persisted flag,
|
||||
// the 32 bit reserved data 1,
|
||||
// the 32 bit reserved data 2,
|
||||
// the 32 bit suffix length,
|
||||
// the suffix,
|
||||
// the 32 bit group length and
|
||||
// the group
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:95", dbName: "dbQ",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+96^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// the 64 bit timestamp,
|
||||
// the 8 bit persisted flag,
|
||||
// the 32 bit reserved data 1,
|
||||
// the 32 bit reserved data 2,
|
||||
// the 32 bit suffix length,
|
||||
// the suffix,
|
||||
// the 32 bit group length,
|
||||
// the group and
|
||||
// 2 bytes of the 32 bit origin length
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:96", dbName: "dbR",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+97^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// the 64 bit timestamp,
|
||||
// the 8 bit persisted flag,
|
||||
// the 32 bit reserved data 1,
|
||||
// the 32 bit reserved data 2,
|
||||
// the 32 bit suffix length,
|
||||
// the suffix,
|
||||
// the 32 bit group length,
|
||||
// the group,
|
||||
// the 32 bit origin length and
|
||||
// first 12 char of the origin
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:97", dbName: "dbS",
|
||||
dbOptions: { version: 1, storage: "default" } },
|
||||
|
||||
// This one lives in storage/default/http+++localhost+98^userContextId=1
|
||||
// The .metadata-v2 file was intentionally modified to contain only
|
||||
// the 64 bit timestamp,
|
||||
// the 8 bit persisted flag,
|
||||
// the 32 bit reserved data 1,
|
||||
// the 32 bit reserved data 2,
|
||||
// the 32 bit suffix length,
|
||||
// the suffix,
|
||||
// the 32 bit group length,
|
||||
// the group,
|
||||
// the 32 bit origin length and
|
||||
// the origin
|
||||
// for this origin directory to test restoring.
|
||||
{ attrs: { userContextId: 1 }, url: "http://localhost:98", dbName: "dbT",
|
||||
dbOptions: { version: 1, storage: "default" } }
|
||||
];
|
||||
|
||||
let ios = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIIOService);
|
||||
|
||||
let ssm = SpecialPowers.Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(SpecialPowers.Ci.nsIScriptSecurityManager);
|
||||
|
||||
function openDatabase(params) {
|
||||
let request;
|
||||
if ("url" in params) {
|
||||
let uri = ios.newURI(params.url, null, null);
|
||||
let principal = ssm.createCodebasePrincipal(uri, params.attrs || {});
|
||||
request = indexedDB.openForPrincipal(principal, params.dbName,
|
||||
params.dbOptions);
|
||||
} else {
|
||||
request = indexedDB.open(params.dbName, params.dbOptions);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
clearAllDatabases(continueToNextStepSync);
|
||||
yield undefined;
|
||||
|
||||
installPackagedProfile("metadata2Restore_profile");
|
||||
|
||||
for (let params of openParams) {
|
||||
let request = openDatabase(params);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Correct event type");
|
||||
}
|
||||
|
||||
resetAllDatabases(continueToNextStepSync);
|
||||
yield undefined;
|
||||
|
||||
for (let params of openParams) {
|
||||
let request = openDatabase(params);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Correct event type");
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
// This lives in storage/default/http+++www.mozilla.org
|
||||
const url = "http://www.mozilla.org";
|
||||
const dbName = "dbC";
|
||||
const dbVersion = 1;
|
||||
|
||||
let ios = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIIOService);
|
||||
|
||||
let ssm = SpecialPowers.Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(SpecialPowers.Ci.nsIScriptSecurityManager);
|
||||
|
||||
function openDatabase() {
|
||||
let uri = ios.newURI(url, null, null);
|
||||
let principal = ssm.createCodebasePrincipal(uri, {});
|
||||
let request = indexedDB.openForPrincipal(principal, dbName, dbVersion);
|
||||
return request;
|
||||
}
|
||||
|
||||
clearAllDatabases(continueToNextStepSync);
|
||||
yield undefined;
|
||||
|
||||
installPackagedProfile("oldDirectories_profile");
|
||||
|
||||
let request = openDatabase();
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Correct event type");
|
||||
|
||||
resetAllDatabases(continueToNextStepSync);
|
||||
yield undefined;
|
||||
|
||||
request = openDatabase();
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Correct event type");
|
||||
|
||||
let directoryService = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIProperties);
|
||||
|
||||
let profileDir = directoryService.get("ProfD", Ci.nsIFile);
|
||||
|
||||
let dir = profileDir.clone();
|
||||
dir.append("indexedDB");
|
||||
|
||||
let exists = dir.exists();
|
||||
ok(!exists, "indexedDB doesn't exist");
|
||||
|
||||
dir = profileDir.clone();
|
||||
dir.append("storage");
|
||||
dir.append("persistent");
|
||||
|
||||
exists = dir.exists();
|
||||
ok(!exists, "storage/persistent doesn't exist");
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
const openParams = [
|
||||
// This one lives in storage/default/http+++www.mozilla.org
|
||||
{ url: "http://www.mozilla.org", dbName: "dbB", dbVersion: 1 },
|
||||
|
||||
// This one lives in storage/default/1007+f+app+++system.gaiamobile.org
|
||||
{ appId: 1007, inIsolatedMozBrowser: false, url: "app://system.gaiamobile.org",
|
||||
dbName: "dbM", dbVersion: 1 },
|
||||
|
||||
// This one lives in storage/default/1007+t+https+++developer.cdn.mozilla.net
|
||||
{ appId: 1007, inIsolatedMozBrowser: true, url: "https://developer.cdn.mozilla.net",
|
||||
dbName: "dbN", dbVersion: 1 },
|
||||
];
|
||||
|
||||
let ios = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIIOService);
|
||||
|
||||
let ssm = SpecialPowers.Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(SpecialPowers.Ci.nsIScriptSecurityManager);
|
||||
|
||||
function openDatabase(params) {
|
||||
let uri = ios.newURI(params.url, null, null);
|
||||
let principal =
|
||||
ssm.createCodebasePrincipal(uri,
|
||||
{appId: params.appId || ssm.NO_APPID,
|
||||
inIsolatedMozBrowser: params.inIsolatedMozBrowser});
|
||||
let request = indexedDB.openForPrincipal(principal, params.dbName,
|
||||
params.dbVersion);
|
||||
return request;
|
||||
}
|
||||
|
||||
clearAllDatabases(continueToNextStepSync);
|
||||
yield undefined;
|
||||
|
||||
installPackagedProfile("schema23upgrade_profile");
|
||||
|
||||
for (let params of openParams) {
|
||||
let request = openDatabase(params);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Correct event type");
|
||||
}
|
||||
|
||||
resetAllDatabases(continueToNextStepSync);
|
||||
yield undefined;
|
||||
|
||||
for (let params of openParams) {
|
||||
let request = openDatabase(params);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Correct event type");
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
const openParams = [
|
||||
// This one lives in storage/default/http+++www.mozilla.org
|
||||
{ url: "http://www.mozilla.org", dbName: "dbB", dbVersion: 1 },
|
||||
|
||||
// This one lives in storage/default/1007+f+app+++system.gaiamobile.org
|
||||
{ appId: 1007, inIsolatedMozBrowser: false, url: "app://system.gaiamobile.org",
|
||||
dbName: "dbM", dbVersion: 1 },
|
||||
|
||||
// This one lives in storage/default/1007+t+https+++developer.cdn.mozilla.net
|
||||
{ appId: 1007, inIsolatedMozBrowser: true, url: "https://developer.cdn.mozilla.net",
|
||||
dbName: "dbN", dbVersion: 1 },
|
||||
];
|
||||
|
||||
let ios = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIIOService);
|
||||
|
||||
let ssm = SpecialPowers.Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(SpecialPowers.Ci.nsIScriptSecurityManager);
|
||||
|
||||
function openDatabase(params) {
|
||||
let uri = ios.newURI(params.url, null, null);
|
||||
let principal =
|
||||
ssm.createCodebasePrincipal(uri,
|
||||
{appId: params.appId || ssm.NO_APPID,
|
||||
inIsolatedMozBrowser: params.inIsolatedMozBrowser});
|
||||
let request = indexedDB.openForPrincipal(principal, params.dbName,
|
||||
params.dbVersion);
|
||||
return request;
|
||||
}
|
||||
|
||||
clearAllDatabases(continueToNextStepSync);
|
||||
yield undefined;
|
||||
|
||||
installPackagedProfile("storagePersistentUpgrade_profile");
|
||||
|
||||
for (let params of openParams) {
|
||||
let request = openDatabase(params);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Correct event type");
|
||||
}
|
||||
|
||||
resetAllDatabases(continueToNextStepSync);
|
||||
yield undefined;
|
||||
|
||||
for (let params of openParams) {
|
||||
let request = openDatabase(params);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Correct event type");
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
|
@ -10,15 +10,21 @@ skip-if = toolkit == 'gonk'
|
|||
support-files =
|
||||
bug1056939_profile.zip
|
||||
defaultStorageUpgrade_profile.zip
|
||||
idbSubdirUpgrade1_profile.zip
|
||||
idbSubdirUpgrade2_profile.zip
|
||||
mutableFileUpgrade_profile.zip
|
||||
oldDirectories_profile.zip
|
||||
GlobalObjectsChild.js
|
||||
GlobalObjectsComponent.js
|
||||
GlobalObjectsComponent.manifest
|
||||
GlobalObjectsModule.jsm
|
||||
GlobalObjectsSandbox.js
|
||||
metadata2Restore_profile.zip
|
||||
metadataRestore_profile.zip
|
||||
schema18upgrade_profile.zip
|
||||
schema21upgrade_profile.zip
|
||||
schema23upgrade_profile.zip
|
||||
storagePersistentUpgrade_profile.zip
|
||||
xpcshell-shared.ini
|
||||
|
||||
[include:xpcshell-shared.ini]
|
||||
|
@ -27,6 +33,7 @@ support-files =
|
|||
[test_bug1056939.js]
|
||||
[test_cleanup_transaction.js]
|
||||
[test_defaultStorageUpgrade.js]
|
||||
[test_idbSubdirUpgrade.js]
|
||||
[test_globalObjects_ipc.js]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_idle_maintenance.js]
|
||||
|
@ -34,12 +41,16 @@ skip-if = toolkit == 'android'
|
|||
# disabled for the moment.
|
||||
skip-if = true
|
||||
[test_lowDiskSpace.js]
|
||||
[test_metadata2Restore.js]
|
||||
[test_metadataRestore.js]
|
||||
[test_mutableFileUpgrade.js]
|
||||
[test_oldDirectories.js]
|
||||
[test_quotaExceeded_recovery.js]
|
||||
[test_readwriteflush_disabled.js]
|
||||
[test_schema18upgrade.js]
|
||||
[test_schema21upgrade.js]
|
||||
[test_schema23upgrade.js]
|
||||
[test_storagePersistentUpgrade.js]
|
||||
[test_temporary_storage.js]
|
||||
# bug 951017: intermittent failure on Android x86 emulator
|
||||
skip-if = os == "android" && processor == "x86"
|
||||
|
|
|
@ -90,17 +90,13 @@
|
|||
info("blocking browserFrame");
|
||||
event.preventDefault();
|
||||
|
||||
let request = navigator.mozApps.getSelf();
|
||||
request.onsuccess = function() {
|
||||
let app = request.result;
|
||||
ok(app, "got app");
|
||||
let appId = SpecialPowers.wrap(document).nodePrincipal.appId;
|
||||
|
||||
info("clearing browser data");
|
||||
app.clearBrowserData();
|
||||
SpecialPowers.clearAppPrivateData(appId, true);
|
||||
|
||||
info("unblocking browserFrame");
|
||||
event.detail.unblock();
|
||||
}
|
||||
break;
|
||||
case "done":
|
||||
continueToNextStepSync();
|
||||
|
|
|
@ -663,9 +663,10 @@ void AudioClock::UpdateFrameHistory(uint32_t aServiced, uint32_t aUnderrun)
|
|||
mFrameHistory->Append(aServiced, aUnderrun, mOutRate);
|
||||
}
|
||||
|
||||
int64_t AudioClock::GetPositionInFrames(int64_t frames) const
|
||||
int64_t AudioClock::GetPositionInFrames(int64_t aFrames) const
|
||||
{
|
||||
return (GetPosition(frames) * mInRate) / USECS_PER_S;
|
||||
CheckedInt64 v = UsecsToFrames(GetPosition(aFrames), mInRate);
|
||||
return v.isValid() ? v.value() : -1;
|
||||
}
|
||||
|
||||
int64_t AudioClock::GetPosition(int64_t frames) const
|
||||
|
|
|
@ -46,11 +46,11 @@ public:
|
|||
void UpdateFrameHistory(uint32_t aServiced, uint32_t aUnderrun);
|
||||
|
||||
/**
|
||||
* @param frames The playback position in frames of the audio engine.
|
||||
* @param aFrames The playback position in frames of the audio engine.
|
||||
* @return The playback position in frames of the stream,
|
||||
* adjusted by playback rate changes and underrun frames.
|
||||
*/
|
||||
int64_t GetPositionInFrames(int64_t frames) const;
|
||||
int64_t GetPositionInFrames(int64_t aFrames) const;
|
||||
|
||||
/**
|
||||
* @param frames The playback position in frames of the audio engine.
|
||||
|
|
|
@ -626,6 +626,9 @@ AudioCallbackDriver::Init()
|
|||
mGraphImpl->mOutputWanted ? &output : nullptr, latency,
|
||||
DataCallback_s, StateCallback_s, this) == CUBEB_OK) {
|
||||
mAudioStream.own(stream);
|
||||
DebugOnly<int> rv = cubeb_stream_set_volume(mAudioStream, CubebUtils::GetVolumeScale());
|
||||
NS_WARN_IF_FALSE(rv == CUBEB_OK,
|
||||
"Could not set the audio stream volume in GraphDriver.cpp");
|
||||
} else {
|
||||
#ifdef MOZ_WEBRTC
|
||||
StaticMutexAutoUnlock unlock(AudioInputCubeb::Mutex());
|
||||
|
|
|
@ -129,6 +129,7 @@ public:
|
|||
uint64_t aWindowID,
|
||||
const PrincipalHandle& aPrincipalHandle)
|
||||
: mMediaThread(aThread)
|
||||
, mMainThreadCheck(nullptr)
|
||||
, mWindowID(aWindowID)
|
||||
, mPrincipalHandle(aPrincipalHandle)
|
||||
, mStopped(false)
|
||||
|
@ -149,6 +150,7 @@ public:
|
|||
VideoDevice* aVideoDevice)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mMainThreadCheck = PR_GetCurrentThread();
|
||||
mStream = aStream;
|
||||
mAudioDevice = aAudioDevice;
|
||||
mVideoDevice = aVideoDevice;
|
||||
|
@ -274,14 +276,33 @@ public:
|
|||
NotifyEvent(MediaStreamGraph* aGraph,
|
||||
MediaStreamListener::MediaStreamGraphEvent aEvent) override
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
|
||||
switch (aEvent) {
|
||||
case EVENT_FINISHED:
|
||||
NS_DispatchToMainThread(
|
||||
NewRunnableMethod(this, &GetUserMediaCallbackMediaStreamListener::NotifyFinished));
|
||||
rv = NS_GetMainThread(getter_AddRefs(thread));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
NS_ASSERTION(false, "Mainthread not available; running on current thread");
|
||||
// Ensure this really *was* MainThread (NS_GetCurrentThread won't work)
|
||||
MOZ_RELEASE_ASSERT(mMainThreadCheck == PR_GetCurrentThread());
|
||||
NotifyFinished();
|
||||
return;
|
||||
}
|
||||
thread->Dispatch(NewRunnableMethod(this, &GetUserMediaCallbackMediaStreamListener::NotifyFinished),
|
||||
NS_DISPATCH_NORMAL);
|
||||
break;
|
||||
case EVENT_REMOVED:
|
||||
NS_DispatchToMainThread(
|
||||
NewRunnableMethod(this, &GetUserMediaCallbackMediaStreamListener::NotifyRemoved));
|
||||
rv = NS_GetMainThread(getter_AddRefs(thread));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
NS_ASSERTION(false, "Mainthread not available; running on current thread");
|
||||
// Ensure this really *was* MainThread (NS_GetCurrentThread won't work)
|
||||
MOZ_RELEASE_ASSERT(mMainThreadCheck == PR_GetCurrentThread());
|
||||
NotifyRemoved();
|
||||
return;
|
||||
}
|
||||
thread->Dispatch(NewRunnableMethod(this, &GetUserMediaCallbackMediaStreamListener::NotifyRemoved),
|
||||
NS_DISPATCH_NORMAL);
|
||||
break;
|
||||
case EVENT_HAS_DIRECT_LISTENERS:
|
||||
NotifyDirectListeners(aGraph, true);
|
||||
|
@ -308,6 +329,9 @@ public:
|
|||
private:
|
||||
// Set at construction
|
||||
base::Thread* mMediaThread;
|
||||
// never ever indirect off this; just for assertions
|
||||
PRThread* mMainThreadCheck;
|
||||
|
||||
uint64_t mWindowID;
|
||||
const PrincipalHandle mPrincipalHandle;
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ class PeerConnectionMedia;
|
|||
class PeerIdentity;
|
||||
class ProcessedMediaStream;
|
||||
class RemoteSourceStreamInfo;
|
||||
class SourceStreamInfo;
|
||||
|
||||
namespace dom {
|
||||
|
||||
|
@ -228,6 +229,7 @@ class MediaStreamTrack : public DOMEventTargetHelper,
|
|||
// PeerConnection and friends need to know our owning DOMStream and track id.
|
||||
friend class mozilla::PeerConnectionImpl;
|
||||
friend class mozilla::PeerConnectionMedia;
|
||||
friend class mozilla::SourceStreamInfo;
|
||||
friend class mozilla::RemoteSourceStreamInfo;
|
||||
|
||||
class PrincipalHandleListener;
|
||||
|
|
|
@ -39,7 +39,7 @@ TextTrackCue::SetDefaultCueSettings()
|
|||
mSnapToLines = true;
|
||||
mLineIsAutoKeyword = true;
|
||||
mAlign = AlignSetting::Middle;
|
||||
mLineAlign = AlignSetting::Start;
|
||||
mLineAlign = LineAlignSetting::Start;
|
||||
mVertical = DirectionSetting::_empty;
|
||||
mActive = false;
|
||||
}
|
||||
|
|
|
@ -172,19 +172,15 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
AlignSetting LineAlign() const
|
||||
LineAlignSetting LineAlign() const
|
||||
{
|
||||
return mLineAlign;
|
||||
}
|
||||
|
||||
void SetLineAlign(AlignSetting& aLineAlign, ErrorResult& aRv)
|
||||
void SetLineAlign(LineAlignSetting& aLineAlign, ErrorResult& aRv)
|
||||
{
|
||||
if (mLineAlign == aLineAlign)
|
||||
if (mLineAlign == aLineAlign) {
|
||||
return;
|
||||
|
||||
if (aLineAlign == AlignSetting::Left ||
|
||||
aLineAlign == AlignSetting::Right) {
|
||||
return aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
}
|
||||
|
||||
mReset = true;
|
||||
|
@ -364,7 +360,7 @@ private:
|
|||
bool mLineIsAutoKeyword;
|
||||
long mLineLong;
|
||||
AlignSetting mAlign;
|
||||
AlignSetting mLineAlign;
|
||||
LineAlignSetting mLineAlign;
|
||||
|
||||
// Holds the computed DOM elements that represent the parsed cue text.
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#text-track-cue-display-state
|
||||
|
|
|
@ -212,21 +212,34 @@ navigator.requestMediaKeySystemAccess('com.adobe.primetime',
|
|||
"""
|
||||
|
||||
|
||||
reset_widevine_gmp_script = """
|
||||
navigator.requestMediaKeySystemAccess('com.widevine.alpha',
|
||||
[{initDataTypes: ['cenc']}]).then(
|
||||
function(access) {
|
||||
marionetteScriptFinished('success');
|
||||
},
|
||||
function(ex) {
|
||||
marionetteScriptFinished(ex);
|
||||
}
|
||||
);
|
||||
"""
|
||||
|
||||
|
||||
class EMESetupMixin(object):
|
||||
|
||||
"""
|
||||
An object that needs to use the Adobe GMP system must inherit from this
|
||||
class, and then call check_eme_system() to insure that everything is
|
||||
setup correctly.
|
||||
An object that needs to use the Adobe or Widevine GMP system must inherit
|
||||
from this class, and then call check_eme_system() to insure that everything
|
||||
is setup correctly.
|
||||
"""
|
||||
|
||||
version_needs_reset = True
|
||||
|
||||
def check_eme_system(self):
|
||||
"""
|
||||
Download the most current version of the Adobe GMP Plugin. Verify
|
||||
that all MSE and EME prefs are set correctly. Raises if things
|
||||
are not OK.
|
||||
Download the most current version of the Adobe and Widevine GMP
|
||||
Plugins. Verify that all MSE and EME prefs are set correctly. Raises
|
||||
if things are not OK.
|
||||
"""
|
||||
self.set_eme_prefs()
|
||||
self.reset_GMP_version()
|
||||
|
@ -244,13 +257,21 @@ class EMESetupMixin(object):
|
|||
with self.marionette.using_context('chrome'):
|
||||
if self.prefs.get_pref('media.gmp-eme-adobe.version'):
|
||||
self.prefs.reset_pref('media.gmp-eme-adobe.version')
|
||||
if self.prefs.get_pref('media.gmp-widevinecdm.version'):
|
||||
self.prefs.reset_pref('media.gmp-widevinecdm.version')
|
||||
with self.marionette.using_context('content'):
|
||||
result = self.marionette.execute_async_script(
|
||||
adobe_result = self.marionette.execute_async_script(
|
||||
reset_adobe_gmp_script,
|
||||
script_timeout=60000)
|
||||
if not result == 'success':
|
||||
widevine_result = self.marionette.execute_async_script(
|
||||
reset_widevine_gmp_script,
|
||||
script_timeout=60000)
|
||||
if not adobe_result == 'success':
|
||||
raise VideoException(
|
||||
'ERROR: Resetting Adobe GMP failed % s' % result)
|
||||
if not widevine_result == 'success':
|
||||
raise VideoException(
|
||||
'ERROR: Resetting Widevine GMP failed % s' % result)
|
||||
|
||||
EMESetupMixin.version_needs_reset = False
|
||||
|
||||
|
@ -287,20 +308,50 @@ class EMESetupMixin(object):
|
|||
|
||||
return pref_value >= minimum_value
|
||||
|
||||
def chceck_and_log_version_string_pref(self, pref_name, minimum_value='0'):
|
||||
"""
|
||||
Compare a pref made up of integers separated by stops .s, with a
|
||||
version string of the same format. The number of integers in each string
|
||||
does not need to match. The comparison is done by converting each to an
|
||||
integer array and comparing those. Both version strings must be made
|
||||
up of only integers, or this method will raise an unhandled exception
|
||||
of type ValueError when the conversion to int fails.
|
||||
"""
|
||||
with self.marionette.using_context('chrome'):
|
||||
pref_value = self.prefs.get_pref(pref_name)
|
||||
|
||||
if pref_value is None:
|
||||
self.logger.info('Pref %s has no value.' % pref_name)
|
||||
return False
|
||||
else:
|
||||
self.logger.info('Pref %s = %s' % (pref_name, pref_value))
|
||||
|
||||
match = re.search('^\d(.\d+)*$', pref_value)
|
||||
if not match:
|
||||
self.logger.info('Pref %s is not a version string' % pref_name)
|
||||
return False
|
||||
|
||||
pref_ints = [int(n) for n in pref_value.split('.')]
|
||||
minumum_ints = [int(n) for n in minimum_value.split('.')]
|
||||
|
||||
return pref_ints >= minumum_ints
|
||||
|
||||
|
||||
def check_eme_prefs(self):
|
||||
with self.marionette.using_context('chrome'):
|
||||
prefs_ok = self.check_and_log_boolean_pref(
|
||||
'media.mediasource.enabled', True)
|
||||
prefs_ok = self.check_and_log_boolean_pref(
|
||||
'media.eme.enabled', True) and prefs_ok
|
||||
prefs_ok = self.check_and_log_boolean_pref(
|
||||
'media.mediasource.mp4.enabled', True) and prefs_ok
|
||||
prefs_ok = self.check_and_log_boolean_pref(
|
||||
'media.gmp-eme-adobe.enabled', True) and prefs_ok
|
||||
prefs_ok = self.check_and_log_integer_pref(
|
||||
'media.gmp-eme-adobe.version', 1) and prefs_ok
|
||||
|
||||
return prefs_ok
|
||||
|
||||
|
||||
|
||||
return all([
|
||||
self.check_and_log_boolean_pref(
|
||||
'media.mediasource.enabled', True),
|
||||
self.check_and_log_boolean_pref(
|
||||
'media.eme.enabled', True),
|
||||
self.check_and_log_boolean_pref(
|
||||
'media.mediasource.mp4.enabled', True),
|
||||
self.check_and_log_boolean_pref(
|
||||
'media.gmp-eme-adobe.enabled', True),
|
||||
self.check_and_log_integer_pref(
|
||||
'media.gmp-eme-adobe.version', 1),
|
||||
self.check_and_log_boolean_pref(
|
||||
'media.gmp-widevinecdm.enabled', True),
|
||||
self.chceck_and_log_version_string_pref(
|
||||
'media.gmp-widevinecdm.version', '1.0.0.0')
|
||||
])
|
||||
|
|
|
@ -128,33 +128,13 @@ SpecialPowers.pushPrefEnv({"set": [["media.webvtt.regions.enabled", true]]},
|
|||
}
|
||||
|
||||
checkEnumValue("align", "middle", [ "start", "left", "middle", "right", "end" ]);
|
||||
checkEnumValue("lineAlign", "start", [ "start", "center", "end" ]);
|
||||
checkEnumValue("vertical", "", [ "", "lr", "rl" ]);
|
||||
|
||||
// Check that cue line align works properly
|
||||
is(cue.lineAlign, "start", "Cue's default line alignment should be start.");
|
||||
|
||||
exceptionHappened = false;
|
||||
try {
|
||||
cue.lineAlign = "left";
|
||||
} catch(e) {
|
||||
exceptionHappened = true;
|
||||
is(e.name, "SyntaxError", "Should have thrown SyntaxError.");
|
||||
}
|
||||
ok(exceptionHappened, "Exception should have happened.");
|
||||
|
||||
exceptionHappened = false;
|
||||
try {
|
||||
cue.lineAlign = "right";
|
||||
} catch(e) {
|
||||
exceptionHappened = true;
|
||||
is(e.name, "SyntaxError", "Should have thrown SyntaxError.");
|
||||
}
|
||||
ok(exceptionHappened, "Exception should have happened.");
|
||||
|
||||
cue.lineAlign = "middle";
|
||||
is(cue.lineAlign, "middle", "Cue's line align should be middle.");
|
||||
cue.lineAlign = "center";
|
||||
is(cue.lineAlign, "center", "Cue's line align should be center.");
|
||||
cue.lineAlign = "START";
|
||||
is(cue.lineAlign, "middle", "Cue's line align should be middle.");
|
||||
is(cue.lineAlign, "center", "Cue's line align should be center.");
|
||||
cue.lineAlign = "end";
|
||||
is(cue.lineAlign, "end", "Cue's line align should be end.");
|
||||
|
||||
|
|
|
@ -204,7 +204,7 @@ this.EXPORTED_SYMBOLS = ["WebVTT"];
|
|||
settings.percent(k, vals0) ? settings.set("snapToLines", false) : null;
|
||||
settings.alt(k, vals0, ["auto"]);
|
||||
if (vals.length === 2) {
|
||||
settings.alt("lineAlign", vals[1], ["start", "middle", "end"]);
|
||||
settings.alt("lineAlign", vals[1], ["start", "center", "end"]);
|
||||
}
|
||||
break;
|
||||
case "position":
|
||||
|
@ -1076,7 +1076,7 @@ this.EXPORTED_SYMBOLS = ["WebVTT"];
|
|||
var calculatedPercentage = (boxPosition.lineHeight / containerBox.height) * 100;
|
||||
|
||||
switch (cue.lineAlign) {
|
||||
case "middle":
|
||||
case "center":
|
||||
linePos -= (calculatedPercentage / 2);
|
||||
break;
|
||||
case "end":
|
||||
|
|
|
@ -99,18 +99,6 @@ interface nsIPluginHost : nsISupports
|
|||
ACString getPermissionStringForType(in AUTF8String mimeType,
|
||||
[optional] in uint32_t excludeFlags);
|
||||
|
||||
/**
|
||||
* Get the "permission string" for the plugin. This is a string that can be
|
||||
* passed to the permission manager to see whether the plugin is allowed to
|
||||
* run, for example. This will typically be based on the plugin's "nice name"
|
||||
* and its blocklist state.
|
||||
*
|
||||
* @tag The tage we're interested in
|
||||
* @excludeFlags Set of the EXCLUDE_* flags above, defaulting to EXCLUDE_NONE.
|
||||
*/
|
||||
ACString getPermissionStringForTag(in nsIPluginTag tag,
|
||||
[optional] in uint32_t excludeFlags);
|
||||
|
||||
/**
|
||||
* Get the nsIPluginTag for this MIME type. This method works with both
|
||||
* enabled and disabled/blocklisted plugins, but an enabled plugin will
|
||||
|
|
|
@ -1110,19 +1110,11 @@ nsPluginHost::GetPermissionStringForType(const nsACString &aMimeType,
|
|||
nsresult rv = GetPluginTagForType(aMimeType, aExcludeFlags,
|
||||
getter_AddRefs(tag));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return GetPermissionStringForTag(tag, aExcludeFlags, aPermissionString);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPluginHost::GetPermissionStringForTag(nsIPluginTag* aTag,
|
||||
uint32_t aExcludeFlags,
|
||||
nsACString &aPermissionString)
|
||||
{
|
||||
NS_ENSURE_TRUE(aTag, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(tag, NS_ERROR_FAILURE);
|
||||
|
||||
aPermissionString.Truncate();
|
||||
uint32_t blocklistState;
|
||||
nsresult rv = aTag->GetBlocklistState(&blocklistState);
|
||||
rv = tag->GetBlocklistState(&blocklistState);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (blocklistState == nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE ||
|
||||
|
@ -1134,7 +1126,7 @@ nsPluginHost::GetPermissionStringForTag(nsIPluginTag* aTag,
|
|||
}
|
||||
|
||||
nsCString niceName;
|
||||
rv = aTag->GetNiceName(niceName);
|
||||
rv = tag->GetNiceName(niceName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(!niceName.IsEmpty(), NS_ERROR_FAILURE);
|
||||
|
||||
|
|
|
@ -886,16 +886,16 @@ nsPluginInstanceOwner::GetCompositionString(uint32_t aType,
|
|||
for (TextRange& range : *ranges) {
|
||||
uint8_t type = ATTR_INPUT;
|
||||
switch(range.mRangeType) {
|
||||
case NS_TEXTRANGE_RAWINPUT:
|
||||
case TextRangeType::eRawClause:
|
||||
type = ATTR_INPUT;
|
||||
break;
|
||||
case NS_TEXTRANGE_SELECTEDRAWTEXT:
|
||||
case TextRangeType::eSelectedRawClause:
|
||||
type = ATTR_TARGET_NOTCONVERTED;
|
||||
break;
|
||||
case NS_TEXTRANGE_CONVERTEDTEXT:
|
||||
case TextRangeType::eConvertedClause:
|
||||
type = ATTR_CONVERTED;
|
||||
break;
|
||||
case NS_TEXTRANGE_SELECTEDCONVERTEDTEXT:
|
||||
case TextRangeType::eSelectedClause:
|
||||
type = ATTR_TARGET_CONVERTED;
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -323,7 +323,7 @@ nsPluginTag::~nsPluginTag()
|
|||
NS_ASSERTION(!mNext, "Risk of exhausting the stack space, bug 486349");
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsPluginTag, nsPluginTag, nsIInternalPluginTag, nsIPluginTag)
|
||||
NS_IMPL_ISUPPORTS(nsPluginTag, nsIPluginTag, nsIInternalPluginTag)
|
||||
|
||||
void nsPluginTag::InitMime(const char* const* aMimeTypes,
|
||||
const char* const* aMimeDescriptions,
|
||||
|
|
|
@ -31,9 +31,6 @@ struct FakePluginTagInit;
|
|||
{ 0xe8fdd227, 0x27da, 0x46ee, \
|
||||
{ 0xbe, 0xf3, 0x1a, 0xef, 0x5a, 0x8f, 0xc5, 0xb4 } }
|
||||
|
||||
#define NS_PLUGINTAG_IID \
|
||||
{ 0xcce2e8b9, 0x9702, 0x4d4b, \
|
||||
{ 0xbe, 0xa4, 0x7c, 0x1e, 0x13, 0x1f, 0xaf, 0x78 } }
|
||||
class nsIInternalPluginTag : public nsIPluginTag
|
||||
{
|
||||
public:
|
||||
|
@ -94,8 +91,6 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIInternalPluginTag, NS_IINTERNALPLUGINTAG_IID)
|
|||
class nsPluginTag final : public nsIInternalPluginTag
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_PLUGINTAG_IID)
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIPLUGINTAG
|
||||
|
||||
|
@ -198,7 +193,6 @@ private:
|
|||
|
||||
static uint32_t sNextId;
|
||||
};
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsPluginTag, NS_PLUGINTAG_IID)
|
||||
|
||||
// A class representing "fake" plugin tags; that is plugin tags not
|
||||
// corresponding to actual NPAPI plugins. In practice these are all
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "DCPresentationChannelDescription.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS(DCPresentationChannelDescription,
|
||||
nsIPresentationChannelDescription)
|
||||
|
||||
NS_IMETHODIMP
|
||||
DCPresentationChannelDescription::GetType(uint8_t* aRetVal)
|
||||
{
|
||||
if (NS_WARN_IF(!aRetVal)) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
|
||||
*aRetVal = nsIPresentationChannelDescription::TYPE_DATACHANNEL;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DCPresentationChannelDescription::GetTcpAddress(nsIArray** aRetVal)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DCPresentationChannelDescription::GetTcpPort(uint16_t* aRetVal)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DCPresentationChannelDescription::GetDataChannelSDP(nsAString& aDataChannelSDP)
|
||||
{
|
||||
aDataChannelSDP = mSDP;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,37 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_DCPresentationChannelDescription_h
|
||||
#define mozilla_dom_DCPresentationChannelDescription_h
|
||||
|
||||
#include "nsIPresentationControlChannel.h"
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// PresentationChannelDescription for Data Channel
|
||||
class DCPresentationChannelDescription final : public nsIPresentationChannelDescription
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIPRESENTATIONCHANNELDESCRIPTION
|
||||
|
||||
explicit DCPresentationChannelDescription(const nsAString& aSDP)
|
||||
: mSDP(aSDP)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~DCPresentationChannelDescription() = default;
|
||||
|
||||
nsString mSDP;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_DCPresentationChannelDescription_h
|
|
@ -49,11 +49,10 @@ PresentationTransportBuilder.prototype = {
|
|||
classID: PRESENTATIONTRANSPORTBUILDER_CID,
|
||||
contractID: PRESENTATIONTRANSPORTBUILDER_CONTRACTID,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDataChannelSessionTransportBuilder,
|
||||
Ci.nsIPresentationControlChannelListener,
|
||||
Ci.nsITimerCallback]),
|
||||
|
||||
buildDataChannelTransport: function(aRole, aWindow, aControlChannel, aListener) {
|
||||
if (!aRole || !aWindow || !aControlChannel || !aListener) {
|
||||
buildDataChannelTransport: function(aRole, aWindow, aListener) {
|
||||
if (!aRole || !aWindow || !aListener) {
|
||||
log("buildDataChannelTransport with illegal parameters");
|
||||
throw Cr.NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
@ -66,23 +65,21 @@ PresentationTransportBuilder.prototype = {
|
|||
log("buildDataChannelTransport with role " + aRole);
|
||||
this._role = aRole;
|
||||
this._window = aWindow;
|
||||
this._controlChannel = aControlChannel.QueryInterface(Ci.nsIPresentationControlChannel);
|
||||
this._controlChannel.listener = this;
|
||||
this._listener = aListener.QueryInterface(Ci.nsIPresentationSessionTransportBuilderListener);
|
||||
|
||||
// TODO bug 1227053 set iceServers from |nsIPresentationDevice|
|
||||
this._peerConnection = new this._window.RTCPeerConnection();
|
||||
|
||||
// |this._controlChannel == null| will throw since the control channel is
|
||||
// |this._listener == null| will throw since the control channel is
|
||||
// abnormally closed.
|
||||
this._peerConnection.onicecandidate = aEvent => aEvent.candidate &&
|
||||
this._controlChannel.sendIceCandidate(JSON.stringify(aEvent.candidate));
|
||||
this._listener.sendIceCandidate(JSON.stringify(aEvent.candidate));
|
||||
|
||||
this._peerConnection.onnegotiationneeded = () => {
|
||||
log("onnegotiationneeded with role " + this._role);
|
||||
this._peerConnection.createOffer()
|
||||
.then(aOffer => this._peerConnection.setLocalDescription(aOffer))
|
||||
.then(() => this._controlChannel
|
||||
.then(() => this._listener
|
||||
.sendOffer(new PresentationDataChannelDescription(this._peerConnection.localDescription)))
|
||||
.catch(e => this._reportError(e));
|
||||
}
|
||||
|
@ -169,11 +166,6 @@ PresentationTransportBuilder.prototype = {
|
|||
this._role = null;
|
||||
this._window = null;
|
||||
|
||||
if (this._controlChannel) {
|
||||
this._controlChannel.close(aReason);
|
||||
this._controlChannel = null;
|
||||
}
|
||||
|
||||
this._listener = null;
|
||||
this._sessionTransport = null;
|
||||
|
||||
|
@ -202,7 +194,7 @@ PresentationTransportBuilder.prototype = {
|
|||
.then(aAnswer => this._peerConnection.setLocalDescription(aAnswer))
|
||||
.then(() => {
|
||||
this._isControlChannelNeeded = false;
|
||||
this._controlChannel
|
||||
this._listener
|
||||
.sendAnswer(new PresentationDataChannelDescription(this._peerConnection.localDescription))
|
||||
}).catch(e => this._reportError(e));
|
||||
},
|
||||
|
@ -229,10 +221,6 @@ PresentationTransportBuilder.prototype = {
|
|||
this._peerConnection.addIceCandidate(candidate).catch(e => this._reportError(e));
|
||||
},
|
||||
|
||||
notifyOpened: function() {
|
||||
log("notifyOpened, should be opened beforehand");
|
||||
},
|
||||
|
||||
notifyClosed: function(aReason) {
|
||||
log("notifyClosed reason: " + aReason);
|
||||
|
||||
|
@ -241,7 +229,6 @@ PresentationTransportBuilder.prototype = {
|
|||
} else if (this._isControlChannelNeeded) {
|
||||
this._cleanup(Cr.NS_ERROR_FAILURE);
|
||||
}
|
||||
this._controlChannel = null;
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -618,6 +618,25 @@ PresentationService::UnregisterSessionListener(const nsAString& aSessionId,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationService::RegisterTransportBuilder(const nsAString& aSessionId,
|
||||
uint8_t aRole,
|
||||
nsIPresentationSessionTransportBuilder* aBuilder)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aBuilder);
|
||||
MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
|
||||
aRole == nsIPresentationService::ROLE_RECEIVER);
|
||||
|
||||
RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
|
||||
if (NS_WARN_IF(!info)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
info->SetBuilder(aBuilder);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationService::RegisterRespondingListener(
|
||||
uint64_t aWindowId,
|
||||
|
@ -683,6 +702,23 @@ PresentationService::NotifyReceiverReady(const nsAString& aSessionId,
|
|||
return static_cast<PresentationPresentingInfo*>(info.get())->NotifyResponderReady();
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationService::NotifyTransportClosed(const nsAString& aSessionId,
|
||||
uint8_t aRole,
|
||||
nsresult aReason) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
|
||||
aRole == nsIPresentationService::ROLE_RECEIVER);
|
||||
|
||||
RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
|
||||
if (NS_WARN_IF(!info)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return info->NotifyTransportClosed(aReason);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationService::UntrackSessionInfo(const nsAString& aSessionId,
|
||||
uint8_t aRole)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
class nsIPresentationSessionRequest;
|
||||
class nsIURI;
|
||||
class nsIPresentationSessionTransportBuilder;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -54,6 +55,10 @@ public:
|
|||
const uint8_t aRole,
|
||||
base::ProcessId aProcessId);
|
||||
|
||||
nsresult RegisterTransportBuilder(const nsAString& aSessionId,
|
||||
uint8_t aRole,
|
||||
nsIPresentationSessionTransportBuilder* aBuilder);
|
||||
|
||||
private:
|
||||
friend class PresentationDeviceRequest;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef mozilla_dom_PresentationServiceBase_h
|
||||
#define mozilla_dom_PresentationServiceBase_h
|
||||
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
|
|
|
@ -237,7 +237,7 @@ PresentationSessionInfo::Shutdown(nsresult aReason)
|
|||
|
||||
mIsResponderReady = false;
|
||||
|
||||
mBuilder = nullptr;
|
||||
SetBuilder(nullptr);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -350,6 +350,11 @@ PresentationSessionInfo::NotifyTransportReady()
|
|||
|
||||
mIsTransportReady = true;
|
||||
|
||||
// Established RTCDataChannel implies responder is ready.
|
||||
if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
|
||||
mIsResponderReady = true;
|
||||
}
|
||||
|
||||
// At sender side, session might not be ready at this point (waiting for
|
||||
// receiver's answer). Yet at receiver side, session must be ready at this
|
||||
// point since the data transport channel is created after the receiver page
|
||||
|
@ -413,6 +418,13 @@ PresentationSessionInfo::NotifyData(const nsACString& aData)
|
|||
NS_IMETHODIMP
|
||||
PresentationSessionInfo::OnSessionTransport(nsIPresentationSessionTransport* transport)
|
||||
{
|
||||
SetBuilder(nullptr);
|
||||
|
||||
// The session transport is managed by content process
|
||||
if (!transport) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mTransport = transport;
|
||||
|
||||
nsresult rv = mTransport->SetCallback(this);
|
||||
|
@ -430,9 +442,34 @@ PresentationSessionInfo::OnSessionTransport(nsIPresentationSessionTransport* tra
|
|||
NS_IMETHODIMP
|
||||
PresentationSessionInfo::OnError(nsresult reason)
|
||||
{
|
||||
SetBuilder(nullptr);
|
||||
return ReplyError(reason);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationSessionInfo::SendOffer(nsIPresentationChannelDescription* aOffer)
|
||||
{
|
||||
return mControlChannel->SendOffer(aOffer);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationSessionInfo::SendAnswer(nsIPresentationChannelDescription* aAnswer)
|
||||
{
|
||||
return mControlChannel->SendAnswer(aAnswer);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationSessionInfo::SendIceCandidate(const nsAString& candidate)
|
||||
{
|
||||
return mControlChannel->SendIceCandidate(candidate);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationSessionInfo::Close(nsresult reason)
|
||||
{
|
||||
return mControlChannel->Close(reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of PresentationControllingInfo
|
||||
*
|
||||
|
@ -577,13 +614,6 @@ PresentationControllingInfo::GetAddress()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationControllingInfo::OnIceCandidate(const nsAString& aCandidate)
|
||||
{
|
||||
MOZ_ASSERT(false, "Should not receive ICE candidates.");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationControllingInfo::OnGetAddress(const nsACString& aAddress)
|
||||
{
|
||||
|
@ -602,6 +632,23 @@ PresentationControllingInfo::OnGetAddress(const nsACString& aAddress)
|
|||
}
|
||||
|
||||
// nsIPresentationControlChannelListener
|
||||
NS_IMETHODIMP
|
||||
PresentationControllingInfo::OnIceCandidate(const nsAString& aCandidate)
|
||||
{
|
||||
if (mTransportType != nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
|
||||
builder = do_QueryInterface(mBuilder);
|
||||
|
||||
if (NS_WARN_IF(!builder)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return builder->OnIceCandidate(aCandidate);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationControllingInfo::OnOffer(nsIPresentationChannelDescription* aDescription)
|
||||
{
|
||||
|
@ -612,6 +659,17 @@ PresentationControllingInfo::OnOffer(nsIPresentationChannelDescription* aDescrip
|
|||
NS_IMETHODIMP
|
||||
PresentationControllingInfo::OnAnswer(nsIPresentationChannelDescription* aDescription)
|
||||
{
|
||||
if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
|
||||
nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
|
||||
builder = do_QueryInterface(mBuilder);
|
||||
|
||||
if (NS_WARN_IF(!builder)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return builder->OnAnswer(aDescription);
|
||||
}
|
||||
|
||||
mIsResponderReady = true;
|
||||
|
||||
// Close the control channel since it's no longer needed.
|
||||
|
@ -639,21 +697,48 @@ PresentationControllingInfo::NotifyOpened()
|
|||
return GetAddress();
|
||||
}
|
||||
|
||||
nsPIDOMWindowInner* window = nullptr;
|
||||
/**
|
||||
* Generally transport is maintained by the chrome process. However, data
|
||||
* channel should be live with the DOM , which implies RTCDataChannel in an OOP
|
||||
* page should be establish in the content process.
|
||||
*
|
||||
* In OOP data channel transport case, |mBuilder| is hooked when the content
|
||||
* process is ready to build a data channel transport, trigger by:
|
||||
* 1. PresentationIPCService::StartSession (sender)
|
||||
* 2. PresentationIPCService::NotifyReceiverReady (receiver).
|
||||
*
|
||||
* In this case, |mBuilder| would be an object of |PresentationBuilderParent|
|
||||
* and set previously. Therefore, |BuildDataChannelTransport| triggers an IPC
|
||||
* call to make content process establish a RTCDataChannel transport.
|
||||
*/
|
||||
// in-process case
|
||||
if (!mBuilder) {
|
||||
nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder> builder =
|
||||
do_CreateInstance("@mozilla.org/presentation/datachanneltransportbuilder;1");
|
||||
|
||||
if (NS_WARN_IF(!builder)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mBuilder = builder;
|
||||
SetBuilder(builder);
|
||||
// OOP window would be set from content process
|
||||
window = GetWindow();
|
||||
}
|
||||
// OOP case
|
||||
mTransportType = nsIPresentationChannelDescription::TYPE_DATACHANNEL;
|
||||
|
||||
return builder->BuildDataChannelTransport(nsIPresentationService::ROLE_CONTROLLER,
|
||||
GetWindow(),
|
||||
mControlChannel,
|
||||
nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
|
||||
dataChannelBuilder(do_QueryInterface(mBuilder));
|
||||
if (NS_WARN_IF(!dataChannelBuilder)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
nsresult rv = dataChannelBuilder->
|
||||
BuildDataChannelTransport(nsIPresentationService::ROLE_CONTROLLER,
|
||||
window,
|
||||
this);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -661,6 +746,14 @@ PresentationControllingInfo::NotifyClosed(nsresult aReason)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
|
||||
nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
|
||||
builder = do_QueryInterface(mBuilder);
|
||||
if (builder) {
|
||||
NS_WARN_IF(NS_FAILED(builder->NotifyClosed(aReason)));
|
||||
}
|
||||
}
|
||||
|
||||
// Unset control channel here so it won't try to re-close it in potential
|
||||
// subsequent |Shutdown| calls.
|
||||
SetControlChannel(nullptr);
|
||||
|
@ -784,6 +877,7 @@ PresentationPresentingInfo::Shutdown(nsresult aReason)
|
|||
mDevice = nullptr;
|
||||
mLoadingCallback = nullptr;
|
||||
mRequesterDescription = nullptr;
|
||||
mPendingCandidates.Clear();
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
|
@ -797,6 +891,11 @@ PresentationPresentingInfo::OnSessionTransport(nsIPresentationSessionTransport*
|
|||
return rv;
|
||||
}
|
||||
|
||||
// The session transport is managed by content process
|
||||
if (!transport) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// send answer for TCP session transport
|
||||
if (mTransportType == nsIPresentationChannelDescription::TYPE_TCP) {
|
||||
// Prepare and send the answer.
|
||||
|
@ -823,10 +922,26 @@ PresentationPresentingInfo::OnSessionTransport(nsIPresentationSessionTransport*
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Delegate the pending offer and ICE candidates to builder.
|
||||
NS_IMETHODIMP
|
||||
PresentationPresentingInfo::OnError(nsresult reason)
|
||||
PresentationPresentingInfo::FlushPendingEvents(nsIPresentationDataChannelSessionTransportBuilder* builder)
|
||||
{
|
||||
return PresentationSessionInfo::OnError(reason);
|
||||
if (NS_WARN_IF(!builder)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mHasFlushPendingEvents = true;
|
||||
|
||||
if (mRequesterDescription) {
|
||||
builder->OnOffer(mRequesterDescription);
|
||||
}
|
||||
mRequesterDescription = nullptr;
|
||||
|
||||
for (size_t i = 0; i < mPendingCandidates.Length(); ++i) {
|
||||
builder->OnIceCandidate(mPendingCandidates[i]);
|
||||
}
|
||||
mPendingCandidates.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -849,7 +964,7 @@ PresentationPresentingInfo::InitTransportAndSendAnswer()
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mBuilder = builder;
|
||||
SetBuilder(builder);
|
||||
mTransportType = nsIPresentationChannelDescription::TYPE_TCP;
|
||||
return builder->BuildTCPReceiverTransport(mRequesterDescription, this);
|
||||
}
|
||||
|
@ -858,6 +973,24 @@ PresentationPresentingInfo::InitTransportAndSendAnswer()
|
|||
if (!Preferences::GetBool("dom.presentation.session_transport.data_channel.enable")) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
nsPIDOMWindowInner* window = nullptr;
|
||||
|
||||
/**
|
||||
* Generally transport is maintained by the chrome process. However, data
|
||||
* channel should be live with the DOM , which implies RTCDataChannel in an OOP
|
||||
* page should be establish in the content process.
|
||||
*
|
||||
* In OOP data channel transport case, |mBuilder| is hooked when the content
|
||||
* process is ready to build a data channel transport, trigger by:
|
||||
* 1. PresentationIPCService::StartSession (sender)
|
||||
* 2. PresentationIPCService::NotifyReceiverReady (receiver).
|
||||
*
|
||||
* In this case, |mBuilder| would be an object of |PresentationBuilderParent|
|
||||
* and set previously. Therefore, |BuildDataChannelTransport| triggers an IPC
|
||||
* call to make content process establish a RTCDataChannel transport.
|
||||
*/
|
||||
// in-process case
|
||||
if (!mBuilder) {
|
||||
nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder> builder =
|
||||
do_CreateInstance("@mozilla.org/presentation/datachanneltransportbuilder;1");
|
||||
|
||||
|
@ -865,24 +998,32 @@ PresentationPresentingInfo::InitTransportAndSendAnswer()
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mBuilder = builder;
|
||||
SetBuilder(builder);
|
||||
|
||||
// OOP window would be set from content process
|
||||
window = GetWindow();
|
||||
}
|
||||
mTransportType = nsIPresentationChannelDescription::TYPE_DATACHANNEL;
|
||||
rv = builder->BuildDataChannelTransport(nsIPresentationService::ROLE_RECEIVER,
|
||||
GetWindow(),
|
||||
mControlChannel,
|
||||
|
||||
nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
|
||||
dataChannelBuilder(do_QueryInterface(mBuilder));
|
||||
if (NS_WARN_IF(!dataChannelBuilder)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
rv = dataChannelBuilder->
|
||||
BuildDataChannelTransport(nsIPresentationService::ROLE_RECEIVER,
|
||||
window,
|
||||
this);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// delegate |onOffer| to builder
|
||||
nsCOMPtr<nsIPresentationControlChannelListener> listener(do_QueryInterface(builder));
|
||||
|
||||
if (NS_WARN_IF(!listener)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
rv = this->FlushPendingEvents(dataChannelBuilder);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return listener->OnOffer(mRequesterDescription);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "Unknown nsIPresentationChannelDescription type!");
|
||||
|
@ -943,6 +1084,10 @@ PresentationPresentingInfo::NotifyResponderReady()
|
|||
NS_IMETHODIMP
|
||||
PresentationPresentingInfo::OnOffer(nsIPresentationChannelDescription* aDescription)
|
||||
{
|
||||
if (NS_WARN_IF(mHasFlushPendingEvents)) {
|
||||
return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!aDescription)) {
|
||||
return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
|
@ -971,10 +1116,21 @@ PresentationPresentingInfo::OnAnswer(nsIPresentationChannelDescription* aDescrip
|
|||
NS_IMETHODIMP
|
||||
PresentationPresentingInfo::OnIceCandidate(const nsAString& aCandidate)
|
||||
{
|
||||
MOZ_ASSERT(false, "Should not receive ICE candidates.");
|
||||
if (!mBuilder && !mHasFlushPendingEvents) {
|
||||
mPendingCandidates.AppendElement(nsString(aCandidate));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mBuilder && mHasFlushPendingEvents)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
|
||||
builder = do_QueryInterface(mBuilder);
|
||||
|
||||
return builder->OnIceCandidate(aCandidate);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationPresentingInfo::NotifyOpened()
|
||||
{
|
||||
|
@ -987,6 +1143,14 @@ PresentationPresentingInfo::NotifyClosed(nsresult aReason)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
|
||||
nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
|
||||
builder = do_QueryInterface(mBuilder);
|
||||
if (builder) {
|
||||
NS_WARN_IF(NS_FAILED(builder->NotifyClosed(aReason)));
|
||||
}
|
||||
}
|
||||
|
||||
// Unset control channel here so it won't try to re-close it in potential
|
||||
// subsequent |Shutdown| calls.
|
||||
SetControlChannel(nullptr);
|
||||
|
|
|
@ -77,6 +77,11 @@ public:
|
|||
mDevice = aDevice;
|
||||
}
|
||||
|
||||
void SetBuilder(nsIPresentationSessionTransportBuilder* aBuilder)
|
||||
{
|
||||
mBuilder = aBuilder;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIPresentationDevice> GetDevice() const
|
||||
{
|
||||
nsCOMPtr<nsIPresentationDevice> device = mDevice;
|
||||
|
@ -114,7 +119,10 @@ protected:
|
|||
|
||||
nsresult ReplySuccess();
|
||||
|
||||
virtual bool IsSessionReady() = 0;
|
||||
bool IsSessionReady()
|
||||
{
|
||||
return mIsResponderReady && mIsTransportReady;
|
||||
}
|
||||
|
||||
virtual nsresult UntrackFromService();
|
||||
|
||||
|
@ -186,18 +194,6 @@ private:
|
|||
nsresult OnGetAddress(const nsACString& aAddress);
|
||||
|
||||
nsCOMPtr<nsIServerSocket> mServerSocket;
|
||||
|
||||
protected:
|
||||
bool IsSessionReady() override
|
||||
{
|
||||
if (mTransportType == nsIPresentationChannelDescription::TYPE_TCP) {
|
||||
return mIsResponderReady && mIsTransportReady;
|
||||
} else if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
|
||||
// Established RTCDataChannel implies responder is ready.
|
||||
return mIsTransportReady;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Session info with presenting browsing context (receiver side) behaviors.
|
||||
|
@ -208,7 +204,6 @@ class PresentationPresentingInfo final : public PresentationSessionInfo
|
|||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIPRESENTATIONCONTROLCHANNELLISTENER
|
||||
NS_DECL_NSIPRESENTATIONSESSIONTRANSPORTBUILDERLISTENER
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
PresentationPresentingInfo(const nsAString& aUrl,
|
||||
|
@ -226,6 +221,8 @@ public:
|
|||
|
||||
nsresult NotifyResponderReady();
|
||||
|
||||
NS_IMETHODIMP OnSessionTransport(nsIPresentationSessionTransport* transport) override;
|
||||
|
||||
void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
|
||||
|
||||
void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
|
||||
|
@ -250,20 +247,19 @@ private:
|
|||
|
||||
nsresult UntrackFromService() override;
|
||||
|
||||
NS_IMETHODIMP
|
||||
FlushPendingEvents(nsIPresentationDataChannelSessionTransportBuilder* builder);
|
||||
|
||||
bool mHasFlushPendingEvents = false;
|
||||
RefPtr<PresentationResponderLoadingCallback> mLoadingCallback;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
nsCOMPtr<nsIPresentationChannelDescription> mRequesterDescription;
|
||||
nsTArray<nsString> mPendingCandidates;
|
||||
RefPtr<Promise> mPromise;
|
||||
|
||||
// The content parent communicating with the content process which the OOP
|
||||
// receiver page belongs to.
|
||||
nsCOMPtr<nsIContentParent> mContentParent;
|
||||
|
||||
protected:
|
||||
bool IsSessionReady() override
|
||||
{
|
||||
return mIsResponderReady && mIsTransportReady;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -68,12 +68,13 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(PresentationTCPSessionTransport)
|
|||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PresentationTCPSessionTransport)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPresentationSessionTransport)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIPresentationSessionTransport)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIPresentationTCPSessionTransportBuilder)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIPresentationSessionTransport)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIPresentationSessionTransportBuilder)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIPresentationTCPSessionTransportBuilder)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
PresentationTCPSessionTransport::PresentationTCPSessionTransport()
|
||||
|
|
|
@ -54,7 +54,8 @@ interface nsIPresentationControlChannelListener: nsISupports
|
|||
void onIceCandidate(in DOMString candidate);
|
||||
|
||||
/*
|
||||
* The callback for notifying channel opened.
|
||||
* The callback for notifying channel opened. This should be async called
|
||||
* after nsIPresentationDevice::establishControlChannel.
|
||||
*/
|
||||
void notifyOpened();
|
||||
|
||||
|
|
|
@ -168,6 +168,17 @@ interface nsIPresentationService : nsISupports
|
|||
void notifyReceiverReady(in DOMString sessionId,
|
||||
[optional] in unsigned long long windowId);
|
||||
|
||||
/*
|
||||
* Notify the transport is closed
|
||||
*
|
||||
* @param sessionId: An ID to identify presentation session.
|
||||
* @param role: Identify the function called by controller or receiver.
|
||||
* @param reason: the error message. NS_OK indicates it is closed normally.
|
||||
*/
|
||||
void NotifyTransportClosed(in DOMString sessionId,
|
||||
in uint8_t role,
|
||||
in nsresult reason);
|
||||
|
||||
/*
|
||||
* Untrack the relevant info about the presentation session if there's any.
|
||||
*
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче