mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
758c43af6b
73
accessible/tests/crashtests/448064.xhtml
Normal file
73
accessible/tests/crashtests/448064.xhtml
Normal file
@ -0,0 +1,73 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div id="mw_b">
|
||||
<div id="mw_f">
|
||||
<div id="mw_g" style="display: none;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="mw_c" style="display: none;">
|
||||
<div id="mw_d">
|
||||
<div id="mw_e"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input id="mw_a"/>
|
||||
|
||||
|
||||
<script>
|
||||
function dumpAccessibleNode(aNode, level) {
|
||||
var msg = "";
|
||||
|
||||
try {
|
||||
msg += "name=\"" + aNode.name + "\" ";
|
||||
} catch (e) {
|
||||
msg += " noName ";
|
||||
}
|
||||
|
||||
dump(msg + '\n');
|
||||
}
|
||||
|
||||
|
||||
function dumpAccessibleTree(aNode, level) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
level = level || 0;
|
||||
|
||||
dumpAccessibleNode(aNode, level);
|
||||
try {
|
||||
var child = aNode.firstChild;
|
||||
while (child) {
|
||||
dumpAccessibleTree(child, level + 1);
|
||||
child = child.nextSibling;
|
||||
}
|
||||
} catch (e) {
|
||||
dump("Error visiting child nodes: " + e + '\n');
|
||||
}
|
||||
}
|
||||
|
||||
function A(o) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var acc = Components.classes['@mozilla.org/accessibleRetrieval;1']
|
||||
.getService(Components.interfaces.nsIAccessibleRetrieval);
|
||||
return acc.getAccessibleFor(o);
|
||||
}
|
||||
|
||||
function beginAccessible() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
dumpAccessibleTree(A(document),0);
|
||||
}
|
||||
setTimeout(beginAccessible, 100);
|
||||
|
||||
|
||||
setTimeout(doe, 200);
|
||||
function doe() {
|
||||
document.getElementById('mw_a').appendChild(document.getElementById('mw_b'));
|
||||
document.getElementById('mw_c').appendChild(document.getElementById('mw_d'));
|
||||
document.getElementById('mw_e').appendChild(document.getElementById('mw_f'));
|
||||
document.getElementById('mw_g').appendChild(document.getElementById('mw_b'));
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,2 +1,3 @@
|
||||
# Disabled because it causes assertions/crashes in later crashtests, see bug 918246
|
||||
# Disabled because they cause assertions/crashes in later crashtests, see bug 918246
|
||||
skip load 448064.xhtml
|
||||
skip load 471493.xul
|
||||
|
@ -485,7 +485,7 @@ exports["test:setInterval async Errors passed to .onError"] = WorkerTest(
|
||||
onError: function(err) {
|
||||
count++;
|
||||
assert.equal(err.message, "ubik",
|
||||
"error (corectly) propagated " + count + " time(s)");
|
||||
"error (correctly) propagated " + count + " time(s)");
|
||||
if (count >= 3) done();
|
||||
}
|
||||
});
|
||||
|
@ -477,7 +477,7 @@ exports["test:setInterval async Errors passed to .onError"] = WorkerTest(
|
||||
onError: function(err) {
|
||||
count++;
|
||||
assert.equal(err.message, "ubik",
|
||||
"error (corectly) propagated " + count + " time(s)");
|
||||
"error (correctly) propagated " + count + " time(s)");
|
||||
if (count >= 3) done();
|
||||
}
|
||||
});
|
||||
|
@ -485,7 +485,7 @@ exports["test:setInterval async Errors passed to .onError"] = WorkerTest(
|
||||
onError: function(err) {
|
||||
count++;
|
||||
assert.equal(err.message, "ubik",
|
||||
"error (corectly) propagated " + count + " time(s)");
|
||||
"error (correctly) propagated " + count + " time(s)");
|
||||
if (count >= 3) done();
|
||||
}
|
||||
});
|
||||
|
@ -431,7 +431,7 @@ UpdatePrompt.prototype = {
|
||||
|
||||
sendUpdateEvent: function UP_sendUpdateEvent(aType, aUpdate) {
|
||||
let detail = {};
|
||||
for each (let property in this._copyProperties) {
|
||||
for (let property of this._copyProperties) {
|
||||
detail[property] = aUpdate[property];
|
||||
}
|
||||
|
||||
|
@ -1645,6 +1645,8 @@ pref("dom.serviceWorkers.interception.enabled", true);
|
||||
|
||||
// Enable Push API.
|
||||
pref("dom.push.enabled", true);
|
||||
|
||||
pref("dom.serviceWorkers.openWindow.enabled", true);
|
||||
#endif
|
||||
|
||||
// These are the thumbnail width/height set in about:newtab.
|
||||
|
@ -319,26 +319,6 @@
|
||||
orient="horizontal"
|
||||
hidden="true"/>
|
||||
|
||||
<menupopup id="processHangOptions"
|
||||
onpopupshowing="ProcessHangMonitor.refreshMenu(window);">
|
||||
<menuitem id="processHangTerminateScript"
|
||||
oncommand="ProcessHangMonitor.terminateScript(window)"
|
||||
accesskey="&processHang.terminateScript.accessKey;"
|
||||
label="&processHang.terminateScript.label;"/>
|
||||
<menuitem id="processHangDebugScript"
|
||||
oncommand="ProcessHangMonitor.debugScript(window)"
|
||||
accesskey="&processHang.debugScript.accessKey;"
|
||||
label="&processHang.debugScript.label;"/>
|
||||
<menuitem id="processHangTerminatePlugin"
|
||||
oncommand="ProcessHangMonitor.terminatePlugin(window)"
|
||||
accesskey="&processHang.terminatePlugin.accessKey;"
|
||||
label="&processHang.terminatePlugin.label;"/>
|
||||
<menuitem id="processHangTerminateProcess"
|
||||
oncommand="ProcessHangMonitor.terminateProcess(window)"
|
||||
accesskey="&processHang.terminateProcess.accessKey;"
|
||||
label="&processHang.terminateProcess.label;"/>
|
||||
</menupopup>
|
||||
|
||||
<menupopup id="toolbar-context-menu"
|
||||
onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('viewToolbarsMenuSeparator'));">
|
||||
<menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode)"
|
||||
|
@ -1,4 +1,8 @@
|
||||
MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
|
||||
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
fi
|
||||
|
||||
. "$topsrcdir/browser/config/mozconfigs/linux32/common-opt"
|
||||
|
||||
|
@ -2,6 +2,11 @@
|
||||
# safeguard below
|
||||
MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
|
||||
|
||||
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
fi
|
||||
|
||||
. "$topsrcdir/browser/config/mozconfigs/linux32/common-opt"
|
||||
|
||||
ac_add_options --enable-official-branding
|
||||
|
@ -1,4 +1,8 @@
|
||||
MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
|
||||
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
fi
|
||||
|
||||
. "$topsrcdir/browser/config/mozconfigs/linux64/common-opt"
|
||||
|
||||
|
@ -2,6 +2,11 @@
|
||||
# safeguard below
|
||||
MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
|
||||
|
||||
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
fi
|
||||
|
||||
. "$topsrcdir/browser/config/mozconfigs/linux64/common-opt"
|
||||
|
||||
ac_add_options --enable-official-branding
|
||||
|
@ -1,5 +1,10 @@
|
||||
MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
|
||||
|
||||
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
fi
|
||||
|
||||
. "$topsrcdir/browser/config/mozconfigs/macosx-universal/common-opt"
|
||||
|
||||
ac_add_options --enable-official-branding
|
||||
|
@ -2,6 +2,11 @@
|
||||
# safeguard below
|
||||
MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
|
||||
|
||||
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
fi
|
||||
|
||||
. "$topsrcdir/browser/config/mozconfigs/macosx-universal/common-opt"
|
||||
|
||||
ac_add_options --enable-official-branding
|
||||
|
@ -73,6 +73,10 @@ for platform in all_platforms:
|
||||
'ac_add_options --enable-official-branding',
|
||||
'mk_add_options MOZ_MAKE_FLAGS="-j4"',
|
||||
'export BUILDING_RELEASE=1',
|
||||
'if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then',
|
||||
'MOZ_AUTOMATION_UPLOAD_SYMBOLS=1',
|
||||
'MOZ_AUTOMATION_UPDATE_PACKAGING=1',
|
||||
'fi',
|
||||
'MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}',
|
||||
]
|
||||
whitelist['release']['win32'] += ['mk_add_options MOZ_PGO=1']
|
||||
|
@ -1,5 +1,10 @@
|
||||
MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
|
||||
|
||||
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
fi
|
||||
|
||||
. "$topsrcdir/build/mozconfig.win-common"
|
||||
. "$topsrcdir/browser/config/mozconfigs/win32/common-opt"
|
||||
|
||||
|
@ -2,6 +2,11 @@
|
||||
# safeguard below
|
||||
MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
|
||||
|
||||
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
fi
|
||||
|
||||
. "$topsrcdir/build/mozconfig.win-common"
|
||||
. "$topsrcdir/browser/config/mozconfigs/win32/common-opt"
|
||||
|
||||
|
@ -1,5 +1,10 @@
|
||||
MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
|
||||
|
||||
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
fi
|
||||
|
||||
. "$topsrcdir/build/mozconfig.win-common"
|
||||
. "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
|
||||
. "$topsrcdir/browser/config/mozconfigs/win64/common-opt"
|
||||
|
@ -2,6 +2,11 @@
|
||||
# safeguard below
|
||||
MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
|
||||
|
||||
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
fi
|
||||
|
||||
. "$topsrcdir/build/mozconfig.win-common"
|
||||
. "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
|
||||
. "$topsrcdir/browser/config/mozconfigs/win64/common-opt"
|
||||
|
@ -925,15 +925,6 @@ you can use these alternative items. Otherwise, their values should be empty. -
|
||||
<!ENTITY panicButton.thankyou.msg2 "Safe browsing!">
|
||||
<!ENTITY panicButton.thankyou.buttonlabel "Thanks!">
|
||||
|
||||
<!ENTITY processHang.terminateScript.label "Stop Script">
|
||||
<!ENTITY processHang.terminateScript.accessKey "S">
|
||||
<!ENTITY processHang.debugScript.label "Debug Script">
|
||||
<!ENTITY processHang.debugScript.accessKey "D">
|
||||
<!ENTITY processHang.terminatePlugin.label "Kill Plugin">
|
||||
<!ENTITY processHang.terminatePlugin.accessKey "P">
|
||||
<!ENTITY processHang.terminateProcess.label "Kill Web Process">
|
||||
<!ENTITY processHang.terminateProcess.accessKey "K">
|
||||
|
||||
<!ENTITY emeLearnMoreContextMenu.label "Learn more about DRM…">
|
||||
<!ENTITY emeLearnMoreContextMenu.accesskey "D">
|
||||
<!ENTITY emeNotificationsNotNow.label "Not now">
|
||||
|
@ -472,9 +472,13 @@ dataReportingNotification.button.label = Choose What I Share
|
||||
dataReportingNotification.button.accessKey = C
|
||||
|
||||
# Process hang reporter
|
||||
processHang.message = A web page is causing %1$S to run slowly. What would you like to do?
|
||||
processHang.button.label = Options
|
||||
processHang.button.accessKey = O
|
||||
processHang.label = A web page is slowing down your browser. What would you like to do?
|
||||
processHang.button_stop.label = Stop It
|
||||
processHang.button_stop.accessKey = S
|
||||
processHang.button_wait.label = Wait
|
||||
processHang.button_wait.accessKey = W
|
||||
processHang.button_debug.label = Debug Script
|
||||
processHang.button_debug.accessKey = D
|
||||
|
||||
# Webapps notification popup
|
||||
webapps.install = Install
|
||||
|
@ -19,13 +19,31 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
* the platform interface.
|
||||
*/
|
||||
|
||||
/**
|
||||
* If a hang hasn't been reported for more than 10 seconds, assume the
|
||||
* content process has gotten unstuck (and hide the hang notification).
|
||||
*/
|
||||
const HANG_EXPIRATION_TIME = 10000;
|
||||
|
||||
var ProcessHangMonitor = {
|
||||
/**
|
||||
* If a hang hasn't been reported for more than 10 seconds, assume the
|
||||
* content process has gotten unstuck (and hide the hang notification).
|
||||
*/
|
||||
get HANG_EXPIRATION_TIME() {
|
||||
try {
|
||||
return Services.prefs.getIntPref("browser.hangNotification.expiration");
|
||||
} catch (ex) {
|
||||
return 10000;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This timeout is the wait period applied after a user selects "Wait" in
|
||||
* an existing notification.
|
||||
*/
|
||||
get WAIT_EXPIRATION_TIME() {
|
||||
try {
|
||||
return Services.prefs.getIntPref("browser.hangNotification.waitPeriod");
|
||||
} catch (ex) {
|
||||
return 10000;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Collection of hang reports that haven't expired or been dismissed
|
||||
* by the user. The keys are nsIHangReports and values keys are
|
||||
@ -34,6 +52,12 @@ var ProcessHangMonitor = {
|
||||
*/
|
||||
_activeReports: new Map(),
|
||||
|
||||
/**
|
||||
* Collection of hang reports that have been suppressed for a
|
||||
* short period of time.
|
||||
*/
|
||||
_pausedReports: new Map(),
|
||||
|
||||
/**
|
||||
* Initialize hang reporting. Called once in the parent process.
|
||||
*/
|
||||
@ -70,46 +94,78 @@ var ProcessHangMonitor = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Kill the plugin process causing the hang being reported for the
|
||||
* selected browser in |win|.
|
||||
* Terminate the plugin process associated with a hang being reported
|
||||
* for the selected browser in |win|. Will attempt to generate a combined
|
||||
* crash report for all processes.
|
||||
*/
|
||||
terminatePlugin: function(win) {
|
||||
this.handleUserInput(win, report => report.terminatePlugin());
|
||||
},
|
||||
|
||||
/**
|
||||
* Kill the content process causing the hang being reported for the selected
|
||||
* browser in |win|.
|
||||
* Dismiss the browser notification and invoke an appropriate action based on
|
||||
* the hang type.
|
||||
*/
|
||||
terminateProcess: function(win) {
|
||||
this.handleUserInput(win, report => report.terminateProcess());
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the "Options" pop-up menu for the hang notification
|
||||
* associated with the selected browser in |win|. The menu should
|
||||
* display only options that are relevant to the given report.
|
||||
*/
|
||||
refreshMenu: function(win) {
|
||||
let report = this.findReport(win.gBrowser.selectedBrowser);
|
||||
stopIt: function (win) {
|
||||
let report = this.findActiveReport(win.gBrowser.selectedBrowser);
|
||||
if (!report) {
|
||||
return;
|
||||
}
|
||||
|
||||
function setVisible(id, visible) {
|
||||
let item = win.document.getElementById(id);
|
||||
item.hidden = !visible;
|
||||
switch (report.hangType) {
|
||||
case report.SLOW_SCRIPT:
|
||||
this.terminateScript(win);
|
||||
break;
|
||||
case report.PLUGIN_HANG:
|
||||
this.terminatePlugin(win);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
if (report.hangType == report.SLOW_SCRIPT) {
|
||||
setVisible("processHangTerminateScript", true);
|
||||
setVisible("processHangDebugScript", true);
|
||||
setVisible("processHangTerminatePlugin", false);
|
||||
} else if (report.hangType == report.PLUGIN_HANG) {
|
||||
setVisible("processHangTerminateScript", false);
|
||||
setVisible("processHangDebugScript", false);
|
||||
setVisible("processHangTerminatePlugin", true);
|
||||
/**
|
||||
* Dismiss the notification, clear the report from the active list and set up
|
||||
* a new timer to track a wait period during which we won't notify.
|
||||
*/
|
||||
waitLonger: function(win) {
|
||||
let report = this.findActiveReport(win.gBrowser.selectedBrowser);
|
||||
if (!report) {
|
||||
return;
|
||||
}
|
||||
// Remove the report from the active list and cancel its timer.
|
||||
this.removeActiveReport(report);
|
||||
|
||||
// NOTE, we didn't call userCanceled on nsIHangReport here. This insures
|
||||
// we don't repeatedly generate and cache crash report data for this hang
|
||||
// in the process hang reporter. It already has one report for the browser
|
||||
// process we want it hold onto.
|
||||
|
||||
// Create a new wait timer with notify callback
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(() => {
|
||||
for (let [stashedReport, otherTimer] of this._pausedReports) {
|
||||
if (otherTimer === timer) {
|
||||
this.removePausedReport(stashedReport);
|
||||
|
||||
// Create a new notification display timeout timer
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(this, this.HANG_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);
|
||||
|
||||
// Store the timer in the active reports map. If we receive a new
|
||||
// observer notification for this hang, we'll redisplay the browser
|
||||
// notification in reportHang below. If we do not receive a new
|
||||
// observer, timer will take care of cleaning up resources associated
|
||||
// with this hang. The observer for active hangs fires about once
|
||||
// a second.
|
||||
this._activeReports.set(report, timer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, this.WAIT_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);
|
||||
|
||||
this._pausedReports.set(report, timer);
|
||||
|
||||
// remove the browser notification associated with this hang
|
||||
this.updateWindows();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -118,11 +174,11 @@ var ProcessHangMonitor = {
|
||||
* about it.
|
||||
*/
|
||||
handleUserInput: function(win, func) {
|
||||
let report = this.findReport(win.gBrowser.selectedBrowser);
|
||||
let report = this.findActiveReport(win.gBrowser.selectedBrowser);
|
||||
if (!report) {
|
||||
return;
|
||||
}
|
||||
this.removeReport(report);
|
||||
this.removeActiveReport(report);
|
||||
|
||||
return func(report);
|
||||
},
|
||||
@ -153,9 +209,9 @@ var ProcessHangMonitor = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Find any active hang reports for the given <browser> element.
|
||||
* Find a active hang report for the given <browser> element.
|
||||
*/
|
||||
findReport: function(browser) {
|
||||
findActiveReport: function(browser) {
|
||||
let frameLoader = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
|
||||
for (let [report, timer] of this._activeReports) {
|
||||
if (report.isReportForBrowser(frameLoader)) {
|
||||
@ -165,6 +221,44 @@ var ProcessHangMonitor = {
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Find a paused hang report for the given <browser> element.
|
||||
*/
|
||||
findPausedReport: function(browser) {
|
||||
let frameLoader = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
|
||||
for (let [report, timer] of this._pausedReports) {
|
||||
if (report.isReportForBrowser(frameLoader)) {
|
||||
return report;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove an active hang report from the active list and cancel the timer
|
||||
* associated with it.
|
||||
*/
|
||||
removeActiveReport: function(report) {
|
||||
let timer = this._activeReports.get(report);
|
||||
if (timer) {
|
||||
timer.cancel();
|
||||
}
|
||||
this._activeReports.delete(report);
|
||||
this.updateWindows();
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a paused hang report from the paused list and cancel the timer
|
||||
* associated with it.
|
||||
*/
|
||||
removePausedReport: function(report) {
|
||||
let timer = this._pausedReports.get(report);
|
||||
if (timer) {
|
||||
timer.cancel();
|
||||
}
|
||||
this._pausedReports.delete(report);
|
||||
},
|
||||
|
||||
/**
|
||||
* Iterate over all XUL windows and ensure that the proper hang
|
||||
* reports are shown for each one. Also install event handlers in
|
||||
@ -191,7 +285,7 @@ var ProcessHangMonitor = {
|
||||
* If there is a hang report for the current tab in |win|, display it.
|
||||
*/
|
||||
updateWindow: function(win) {
|
||||
let report = this.findReport(win.gBrowser.selectedBrowser);
|
||||
let report = this.findActiveReport(win.gBrowser.selectedBrowser);
|
||||
|
||||
if (report) {
|
||||
this.showNotification(win, report);
|
||||
@ -212,19 +306,36 @@ var ProcessHangMonitor = {
|
||||
|
||||
let bundle = win.gNavigatorBundle;
|
||||
let brandBundle = win.document.getElementById("bundle_brand");
|
||||
let appName = brandBundle.getString("brandShortName");
|
||||
let message = bundle.getFormattedString(
|
||||
"processHang.message",
|
||||
[appName]);
|
||||
|
||||
let buttons = [{
|
||||
label: bundle.getString("processHang.button.label"),
|
||||
accessKey: bundle.getString("processHang.button.accessKey"),
|
||||
popup: "processHangOptions",
|
||||
callback: null,
|
||||
}];
|
||||
label: bundle.getString("processHang.button_stop.label"),
|
||||
accessKey: bundle.getString("processHang.button_stop.accessKey"),
|
||||
callback: function() {
|
||||
ProcessHangMonitor.stopIt(win);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: bundle.getString("processHang.button_wait.label"),
|
||||
accessKey: bundle.getString("processHang.button_wait.accessKey"),
|
||||
callback: function() {
|
||||
ProcessHangMonitor.waitLonger(win);
|
||||
}
|
||||
}];
|
||||
|
||||
nb.appendNotification(message, "process-hang",
|
||||
#ifdef MOZ_DEV_EDITION
|
||||
if (report.hangType == report.SLOW_SCRIPT) {
|
||||
buttons.push({
|
||||
label: bundle.getString("processHang.button_debug.label"),
|
||||
accessKey: bundle.getString("processHang.button_debug.accessKey"),
|
||||
callback: function() {
|
||||
ProcessHangMonitor.debugScript(win);
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
nb.appendNotification(bundle.getString("processHang.label"),
|
||||
"process-hang",
|
||||
"chrome://browser/content/aboutRobots-icon.png",
|
||||
nb.PRIORITY_WARNING_HIGH, buttons);
|
||||
},
|
||||
@ -270,11 +381,19 @@ var ProcessHangMonitor = {
|
||||
* before, show a notification for it in all open XUL windows.
|
||||
*/
|
||||
reportHang: function(report) {
|
||||
// If this hang was already reported, then reset the timer for it.
|
||||
// If this hang was already reported reset the timer for it.
|
||||
if (this._activeReports.has(report)) {
|
||||
let timer = this._activeReports.get(report);
|
||||
timer.cancel();
|
||||
timer.initWithCallback(this, HANG_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);
|
||||
timer.initWithCallback(this, this.HANG_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);
|
||||
// if this report is in active but doesn't have a notification associated
|
||||
// with it, display a notification.
|
||||
this.updateWindows();
|
||||
return;
|
||||
}
|
||||
|
||||
// If this hang was already reported and paused by the user ignore it.
|
||||
if (this._pausedReports.has(report)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -291,28 +410,19 @@ var ProcessHangMonitor = {
|
||||
|
||||
// Otherwise create a new timer and display the report.
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(this, HANG_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);
|
||||
timer.initWithCallback(this, this.HANG_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);
|
||||
|
||||
this._activeReports.set(report, timer);
|
||||
this.updateWindows();
|
||||
},
|
||||
|
||||
/**
|
||||
* Dismiss a hang report because the user closed the notification
|
||||
* for it or the report expired.
|
||||
*/
|
||||
removeReport: function(report) {
|
||||
this._activeReports.delete(report);
|
||||
this.updateWindows();
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for when HANG_EXPIRATION_TIME has elapsed.
|
||||
*/
|
||||
notify: function(timer) {
|
||||
for (let [otherReport, otherTimer] of this._activeReports) {
|
||||
if (otherTimer === timer) {
|
||||
this.removeReport(otherReport);
|
||||
this.removeActiveReport(otherReport);
|
||||
otherReport.userCanceled();
|
||||
break;
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ EXTRA_JS_MODULES += [
|
||||
'offlineAppCache.jsm',
|
||||
'PanelFrame.jsm',
|
||||
'PluginContent.jsm',
|
||||
'ProcessHangMonitor.jsm',
|
||||
'ReaderParent.jsm',
|
||||
'RecentWindow.jsm',
|
||||
'RemotePrompt.jsm',
|
||||
@ -46,6 +45,10 @@ EXTRA_JS_MODULES += [
|
||||
'webrtcUI.jsm',
|
||||
]
|
||||
|
||||
EXTRA_PP_JS_MODULES += [
|
||||
'ProcessHangMonitor.jsm'
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
EXTRA_JS_MODULES += [
|
||||
'Windows8WindowFrameColor.jsm',
|
||||
|
@ -3,6 +3,8 @@ support-files =
|
||||
head.js
|
||||
|
||||
[browser_BrowserUITelemetry_buckets.js]
|
||||
[browser_ProcessHangNotifications.js]
|
||||
skip-if = !e10s
|
||||
[browser_ContentSearch.js]
|
||||
skip-if = e10s
|
||||
support-files =
|
||||
|
185
browser/modules/test/browser_ProcessHangNotifications.js
Normal file
185
browser/modules/test/browser_ProcessHangNotifications.js
Normal file
@ -0,0 +1,185 @@
|
||||
|
||||
Cu.import("resource://gre/modules/UpdateUtils.jsm");
|
||||
|
||||
function getNotificationBox(aWindow) {
|
||||
return aWindow.document.getElementById("high-priority-global-notificationbox");
|
||||
}
|
||||
|
||||
function promiseNotificationShown(aWindow, aName) {
|
||||
return new Promise((resolve) => {
|
||||
let notification = getNotificationBox(aWindow);
|
||||
notification.addEventListener("AlertActive", function active() {
|
||||
notification.removeEventListener("AlertActive", active, true);
|
||||
is(notification.allNotifications.length, 1, "Notification Displayed.");
|
||||
resolve(notification);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function promiseReportCallMade(aValue) {
|
||||
return new Promise((resolve) => {
|
||||
let old = gTestHangReport.testCallback;
|
||||
gTestHangReport.testCallback = function (val) {
|
||||
gTestHangReport.testCallback = old;
|
||||
is(aValue, val, "was the correct method call made on the hang report object?");
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function pushPrefs(...aPrefs) {
|
||||
return new Promise((resolve) => {
|
||||
SpecialPowers.pushPrefEnv({"set": aPrefs}, resolve);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function popPrefs() {
|
||||
return new Promise((resolve) => {
|
||||
SpecialPowers.popPrefEnv(resolve);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
let gTestHangReport = {
|
||||
SLOW_SCRIPT: 1,
|
||||
PLUGIN_HANG: 2,
|
||||
|
||||
TEST_CALLBACK_CANCELED: 1,
|
||||
TEST_CALLBACK_TERMSCRIPT: 2,
|
||||
TEST_CALLBACK_TERMPLUGIN: 3,
|
||||
|
||||
_hangType: 1,
|
||||
_tcb: function (aCallbackType) {},
|
||||
|
||||
get hangType() {
|
||||
return this._hangType;
|
||||
},
|
||||
|
||||
set hangType(aValue) {
|
||||
this._hangType = aValue;
|
||||
},
|
||||
|
||||
set testCallback(aValue) {
|
||||
this._tcb = aValue;
|
||||
},
|
||||
|
||||
QueryInterface: function (aIID) {
|
||||
if (aIID.equals(Components.interfaces.nsIHangReport) ||
|
||||
aIID.equals(Components.interfaces.nsISupports))
|
||||
return this;
|
||||
throw Components.results.NS_NOINTERFACE;
|
||||
},
|
||||
|
||||
userCanceled: function () {
|
||||
this._tcb(this.TEST_CALLBACK_CANCELED);
|
||||
},
|
||||
|
||||
terminateScript: function () {
|
||||
this._tcb(this.TEST_CALLBACK_TERMSCRIPT);
|
||||
},
|
||||
|
||||
terminatePlugin: function () {
|
||||
this._tcb(this.TEST_CALLBACK_TERMPLUGIN);
|
||||
},
|
||||
|
||||
isReportForBrowser: function(aFrameLoader) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// on dev edition we add a button for js debugging of hung scripts.
|
||||
let buttonCount = (UpdateUtils.UpdateChannel == "aurora" ? 3 : 2);
|
||||
|
||||
/**
|
||||
* Test if hang reports receive a terminate script callback when the user selects
|
||||
* stop in response to a script hang.
|
||||
*/
|
||||
|
||||
add_task(function* terminateScriptTest() {
|
||||
let promise = promiseNotificationShown(window, "process-hang");
|
||||
Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
|
||||
let notification = yield promise;
|
||||
|
||||
let buttons = notification.currentNotification.getElementsByTagName("button");
|
||||
is(buttons.length, buttonCount, "proper number of buttons");
|
||||
|
||||
// Click the "Stop It" button, we should get a terminate script callback
|
||||
gTestHangReport.hangType = gTestHangReport.SLOW_SCRIPT;
|
||||
promise = promiseReportCallMade(gTestHangReport.TEST_CALLBACK_TERMSCRIPT);
|
||||
buttons[0].click();
|
||||
yield promise;
|
||||
});
|
||||
|
||||
/**
|
||||
* Test if hang reports receive user canceled callbacks after a user selects wait
|
||||
* and the browser frees up from a script hang on its own.
|
||||
*/
|
||||
|
||||
add_task(function* waitForScriptTest() {
|
||||
let promise = promiseNotificationShown(window, "process-hang");
|
||||
Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
|
||||
let notification = yield promise;
|
||||
|
||||
let buttons = notification.currentNotification.getElementsByTagName("button");
|
||||
is(buttons.length, buttonCount, "proper number of buttons");
|
||||
|
||||
yield pushPrefs(["browser.hangNotification.waitPeriod", 1000],
|
||||
["browser.hangNotification.expiration", 2000]);
|
||||
|
||||
function nocbcheck() {
|
||||
ok(false, "received a callback?");
|
||||
}
|
||||
let oldcb = gTestHangReport.testCallback;
|
||||
gTestHangReport.testCallback = nocbcheck;
|
||||
// Click the "Wait" button this time, we shouldn't get a callback at all.
|
||||
buttons[1].click();
|
||||
gTestHangReport.testCallback = oldcb;
|
||||
|
||||
// send another hang pulse, we should not get a notification here
|
||||
Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
|
||||
is(notification.currentNotification, null, "no notification should be visible");
|
||||
|
||||
// After selecting Wait, we should get a userCanceled callback after
|
||||
// HANG_EXPIRATION_TIME.
|
||||
yield promiseReportCallMade(gTestHangReport.TEST_CALLBACK_CANCELED);
|
||||
|
||||
yield popPrefs();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test if hang reports receive user canceled callbacks after the content
|
||||
* process stops sending hang notifications.
|
||||
*/
|
||||
|
||||
add_task(function* hangGoesAwayTest() {
|
||||
yield pushPrefs(["browser.hangNotification.expiration", 1000]);
|
||||
|
||||
let promise = promiseNotificationShown(window, "process-hang");
|
||||
Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
|
||||
yield promise;
|
||||
|
||||
yield promiseReportCallMade(gTestHangReport.TEST_CALLBACK_CANCELED);
|
||||
|
||||
yield popPrefs();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests if hang reports receive a terminate plugin callback when the user selects
|
||||
* stop in response to a plugin hang.
|
||||
*/
|
||||
|
||||
add_task(function* terminatePluginTest() {
|
||||
let promise = promiseNotificationShown(window, "process-hang");
|
||||
Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
|
||||
let notification = yield promise;
|
||||
|
||||
let buttons = notification.currentNotification.getElementsByTagName("button");
|
||||
is(buttons.length, buttonCount, "proper number of buttons");
|
||||
|
||||
// Click the "Stop It" button, we should get a terminate script callback
|
||||
gTestHangReport.hangType = gTestHangReport.PLUGIN_HANG;
|
||||
promise = promiseReportCallMade(gTestHangReport.TEST_CALLBACK_TERMPLUGIN);
|
||||
buttons[0].click();
|
||||
yield promise;
|
||||
});
|
@ -18,14 +18,14 @@ from mozbuild.preprocessor import preprocess
|
||||
# processing of the jar file in the appropriate directory.
|
||||
def _do_preprocessing(output_svg, input_svg_file, additional_defines):
|
||||
additional_defines.update(buildconfig.defines)
|
||||
preprocess(output=output_svg,
|
||||
includes=[input_svg_file],
|
||||
marker='%',
|
||||
defines=additional_defines)
|
||||
return preprocess(output=output_svg,
|
||||
includes=[input_svg_file],
|
||||
marker='%',
|
||||
defines=additional_defines)
|
||||
|
||||
def tab_side_start(output_svg, input_svg_file):
|
||||
_do_preprocessing(output_svg, input_svg_file, {'TAB_SIDE': 'start'})
|
||||
return _do_preprocessing(output_svg, input_svg_file, {'TAB_SIDE': 'start'})
|
||||
|
||||
def tab_side_end(output_svg, input_svg_file):
|
||||
_do_preprocessing(output_svg, input_svg_file, {'TAB_SIDE': 'end'})
|
||||
return _do_preprocessing(output_svg, input_svg_file, {'TAB_SIDE': 'end'})
|
||||
|
||||
|
@ -85,11 +85,16 @@ def verify_mozconfigs(mozconfig_pair, nightly_mozconfig_pair, platform,
|
||||
# compare to whitelist
|
||||
message = ""
|
||||
if line[0] == '-':
|
||||
# handle lines that move around in diff
|
||||
if '+' + line[1:] in diff_list:
|
||||
continue
|
||||
if platform in mozconfigWhitelist.get('release', {}):
|
||||
if clean_line in \
|
||||
mozconfigWhitelist['release'][platform]:
|
||||
continue
|
||||
elif line[0] == '+':
|
||||
if '-' + line[1:] in diff_list:
|
||||
continue
|
||||
if platform in mozconfigWhitelist.get('nightly', {}):
|
||||
if clean_line in \
|
||||
mozconfigWhitelist['nightly'][platform]:
|
||||
|
4
config/external/nss/Makefile.in
vendored
4
config/external/nss/Makefile.in
vendored
@ -267,6 +267,10 @@ ifdef MOZ_FOLD_LIBS_FLAGS
|
||||
DEFAULT_GMAKE_FLAGS += XCFLAGS='$(MOZ_FOLD_LIBS_FLAGS)'
|
||||
endif
|
||||
|
||||
ifeq (1,$(ALLOW_COMPILER_WARNINGS))
|
||||
DEFAULT_GMAKE_FLAGS += NSS_ENABLE_WERROR=0
|
||||
endif
|
||||
|
||||
NSS_SRCDIR = $(topsrcdir)
|
||||
|
||||
NSS_DIRS =
|
||||
|
1
config/external/nss/nss.def
vendored
1
config/external/nss/nss.def
vendored
@ -682,3 +682,4 @@ VFY_VerifyData
|
||||
VFY_VerifyDataWithAlgorithmID
|
||||
VFY_VerifyDigestDirect
|
||||
_SGN_VerifyPKCS1DigestInfo
|
||||
__PK11_SetCertificateNickname
|
||||
|
@ -67,21 +67,21 @@ function htmlSearch() {
|
||||
if (label) {
|
||||
is(target.querySelector(".results-panel-item-label").getAttribute("value"),
|
||||
gDebugger.SourceUtils.trimUrlLength(label + "()"),
|
||||
"The corect label (" + label + ") is currently selected.");
|
||||
"The correct label (" + label + ") is currently selected.");
|
||||
} else {
|
||||
ok(!target.querySelector(".results-panel-item-label"),
|
||||
"Shouldn't create empty label nodes.");
|
||||
}
|
||||
if (value) {
|
||||
ok(target.querySelector(".results-panel-item-label-below").getAttribute("value").includes(value),
|
||||
"The corect value (" + value + ") is attached.");
|
||||
"The correct value (" + value + ") is attached.");
|
||||
} else {
|
||||
ok(!target.querySelector(".results-panel-item-label-below"),
|
||||
"Shouldn't create empty label nodes.");
|
||||
}
|
||||
if (description) {
|
||||
is(target.querySelector(".results-panel-item-label-before").getAttribute("value"), description,
|
||||
"The corect description (" + description + ") is currently shown.");
|
||||
"The correct description (" + description + ") is currently shown.");
|
||||
} else {
|
||||
ok(!target.querySelector(".results-panel-item-label-before"),
|
||||
"Shouldn't create empty label nodes.");
|
||||
@ -138,21 +138,21 @@ function firstJsSearch() {
|
||||
if (label) {
|
||||
is(target.querySelector(".results-panel-item-label").getAttribute("value"),
|
||||
gDebugger.SourceUtils.trimUrlLength(label + "()"),
|
||||
"The corect label (" + label + ") is currently selected.");
|
||||
"The correct label (" + label + ") is currently selected.");
|
||||
} else {
|
||||
ok(!target.querySelector(".results-panel-item-label"),
|
||||
"Shouldn't create empty label nodes.");
|
||||
}
|
||||
if (value) {
|
||||
ok(target.querySelector(".results-panel-item-label-below").getAttribute("value").includes(value),
|
||||
"The corect value (" + value + ") is attached.");
|
||||
"The correct value (" + value + ") is attached.");
|
||||
} else {
|
||||
ok(!target.querySelector(".results-panel-item-label-below"),
|
||||
"Shouldn't create empty label nodes.");
|
||||
}
|
||||
if (description) {
|
||||
is(target.querySelector(".results-panel-item-label-before").getAttribute("value"), description,
|
||||
"The corect description (" + description + ") is currently shown.");
|
||||
"The correct description (" + description + ") is currently shown.");
|
||||
} else {
|
||||
ok(!target.querySelector(".results-panel-item-label-before"),
|
||||
"Shouldn't create empty label nodes.");
|
||||
@ -209,21 +209,21 @@ function secondJsSearch() {
|
||||
if (label) {
|
||||
is(target.querySelector(".results-panel-item-label").getAttribute("value"),
|
||||
gDebugger.SourceUtils.trimUrlLength(label + "()"),
|
||||
"The corect label (" + label + ") is currently selected.");
|
||||
"The correct label (" + label + ") is currently selected.");
|
||||
} else {
|
||||
ok(!target.querySelector(".results-panel-item-label"),
|
||||
"Shouldn't create empty label nodes.");
|
||||
}
|
||||
if (value) {
|
||||
ok(target.querySelector(".results-panel-item-label-below").getAttribute("value").includes(value),
|
||||
"The corect value (" + value + ") is attached.");
|
||||
"The correct value (" + value + ") is attached.");
|
||||
} else {
|
||||
ok(!target.querySelector(".results-panel-item-label-below"),
|
||||
"Shouldn't create empty label nodes.");
|
||||
}
|
||||
if (description) {
|
||||
is(target.querySelector(".results-panel-item-label-before").getAttribute("value"), description,
|
||||
"The corect description (" + description + ") is currently shown.");
|
||||
"The correct description (" + description + ") is currently shown.");
|
||||
} else {
|
||||
ok(!target.querySelector(".results-panel-item-label-before"),
|
||||
"Shouldn't create empty label nodes.");
|
||||
@ -280,21 +280,21 @@ function thirdJsSearch() {
|
||||
if (label) {
|
||||
is(target.querySelector(".results-panel-item-label").getAttribute("value"),
|
||||
gDebugger.SourceUtils.trimUrlLength(label + "()"),
|
||||
"The corect label (" + label + ") is currently selected.");
|
||||
"The correct label (" + label + ") is currently selected.");
|
||||
} else {
|
||||
ok(!target.querySelector(".results-panel-item-label"),
|
||||
"Shouldn't create empty label nodes.");
|
||||
}
|
||||
if (value) {
|
||||
ok(target.querySelector(".results-panel-item-label-below").getAttribute("value").includes(value),
|
||||
"The corect value (" + value + ") is attached.");
|
||||
"The correct value (" + value + ") is attached.");
|
||||
} else {
|
||||
ok(!target.querySelector(".results-panel-item-label-below"),
|
||||
"Shouldn't create empty label nodes.");
|
||||
}
|
||||
if (description) {
|
||||
is(target.querySelector(".results-panel-item-label-before").getAttribute("value"), description,
|
||||
"The corect description (" + description + ") is currently shown.");
|
||||
"The correct description (" + description + ") is currently shown.");
|
||||
} else {
|
||||
ok(!target.querySelector(".results-panel-item-label-before"),
|
||||
"Shouldn't create empty label nodes.");
|
||||
@ -348,21 +348,21 @@ function filterSearch() {
|
||||
if (label) {
|
||||
is(target.querySelector(".results-panel-item-label").getAttribute("value"),
|
||||
gDebugger.SourceUtils.trimUrlLength(label + "()"),
|
||||
"The corect label (" + label + ") is currently selected.");
|
||||
"The correct label (" + label + ") is currently selected.");
|
||||
} else {
|
||||
ok(!target.querySelector(".results-panel-item-label"),
|
||||
"Shouldn't create empty label nodes.");
|
||||
}
|
||||
if (value) {
|
||||
ok(target.querySelector(".results-panel-item-label-below").getAttribute("value").includes(value),
|
||||
"The corect value (" + value + ") is attached.");
|
||||
"The correct value (" + value + ") is attached.");
|
||||
} else {
|
||||
ok(!target.querySelector(".results-panel-item-label-below"),
|
||||
"Shouldn't create empty label nodes.");
|
||||
}
|
||||
if (description) {
|
||||
is(target.querySelector(".results-panel-item-label-before").getAttribute("value"), description,
|
||||
"The corect description (" + description + ") is currently shown.");
|
||||
"The correct description (" + description + ") is currently shown.");
|
||||
} else {
|
||||
ok(!target.querySelector(".results-panel-item-label-before"),
|
||||
"Shouldn't create empty label nodes.");
|
||||
|
@ -15,7 +15,7 @@ function test() {
|
||||
"The format() function shouldn't work if no params are passed.");
|
||||
|
||||
is(typeof l10.get("initWebGL.error"), "string",
|
||||
"No valid string was returned from a corect name in the bundle.");
|
||||
"No valid string was returned from a correct name in the bundle.");
|
||||
is(typeof l10.format("linkProgram.error", ["error"]), "string",
|
||||
"No valid formatted string was returned from a name in the bundle.");
|
||||
}
|
||||
|
55
dom/base/WindowOrientationObserver.cpp
Normal file
55
dom/base/WindowOrientationObserver.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WindowOrientationObserver.h"
|
||||
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "mozilla/Hal.h"
|
||||
|
||||
/**
|
||||
* This class is used by nsGlobalWindow to implement window.orientation
|
||||
* and window.onorientationchange. This class is defined in its own file
|
||||
* because Hal.h pulls in windows.h and can't be included from
|
||||
* nsGlobalWindow.cpp
|
||||
*/
|
||||
WindowOrientationObserver::WindowOrientationObserver(
|
||||
nsGlobalWindow* aGlobalWindow)
|
||||
: mWindow(aGlobalWindow)
|
||||
{
|
||||
MOZ_ASSERT(aGlobalWindow && aGlobalWindow->IsInnerWindow());
|
||||
hal::RegisterScreenConfigurationObserver(this);
|
||||
|
||||
hal::ScreenConfiguration config;
|
||||
hal::GetCurrentScreenConfiguration(&config);
|
||||
mAngle = config.angle();
|
||||
}
|
||||
|
||||
WindowOrientationObserver::~WindowOrientationObserver()
|
||||
{
|
||||
hal::UnregisterScreenConfigurationObserver(this);
|
||||
}
|
||||
|
||||
void
|
||||
WindowOrientationObserver::Notify(
|
||||
const mozilla::hal::ScreenConfiguration& aConfiguration)
|
||||
{
|
||||
uint16_t currentAngle = aConfiguration.angle();
|
||||
if (mAngle != currentAngle && mWindow->IsCurrentInnerWindow()) {
|
||||
mAngle = currentAngle;
|
||||
mWindow->GetOuterWindow()->DispatchCustomEvent(NS_LITERAL_STRING("orientationchange"));
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ int16_t
|
||||
WindowOrientationObserver::OrientationAngle()
|
||||
{
|
||||
hal::ScreenConfiguration config;
|
||||
hal::GetCurrentScreenConfiguration(&config);
|
||||
int16_t angle = static_cast<int16_t>(config.angle());
|
||||
// config.angle() returns 0, 90, 180 or 270.
|
||||
// window.orientation returns -90, 0, 90 or 180.
|
||||
return angle <= 180 ? angle : angle - 360;
|
||||
}
|
35
dom/base/WindowOrientationObserver.h
Normal file
35
dom/base/WindowOrientationObserver.h
Normal file
@ -0,0 +1,35 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_WindowOrientationObserver_h
|
||||
#define mozilla_dom_WindowOrientationObserver_h
|
||||
|
||||
#include "mozilla/HalScreenConfiguration.h"
|
||||
|
||||
class nsGlobalWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class WindowOrientationObserver final :
|
||||
public mozilla::hal::ScreenConfigurationObserver
|
||||
{
|
||||
public:
|
||||
explicit WindowOrientationObserver(nsGlobalWindow* aGlobalWindow);
|
||||
~WindowOrientationObserver();
|
||||
void Notify(const mozilla::hal::ScreenConfiguration& aConfiguration) override;
|
||||
static int16_t OrientationAngle();
|
||||
|
||||
private:
|
||||
// Weak pointer, instance is owned by mWindow.
|
||||
nsGlobalWindow* MOZ_NON_OWNING_REF mWindow;
|
||||
uint16_t mAngle;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_WindowOrientationObserver_h
|
36
dom/base/crashtests/729431-1.xhtml
Normal file
36
dom/base/crashtests/729431-1.xhtml
Normal file
@ -0,0 +1,36 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<script>
|
||||
<![CDATA[
|
||||
|
||||
function boom()
|
||||
{
|
||||
var d = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
|
||||
d.setAttributeNS(null, "contenteditable", "true");
|
||||
var s = document.createElementNS("http://www.w3.org/1999/xhtml", "span");
|
||||
d.appendChild(s);
|
||||
document.documentElement.appendChild(d);
|
||||
|
||||
var textarea = document.createElementNS("http://www.w3.org/1999/xhtml", "textarea");
|
||||
var t1 = document.createTextNode("A");
|
||||
textarea.appendChild(t1);
|
||||
var t2 = document.createTextNode("B");
|
||||
textarea.appendChild(t2);
|
||||
document.documentElement.appendChild(textarea);
|
||||
|
||||
document.documentElement.offsetHeight;
|
||||
|
||||
d.removeChild(s);
|
||||
textarea.removeChild(t2);
|
||||
document.documentElement.appendChild(document.createTextNode(" C "));
|
||||
document.documentElement.appendChild(t2);
|
||||
}
|
||||
|
||||
window.addEventListener("load", boom, false);
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<!-- no body -->
|
||||
|
||||
</html>
|
@ -149,6 +149,7 @@ load 709954.html
|
||||
load 713417-2.html
|
||||
load 713417.html
|
||||
load 715056.html
|
||||
load 729431-1.xhtml
|
||||
load 741163-1.html
|
||||
load 745495.html
|
||||
load 752226-1.html
|
||||
|
@ -209,6 +209,7 @@ EXPORTS.mozilla.dom += [
|
||||
'URL.h',
|
||||
'URLSearchParams.h',
|
||||
'WebSocket.h',
|
||||
'WindowOrientationObserver.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
@ -355,6 +356,7 @@ UNIFIED_SOURCES += [
|
||||
'URLSearchParams.cpp',
|
||||
'WebSocket.cpp',
|
||||
'WindowNamedPropertiesHandler.cpp',
|
||||
'WindowOrientationObserver.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBRTC']:
|
||||
|
@ -847,6 +847,7 @@ GK_ATOM(onobsolete, "onobsolete")
|
||||
GK_ATOM(ononline, "ononline")
|
||||
GK_ATOM(onoffline, "onoffline")
|
||||
GK_ATOM(onopen, "onopen")
|
||||
GK_ATOM(onorientationchange, "onorientationchange")
|
||||
GK_ATOM(onotastatuschange, "onotastatuschange")
|
||||
GK_ATOM(onoverflow, "onoverflow")
|
||||
GK_ATOM(onoverflowchanged, "onoverflowchanged")
|
||||
|
@ -20,6 +20,9 @@
|
||||
#include "mozilla/dom/DOMStorage.h"
|
||||
#include "mozilla/dom/StorageEvent.h"
|
||||
#include "mozilla/dom/StorageEventBinding.h"
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
#include "mozilla/dom/WindowOrientationObserver.h"
|
||||
#endif
|
||||
#include "nsDOMOfflineResourceList.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIIdleService.h"
|
||||
@ -1527,6 +1530,10 @@ nsGlobalWindow::CleanUp()
|
||||
mSpeechSynthesis = nullptr;
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
mOrientationChangeObserver = nullptr;
|
||||
#endif
|
||||
|
||||
ClearControllers();
|
||||
|
||||
mOpener = nullptr; // Forces Release
|
||||
@ -1641,6 +1648,10 @@ nsGlobalWindow::FreeInnerObjects()
|
||||
mScreen = nullptr;
|
||||
}
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
mOrientationChangeObserver = nullptr;
|
||||
#endif
|
||||
|
||||
if (mDoc) {
|
||||
// Remember the document's principal and URI.
|
||||
mDocumentPrincipal = mDoc->NodePrincipal();
|
||||
@ -13654,6 +13665,27 @@ nsGlobalWindow::DisableDeviceSensor(uint32_t aType)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
void
|
||||
nsGlobalWindow::EnableOrientationChangeListener()
|
||||
{
|
||||
MOZ_ASSERT(IsInnerWindow());
|
||||
|
||||
if (!mOrientationChangeObserver) {
|
||||
mOrientationChangeObserver =
|
||||
new WindowOrientationObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::DisableOrientationChangeListener()
|
||||
{
|
||||
MOZ_ASSERT(IsInnerWindow());
|
||||
|
||||
mOrientationChangeObserver = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
nsGlobalWindow::SetHasGamepadEventListener(bool aHasGamepad/* = true*/)
|
||||
{
|
||||
@ -14501,6 +14533,15 @@ nsGlobalWindow::IsModalContentWindow(JSContext* aCx, JSObject* aGlobal)
|
||||
return xpc::WindowOrNull(aGlobal)->IsModalContentWindow();
|
||||
}
|
||||
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
int16_t
|
||||
nsGlobalWindow::Orientation() const
|
||||
{
|
||||
return WindowOrientationObserver::OrientationAngle();
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::GetConsole(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aConsole)
|
||||
|
@ -118,6 +118,9 @@ class RequestOrUSVString;
|
||||
class Selection;
|
||||
class SpeechSynthesis;
|
||||
class WakeLock;
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
class WindowOrientationObserver;
|
||||
#endif
|
||||
namespace cache {
|
||||
class CacheStorage;
|
||||
} // namespace cache
|
||||
@ -656,6 +659,11 @@ public:
|
||||
virtual void EnableDeviceSensor(uint32_t aType) override;
|
||||
virtual void DisableDeviceSensor(uint32_t aType) override;
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
virtual void EnableOrientationChangeListener() override;
|
||||
virtual void DisableOrientationChangeListener() override;
|
||||
#endif
|
||||
|
||||
virtual void EnableTimeChangeNotifications() override;
|
||||
virtual void DisableTimeChangeNotifications() override;
|
||||
|
||||
@ -907,6 +915,10 @@ public:
|
||||
mozilla::dom::Navigator* GetNavigator(mozilla::ErrorResult& aError);
|
||||
nsIDOMOfflineResourceList* GetApplicationCache(mozilla::ErrorResult& aError);
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
int16_t Orientation() const;
|
||||
#endif
|
||||
|
||||
mozilla::dom::Console* GetConsole(mozilla::ErrorResult& aRv);
|
||||
|
||||
void GetSidebar(mozilla::dom::OwningExternalOrWindowProxy& aResult,
|
||||
@ -1822,6 +1834,10 @@ protected:
|
||||
|
||||
nsTArray<uint32_t> mEnabledSensors;
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
nsAutoPtr<mozilla::dom::WindowOrientationObserver> mOrientationChangeObserver;
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
// mSpeechSynthesis is only used on inner windows.
|
||||
RefPtr<mozilla::dom::SpeechSynthesis> mSpeechSynthesis;
|
||||
|
@ -635,6 +635,11 @@ public:
|
||||
*/
|
||||
virtual void DisableDeviceSensor(uint32_t aType) = 0;
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
virtual void EnableOrientationChangeListener() = 0;
|
||||
virtual void DisableOrientationChangeListener() = 0;
|
||||
#endif
|
||||
|
||||
virtual void EnableTimeChangeNotifications() = 0;
|
||||
virtual void DisableTimeChangeNotifications() = 0;
|
||||
|
||||
|
@ -359,6 +359,8 @@ skip-if = buildapp == 'mulet'
|
||||
[test_window_extensible.html]
|
||||
[test_window_indexing.html]
|
||||
[test_window_named_frame_enumeration.html]
|
||||
[test_window_orientation.html]
|
||||
skip-if = toolkit != 'gonk'
|
||||
[test_writable-replaceable.html]
|
||||
[test_navigatorPrefOverride.html]
|
||||
[test_EventSource_redirects.html]
|
||||
|
33
dom/base/test/test_window_orientation.html
Normal file
33
dom/base/test/test_window_orientation.html
Normal file
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for window.orientation</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="orientationcommon.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
async_test(function(t) {
|
||||
var originalOrientation = screen.orientation.type;
|
||||
var alternateOrientation = originalOrientation == "portrait-primary" ?
|
||||
"landscape-primary" : "portrait-primary";
|
||||
|
||||
var originalWindowOrientation = window.orientation;
|
||||
window.onorientationchange = function() {
|
||||
t.step(function() { assert_not_equals(window.orientation, originalWindowOrientation); });
|
||||
|
||||
var p2 = specialPowersUnlock();
|
||||
p2.then(function() {
|
||||
t.done();
|
||||
}).catch(t.step_func(function(err) {
|
||||
assert_unreached("Error unlocking orientation: " + err);
|
||||
t.done();
|
||||
}));
|
||||
}
|
||||
|
||||
var p1 = specialPowersLock(alternateOrientation);
|
||||
p1.catch(t.step_func(function(err) {
|
||||
assert_unreached("Error locking orientation: " + err);
|
||||
t.done();
|
||||
}));
|
||||
}, "Test window.orientation and orientationchange.");
|
||||
</script>
|
1
dom/cache/test/mochitest/driver.js
vendored
1
dom/cache/test/mochitest/driver.js
vendored
@ -22,6 +22,7 @@ function runTests(testFile, order) {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [["dom.caches.enabled", true],
|
||||
["dom.caches.testing.enabled", true],
|
||||
["dom.requestcache.enabled", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true]]
|
||||
|
@ -80,7 +80,8 @@ ClipboardEvent::Constructor(const GlobalObject& aGlobal,
|
||||
// support other types of events, make sure that read/write privileges are
|
||||
// checked properly within DataTransfer.
|
||||
clipboardData = new DataTransfer(ToSupports(e), eCopy, false, -1);
|
||||
clipboardData->SetData(aParam.mDataType, aParam.mData);
|
||||
clipboardData->SetData(aParam.mDataType, aParam.mData, aRv);
|
||||
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -280,6 +280,12 @@ DataTransfer::GetMozUserCancelled(bool* aUserCancelled)
|
||||
|
||||
FileList*
|
||||
DataTransfer::GetFiles(ErrorResult& aRv)
|
||||
{
|
||||
return GetFilesInternal(aRv, nsContentUtils::SubjectPrincipal());
|
||||
}
|
||||
|
||||
FileList*
|
||||
DataTransfer::GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal)
|
||||
{
|
||||
if (mEventMessage != eDrop &&
|
||||
mEventMessage != eLegacyDragDrop &&
|
||||
@ -294,7 +300,7 @@ DataTransfer::GetFiles(ErrorResult& aRv)
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsIVariant> variant;
|
||||
aRv = MozGetDataAt(NS_ConvertUTF8toUTF16(kFileMime), i, getter_AddRefs(variant));
|
||||
aRv = GetDataAtInternal(NS_ConvertUTF8toUTF16(kFileMime), i, aSubjectPrincipal, getter_AddRefs(variant));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -346,7 +352,7 @@ NS_IMETHODIMP
|
||||
DataTransfer::GetFiles(nsIDOMFileList** aFileList)
|
||||
{
|
||||
ErrorResult rv;
|
||||
NS_IF_ADDREF(*aFileList = GetFiles(rv));
|
||||
NS_IF_ADDREF(*aFileList = GetFilesInternal(rv, nsContentUtils::GetSystemPrincipal()));
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
@ -391,7 +397,7 @@ DataTransfer::GetData(const nsAString& aFormat, nsAString& aData,
|
||||
aData.Truncate();
|
||||
|
||||
nsCOMPtr<nsIVariant> data;
|
||||
nsresult rv = MozGetDataAt(aFormat, 0, getter_AddRefs(data));
|
||||
nsresult rv = GetDataAtInternal(aFormat, 0, nsContentUtils::SubjectPrincipal(), getter_AddRefs(data));
|
||||
if (NS_FAILED(rv)) {
|
||||
if (rv != NS_ERROR_DOM_INDEX_SIZE_ERR) {
|
||||
aRv.Throw(rv);
|
||||
@ -450,15 +456,7 @@ DataTransfer::SetData(const nsAString& aFormat, const nsAString& aData,
|
||||
RefPtr<nsVariantCC> variant = new nsVariantCC();
|
||||
variant->SetAsAString(aData);
|
||||
|
||||
aRv = MozSetDataAt(aFormat, variant, 0);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DataTransfer::SetData(const nsAString& aFormat, const nsAString& aData)
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetData(aFormat, aData, rv);
|
||||
return rv.StealNSResult();
|
||||
aRv = SetDataAtInternal(aFormat, variant, 0, nsContentUtils::SubjectPrincipal());
|
||||
}
|
||||
|
||||
void
|
||||
@ -577,9 +575,16 @@ DataTransfer::MozTypesAt(uint32_t aIndex, nsISupports** aTypes)
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DataTransfer::MozGetDataAt(const nsAString& aFormat, uint32_t aIndex,
|
||||
nsIVariant** aData)
|
||||
nsresult
|
||||
DataTransfer::GetDataAtNoSecurityCheck(const nsAString& aFormat, uint32_t aIndex,
|
||||
nsIVariant** aData)
|
||||
{
|
||||
return GetDataAtInternal(aFormat, aIndex, nsContentUtils::GetSystemPrincipal(), aData);
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataTransfer::GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
|
||||
nsIPrincipal* aSubjectPrincipal, nsIVariant** aData)
|
||||
{
|
||||
*aData = nullptr;
|
||||
|
||||
@ -609,22 +614,18 @@ DataTransfer::MozGetDataAt(const nsAString& aFormat, uint32_t aIndex,
|
||||
// source of the drag is in a child frame of the caller. In that case,
|
||||
// we only allow access to data of the same principal. During other events,
|
||||
// only allow access to the data with the same principal.
|
||||
nsIPrincipal* principal = nullptr;
|
||||
if (mIsCrossDomainSubFrameDrop ||
|
||||
bool checkFormatItemPrincipal = mIsCrossDomainSubFrameDrop ||
|
||||
(mEventMessage != eDrop && mEventMessage != eLegacyDragDrop &&
|
||||
mEventMessage != ePaste &&
|
||||
!nsContentUtils::IsCallerChrome())) {
|
||||
principal = nsContentUtils::SubjectPrincipal();
|
||||
}
|
||||
mEventMessage != ePaste);
|
||||
|
||||
uint32_t count = item.Length();
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
TransferItem& formatitem = item[i];
|
||||
if (formatitem.mFormat.Equals(format)) {
|
||||
bool subsumes;
|
||||
if (formatitem.mPrincipal && principal &&
|
||||
(NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes))
|
||||
if (formatitem.mPrincipal && checkFormatItemPrincipal &&
|
||||
!aSubjectPrincipal->Subsumes(formatitem.mPrincipal)) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
if (!formatitem.mData) {
|
||||
FillInExternalData(formatitem, aIndex);
|
||||
@ -643,12 +644,7 @@ DataTransfer::MozGetDataAt(const nsAString& aFormat, uint32_t aIndex,
|
||||
MOZ_ASSERT(sp, "This cannot fail on the main thread.");
|
||||
nsIPrincipal* dataPrincipal = sp->GetPrincipal();
|
||||
NS_ENSURE_TRUE(dataPrincipal, NS_ERROR_DOM_SECURITY_ERR);
|
||||
if (!principal) {
|
||||
principal = nsContentUtils::SubjectPrincipal();
|
||||
}
|
||||
bool equals = false;
|
||||
NS_ENSURE_TRUE(NS_SUCCEEDED(principal->Equals(dataPrincipal, &equals)) && equals,
|
||||
NS_ERROR_DOM_SECURITY_ERR);
|
||||
NS_ENSURE_TRUE(aSubjectPrincipal->Subsumes(dataPrincipal), NS_ERROR_DOM_SECURITY_ERR);
|
||||
}
|
||||
}
|
||||
*aData = formatitem.mData;
|
||||
@ -667,7 +663,7 @@ DataTransfer::MozGetDataAt(JSContext* aCx, const nsAString& aFormat,
|
||||
mozilla::ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIVariant> data;
|
||||
aRv = MozGetDataAt(aFormat, aIndex, getter_AddRefs(data));
|
||||
aRv = GetDataAtInternal(aFormat, aIndex, nsContentUtils::SubjectPrincipal(), getter_AddRefs(data));
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
@ -684,9 +680,9 @@ DataTransfer::MozGetDataAt(JSContext* aCx, const nsAString& aFormat,
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DataTransfer::MozSetDataAt(const nsAString& aFormat, nsIVariant* aData,
|
||||
uint32_t aIndex)
|
||||
nsresult
|
||||
DataTransfer::SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData,
|
||||
uint32_t aIndex, nsIPrincipal* aSubjectPrincipal)
|
||||
{
|
||||
if (aFormat.IsEmpty()) {
|
||||
return NS_OK;
|
||||
@ -713,12 +709,11 @@ DataTransfer::MozSetDataAt(const nsAString& aFormat, nsIVariant* aData,
|
||||
// XXX perhaps this should also limit any non-string type as well
|
||||
if ((aFormat.EqualsLiteral("application/x-moz-file-promise") ||
|
||||
aFormat.EqualsLiteral("application/x-moz-file")) &&
|
||||
!nsContentUtils::IsCallerChrome()) {
|
||||
!nsContentUtils::IsSystemPrincipal(aSubjectPrincipal)) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
return SetDataWithPrincipal(aFormat, aData, aIndex,
|
||||
nsContentUtils::SubjectPrincipal());
|
||||
return SetDataWithPrincipal(aFormat, aData, aIndex, aSubjectPrincipal);
|
||||
}
|
||||
|
||||
void
|
||||
@ -730,7 +725,7 @@ DataTransfer::MozSetDataAt(JSContext* aCx, const nsAString& aFormat,
|
||||
aRv = nsContentUtils::XPConnect()->JSValToVariant(aCx, aData,
|
||||
getter_AddRefs(data));
|
||||
if (!aRv.Failed()) {
|
||||
aRv = MozSetDataAt(aFormat, data, aIndex);
|
||||
aRv = SetDataAtInternal(aFormat, data, aIndex, nsContentUtils::SubjectPrincipal());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,8 @@ public:
|
||||
|
||||
friend class mozilla::EventStateManager;
|
||||
|
||||
static DataTransfer* Cast(nsIDOMDataTransfer* aArg) { return static_cast<DataTransfer*>(aArg); }
|
||||
|
||||
protected:
|
||||
|
||||
// hide the default constructor
|
||||
@ -183,6 +185,9 @@ public:
|
||||
return mDragTarget;
|
||||
}
|
||||
|
||||
nsresult GetDataAtNoSecurityCheck(const nsAString& aFormat, uint32_t aIndex,
|
||||
nsIVariant** aData);
|
||||
|
||||
// a readonly dataTransfer cannot have new data added or existing data removed.
|
||||
// Only the dropEffect and effectAllowed may be modified.
|
||||
void SetReadOnly() { mReadOnly = true; }
|
||||
@ -246,6 +251,13 @@ protected:
|
||||
// clipboard for a given index.
|
||||
void FillInExternalData(TransferItem& aItem, uint32_t aIndex);
|
||||
|
||||
|
||||
FileList* GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal);
|
||||
nsresult GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
|
||||
nsIPrincipal* aSubjectPrincipal, nsIVariant** aData);
|
||||
nsresult SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData, uint32_t aIndex,
|
||||
nsIPrincipal* aSubjectPrincipal);
|
||||
|
||||
friend class ContentParent;
|
||||
void FillAllExternalData();
|
||||
|
||||
|
@ -325,6 +325,10 @@ EventListenerManager::AddEventListenerInternal(
|
||||
EnableDevice(eDeviceLight);
|
||||
} else if (aTypeAtom == nsGkAtoms::ondevicemotion) {
|
||||
EnableDevice(eDeviceMotion);
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
} else if (aTypeAtom == nsGkAtoms::onorientationchange) {
|
||||
EnableDevice(eOrientationChange);
|
||||
#endif
|
||||
#ifdef MOZ_B2G
|
||||
} else if (aTypeAtom == nsGkAtoms::onmoztimechange) {
|
||||
nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
|
||||
@ -431,6 +435,9 @@ EventListenerManager::IsDeviceType(EventMessage aEventMessage)
|
||||
case eDeviceLight:
|
||||
case eDeviceProximity:
|
||||
case eUserProximity:
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
case eOrientationChange:
|
||||
#endif
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
@ -462,6 +469,11 @@ EventListenerManager::EnableDevice(EventMessage aEventMessage)
|
||||
window->EnableDeviceSensor(SENSOR_LINEAR_ACCELERATION);
|
||||
window->EnableDeviceSensor(SENSOR_GYROSCOPE);
|
||||
break;
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
case eOrientationChange:
|
||||
window->EnableOrientationChangeListener();
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
NS_WARNING("Enabling an unknown device sensor.");
|
||||
break;
|
||||
@ -492,6 +504,11 @@ EventListenerManager::DisableDevice(EventMessage aEventMessage)
|
||||
case eDeviceLight:
|
||||
window->DisableDeviceSensor(SENSOR_LIGHT);
|
||||
break;
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
case eOrientationChange:
|
||||
window->DisableOrientationChangeListener();
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
NS_WARNING("Disabling an unknown device sensor.");
|
||||
break;
|
||||
|
@ -507,6 +507,12 @@ WINDOW_EVENT(online,
|
||||
eOnline,
|
||||
EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
|
||||
eBasicEventClass)
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
WINDOW_EVENT(orientationchange,
|
||||
eOrientationChange,
|
||||
EventNameType_HTMLBodyOrFramesetOnly,
|
||||
eBasicEventClass)
|
||||
#endif
|
||||
WINDOW_EVENT(pagehide,
|
||||
ePageHide,
|
||||
EventNameType_HTMLBodyOrFramesetOnly,
|
||||
|
@ -64,6 +64,25 @@ Request::RequestContextEnabled(JSContext* aCx, JSObject* aObj)
|
||||
return workerPrivate->RequestContextEnabled();
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
Request::RequestCacheEnabled(JSContext* aCx, JSObject* aObj)
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
return Preferences::GetBool("dom.requestcache.enabled", false);
|
||||
}
|
||||
|
||||
using namespace workers;
|
||||
|
||||
// Otherwise, check the pref via the WorkerPrivate
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
||||
if (!workerPrivate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return workerPrivate->RequestCacheEnabled();
|
||||
}
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
Request::GetInternalRequest()
|
||||
{
|
||||
|
@ -36,6 +36,8 @@ public:
|
||||
|
||||
static bool
|
||||
RequestContextEnabled(JSContext* aCx, JSObject* aObj);
|
||||
static bool
|
||||
RequestCacheEnabled(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
|
||||
|
19
dom/html/crashtests/495546-1.html
Normal file
19
dom/html/crashtests/495546-1.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
|
||||
function boom()
|
||||
{
|
||||
var video = document.createElement("video");
|
||||
var source = document.createElement("source");
|
||||
source.setAttributeNS(null, "src", "http://127.0.0.1/");
|
||||
video.appendChild(source);
|
||||
document.body.appendChild(video);
|
||||
setTimeout(function() { document.body.removeChild(video); }, 20);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();"></body>
|
||||
</html>
|
@ -23,6 +23,7 @@ load 468562-1.html
|
||||
load 468562-2.html
|
||||
load 494225.html
|
||||
load 495543.svg
|
||||
load 495546-1.html
|
||||
load 504183-1.html
|
||||
load 515829-1.html
|
||||
load 515829-2.html
|
||||
|
@ -8,7 +8,7 @@
|
||||
interface nsIVariant;
|
||||
interface nsIDOMFileList;
|
||||
|
||||
[builtinclass, uuid(c71180e3-298b-4fbb-9ccb-82c822474741)]
|
||||
[builtinclass, uuid(655078bf-1675-4aa0-a48d-a133e864ce57)]
|
||||
interface nsIDOMDataTransfer : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -81,17 +81,6 @@ interface nsIDOMDataTransfer : nsISupports
|
||||
*/
|
||||
void clearData([optional] in DOMString format);
|
||||
|
||||
/**
|
||||
* Set the data for a given format. If data for the format does not exist,
|
||||
* it is added at the end, such that the last item in the types list will be
|
||||
* the new format. If data for the format already exists, the existing data
|
||||
* is replaced in the same position. That is, the order of the types list is
|
||||
* not changed.
|
||||
*
|
||||
* @throws NS_ERROR_NULL_POINTER if the data is null
|
||||
*/
|
||||
void setData(in DOMString format, in DOMString data);
|
||||
|
||||
/**
|
||||
* Retrieves the data for a given format, or an empty string if data for
|
||||
* that format does not exist or the data transfer contains no data.
|
||||
@ -171,40 +160,6 @@ interface nsIDOMDataTransfer : nsISupports
|
||||
*/
|
||||
void mozClearDataAt(in DOMString format, in unsigned long index);
|
||||
|
||||
/*
|
||||
* A data transfer may store multiple items, each at a given zero-based
|
||||
* index. setDataAt may only be called with an index argument less than
|
||||
* itemCount in which case an existing item is modified, or equal to
|
||||
* itemCount in which case a new item is added, and the itemCount is
|
||||
* incremented by one.
|
||||
*
|
||||
* Data should be added in order of preference, with the most specific
|
||||
* format added first and the least specific format added last. If data of
|
||||
* the given format already exists, it is replaced in the same position as
|
||||
* the old data.
|
||||
*
|
||||
* The data should be either a string, a primitive boolean or number type
|
||||
* (which will be converted into a string) or an nsISupports.
|
||||
*
|
||||
* @param format the format to add
|
||||
* @param data the data to add
|
||||
* @throws NS_ERROR_NULL_POINTER if the data is null
|
||||
* @throws NS_ERROR_DOM_INDEX_SIZE_ERR if index is greater than itemCount
|
||||
* @throws NO_MODIFICATION_ALLOWED_ERR if the item cannot be modified
|
||||
*/
|
||||
void mozSetDataAt(in DOMString format, in nsIVariant data, in unsigned long index);
|
||||
|
||||
/**
|
||||
* Retrieve the data associated with the given format for an item at the
|
||||
* specified index, or null if it does not exist. The index should be in the
|
||||
* range from zero to itemCount - 1.
|
||||
*
|
||||
* @param format the format of the data to look up
|
||||
* @returns the data of the given format, or null if it doesn't exist.
|
||||
* @throws NS_ERROR_DOM_INDEX_SIZE_ERR if index is greater or equal than itemCount
|
||||
*/
|
||||
nsIVariant mozGetDataAt(in DOMString format, in unsigned long index);
|
||||
|
||||
/**
|
||||
* Will be true when the user has cancelled the drag (typically by pressing
|
||||
* Escape) and when the drag has been cancelled unexpectedly. This will be
|
||||
|
@ -151,7 +151,6 @@ public:
|
||||
NS_IMETHOD BeginStartingDebugger() override;
|
||||
NS_IMETHOD EndStartingDebugger() override;
|
||||
NS_IMETHOD TerminatePlugin() override;
|
||||
NS_IMETHOD TerminateProcess() override;
|
||||
NS_IMETHOD UserCanceled() override;
|
||||
|
||||
NS_IMETHOD IsReportForBrowser(nsIFrameLoader* aFrameLoader, bool* aResult) override;
|
||||
@ -820,6 +819,8 @@ HangMonitoredProcess::TerminatePlugin()
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// generates a crash report that includes a browser report taken here
|
||||
// earlier, the content process, and any plugin process(es).
|
||||
uint32_t id = mHangData.get_PluginHangData().pluginId();
|
||||
plugins::TerminatePlugin(id, NS_LITERAL_CSTRING("HangMonitor"),
|
||||
mBrowserDumpId);
|
||||
@ -830,24 +831,6 @@ HangMonitoredProcess::TerminatePlugin()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HangMonitoredProcess::TerminateProcess()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mContentParent) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (mActor && mHangData.type() == HangData::TPluginHangData) {
|
||||
uint32_t id = mHangData.get_PluginHangData().pluginId();
|
||||
mActor->CleanupPluginHang(id, true);
|
||||
}
|
||||
|
||||
mContentParent->KillHard("HangMonitor");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HangMonitoredProcess::IsReportForBrowser(nsIFrameLoader* aFrameLoader, bool* aResult)
|
||||
{
|
||||
|
@ -18,7 +18,7 @@ interface nsIFrameLoader;
|
||||
* process will continue to run uninhibitedly during this time.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(90cea731-dd3e-459e-b017-f9a14697b56e)]
|
||||
[scriptable, uuid(5fcffbb9-be62-49b1-b8a1-36e820787a74)]
|
||||
interface nsIHangReport : nsISupports
|
||||
{
|
||||
const unsigned long SLOW_SCRIPT = 1;
|
||||
@ -50,10 +50,6 @@ interface nsIHangReport : nsISupports
|
||||
// Only valid for PLUGIN_HANG reports.
|
||||
void terminatePlugin();
|
||||
|
||||
// Terminate the hung content process unconditionally.
|
||||
// Valid for any type of hang.
|
||||
void terminateProcess();
|
||||
|
||||
// Ask the content process to start up the slow script debugger.
|
||||
// Only valid for SLOW_SCRIPT reports.
|
||||
void beginStartingDebugger();
|
||||
|
@ -501,11 +501,11 @@ StreamAndPromiseForOperation::StreamAndPromiseForOperation(MediaStream* aStream,
|
||||
// MOZ_ASSERT(aPromise);
|
||||
}
|
||||
|
||||
AudioCallbackDriver::AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl, dom::AudioChannel aChannel)
|
||||
AudioCallbackDriver::AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl)
|
||||
: GraphDriver(aGraphImpl)
|
||||
, mIterationDurationMS(MEDIA_GRAPH_TARGET_PERIOD_MS)
|
||||
, mStarted(false)
|
||||
, mAudioChannel(aChannel)
|
||||
, mAudioChannel(aGraphImpl->AudioChannel())
|
||||
, mInCallback(false)
|
||||
, mPauseRequested(false)
|
||||
#ifdef XP_MACOSX
|
||||
|
@ -329,8 +329,7 @@ class AudioCallbackDriver : public GraphDriver,
|
||||
public MixerCallbackReceiver
|
||||
{
|
||||
public:
|
||||
explicit AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl,
|
||||
dom::AudioChannel aChannel = dom::AudioChannel::Normal);
|
||||
explicit AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl);
|
||||
virtual ~AudioCallbackDriver();
|
||||
|
||||
virtual void Destroy() override;
|
||||
|
@ -1409,9 +1409,9 @@ MediaStreamGraphImpl::RunInStableState(bool aSourceIsMSG)
|
||||
|
||||
LIFECYCLE_LOG("Disconnecting MediaStreamGraph %p", this);
|
||||
MediaStreamGraphImpl* graph;
|
||||
if (gGraphs.Get(mAudioChannel, &graph) && graph == this) {
|
||||
if (gGraphs.Get(uint32_t(mAudioChannel), &graph) && graph == this) {
|
||||
// null out gGraph if that's the graph being shut down
|
||||
gGraphs.Remove(mAudioChannel);
|
||||
gGraphs.Remove(uint32_t(mAudioChannel));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1566,8 +1566,8 @@ MediaStreamGraphImpl::AppendMessage(ControlMessage* aMessage)
|
||||
mLifecycleState >= LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION) {
|
||||
|
||||
MediaStreamGraphImpl* graph;
|
||||
if (gGraphs.Get(mAudioChannel, &graph) && graph == this) {
|
||||
gGraphs.Remove(mAudioChannel);
|
||||
if (gGraphs.Get(uint32_t(mAudioChannel), &graph) && graph == this) {
|
||||
gGraphs.Remove(uint32_t(mAudioChannel));
|
||||
}
|
||||
|
||||
Destroy();
|
||||
@ -1653,7 +1653,7 @@ MediaStream::SetGraphImpl(MediaStreamGraphImpl* aGraph)
|
||||
{
|
||||
MOZ_ASSERT(!mGraph, "Should only be called once");
|
||||
mGraph = aGraph;
|
||||
mAudioChannelType = static_cast<AudioChannel>(aGraph->AudioChannel());
|
||||
mAudioChannelType = aGraph->AudioChannel();
|
||||
mBuffer.InitGraphRate(aGraph->GraphRate());
|
||||
}
|
||||
|
||||
@ -2567,7 +2567,7 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
|
||||
#ifdef DEBUG
|
||||
, mCanRunMessagesSynchronously(false)
|
||||
#endif
|
||||
, mAudioChannel(static_cast<uint32_t>(aChannel))
|
||||
, mAudioChannel(aChannel)
|
||||
{
|
||||
if (!gMediaStreamGraphLog) {
|
||||
gMediaStreamGraphLog = PR_NewLogModule("MediaStreamGraph");
|
||||
@ -2575,7 +2575,7 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
|
||||
|
||||
if (mRealtime) {
|
||||
if (aDriverRequested == AUDIO_THREAD_DRIVER) {
|
||||
AudioCallbackDriver* driver = new AudioCallbackDriver(this, aChannel);
|
||||
AudioCallbackDriver* driver = new AudioCallbackDriver(this);
|
||||
mDriver = driver;
|
||||
mMixer.AddCallback(driver);
|
||||
} else {
|
||||
@ -3082,7 +3082,7 @@ MediaStreamGraph::IsNonRealtime() const
|
||||
const MediaStreamGraphImpl* impl = static_cast<const MediaStreamGraphImpl*>(this);
|
||||
MediaStreamGraphImpl* graph;
|
||||
|
||||
return !gGraphs.Get(impl->AudioChannel(), &graph) || graph != impl;
|
||||
return !gGraphs.Get(uint32_t(impl->AudioChannel()), &graph) || graph != impl;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -717,7 +717,7 @@ public:
|
||||
RefPtr<AudioOutputObserver> mFarendObserverRef;
|
||||
#endif
|
||||
|
||||
uint32_t AudioChannel() const { return mAudioChannel; }
|
||||
dom::AudioChannel AudioChannel() const { return mAudioChannel; }
|
||||
|
||||
private:
|
||||
virtual ~MediaStreamGraphImpl();
|
||||
@ -762,9 +762,7 @@ private:
|
||||
bool mCanRunMessagesSynchronously;
|
||||
#endif
|
||||
|
||||
// We use uint32_t instead AudioChannel because this is just used as key for
|
||||
// the hashtable gGraphs.
|
||||
uint32_t mAudioChannel;
|
||||
dom::AudioChannel mAudioChannel;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -29,8 +29,10 @@ namespace dom {
|
||||
class SynthStreamListener : public MediaStreamListener
|
||||
{
|
||||
public:
|
||||
explicit SynthStreamListener(nsSpeechTask* aSpeechTask) :
|
||||
explicit SynthStreamListener(nsSpeechTask* aSpeechTask,
|
||||
MediaStream* aStream) :
|
||||
mSpeechTask(aSpeechTask),
|
||||
mStream(aStream),
|
||||
mStarted(false)
|
||||
{
|
||||
}
|
||||
@ -63,6 +65,8 @@ public:
|
||||
break;
|
||||
case EVENT_REMOVED:
|
||||
mSpeechTask = nullptr;
|
||||
// Dereference MediaStream to destroy safety
|
||||
mStream = nullptr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -83,6 +87,8 @@ private:
|
||||
// Raw pointer; if we exist, the stream exists,
|
||||
// and 'mSpeechTask' exclusively owns it and therefor exists as well.
|
||||
nsSpeechTask* mSpeechTask;
|
||||
// This is KungFuDeathGrip for MediaStream
|
||||
RefPtr<MediaStream> mStream;
|
||||
|
||||
bool mStarted;
|
||||
};
|
||||
@ -132,6 +138,8 @@ nsSpeechTask::~nsSpeechTask()
|
||||
mStream->Destroy();
|
||||
}
|
||||
|
||||
// This will finally destroyed by SynthStreamListener becasue
|
||||
// MediaStream::Destroy() is async.
|
||||
mStream = nullptr;
|
||||
}
|
||||
|
||||
@ -185,7 +193,7 @@ nsSpeechTask::Setup(nsISpeechTaskCallback* aCallback,
|
||||
// mStream is set up in Init() that should be called before this.
|
||||
MOZ_ASSERT(mStream);
|
||||
|
||||
mStream->AddListener(new SynthStreamListener(this));
|
||||
mStream->AddListener(new SynthStreamListener(this, mStream));
|
||||
|
||||
// XXX: Support more than one channel
|
||||
if(NS_WARN_IF(!(aChannels == 1))) {
|
||||
@ -711,7 +719,7 @@ nsSpeechTask::WindowAudioCaptureChanged()
|
||||
void
|
||||
nsSpeechTask::SetAudioOutputVolume(float aVolume)
|
||||
{
|
||||
if (mStream) {
|
||||
if (mStream && !mStream->IsDestroyed()) {
|
||||
mStream->SetAudioOutputVolume(this, aVolume);
|
||||
}
|
||||
if (mIndirectAudio) {
|
||||
|
@ -7,7 +7,8 @@ function testScript(script) {
|
||||
function setupPrefs() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [["dom.requestcontext.enabled", true],
|
||||
"set": [["dom.requestcache.enabled", true],
|
||||
["dom.requestcontext.enabled", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true]]
|
||||
|
@ -36,6 +36,7 @@ skip-if = buildapp == 'b2g' || (toolkit == 'android' && debug) # Bug 1137683 &&
|
||||
[test_formdataparsing_sw_reroute.html]
|
||||
skip-if = buildapp == 'b2g' # Bug 1137683
|
||||
[test_request.html]
|
||||
[test_request_cache.html]
|
||||
[test_request_context.html]
|
||||
[test_request_sw_reroute.html]
|
||||
skip-if = buildapp == 'b2g' # Bug 1137683
|
||||
|
@ -10,7 +10,8 @@ function testScript(script) {
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [["dom.serviceWorkers.enabled", true],
|
||||
"set": [["dom.requestcache.enabled", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.interception.opaque.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true]]
|
||||
|
19
dom/tests/mochitest/fetch/test_request_cache.html
Normal file
19
dom/tests/mochitest/fetch/test_request_cache.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Make sure that Request.cache is not exposed by default</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
var req = new Request("");
|
||||
ok(!("cache" in req), "Request.cache should not be exposed by default");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -212,7 +212,7 @@ function checkEntries(anEntryList) {
|
||||
function firstCheck() {
|
||||
is(window.performance.getEntriesByType("resource").length, 1, "The first xhr entry was not added.");
|
||||
is(window.performance.getEntriesByType("resource")[0].initiatorType, "xmlhttprequest",
|
||||
"The initiatorType is incorect for this entry");
|
||||
"The initiatorType is incorrect for this entry");
|
||||
makeXhr("test-data2.json", secondCheck);
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ interface Clients {
|
||||
// The objects returned will be new instances every time
|
||||
[Throws]
|
||||
Promise<sequence<Client>?> matchAll(optional ClientQueryOptions options);
|
||||
[Throws, Func="mozilla::dom::workers::ServiceWorkerGlobalScope::OpenWindowEnabled"]
|
||||
Promise<WindowClient> openWindow(USVString url);
|
||||
[Throws]
|
||||
Promise<void> claim();
|
||||
|
@ -22,6 +22,7 @@ interface Request {
|
||||
readonly attribute DOMString referrer;
|
||||
readonly attribute RequestMode mode;
|
||||
readonly attribute RequestCredentials credentials;
|
||||
[Func="mozilla::dom::Request::RequestCacheEnabled"]
|
||||
readonly attribute RequestCache cache;
|
||||
readonly attribute RequestRedirect redirect;
|
||||
|
||||
|
@ -398,6 +398,14 @@ Window implements TouchEventHandlers;
|
||||
|
||||
Window implements OnErrorEventHandlerForWindow;
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
// https://compat.spec.whatwg.org/#windoworientation-interface
|
||||
partial interface Window {
|
||||
readonly attribute short orientation;
|
||||
attribute EventHandler onorientationchange;
|
||||
};
|
||||
#endif
|
||||
|
||||
// ConsoleAPI
|
||||
partial interface Window {
|
||||
[Replaceable, GetterThrows]
|
||||
|
@ -168,7 +168,9 @@ static_assert(MAX_WORKERS_PER_DOMAIN >= 1,
|
||||
#define PREF_SERVICEWORKERS_TESTING_ENABLED "dom.serviceWorkers.testing.enabled"
|
||||
#define PREF_INTERCEPTION_ENABLED "dom.serviceWorkers.interception.enabled"
|
||||
#define PREF_INTERCEPTION_OPAQUE_ENABLED "dom.serviceWorkers.interception.opaque.enabled"
|
||||
#define PREF_OPEN_WINDOW_ENABLED "dom.serviceWorkers.openWindow.enabled"
|
||||
#define PREF_PUSH_ENABLED "dom.push.enabled"
|
||||
#define PREF_REQUESTCACHE_ENABLED "dom.requestcache.enabled"
|
||||
#define PREF_REQUESTCONTEXT_ENABLED "dom.requestcontext.enabled"
|
||||
#define PREF_OFFSCREENCANVAS_ENABLED "gfx.offscreencanvas.enabled"
|
||||
|
||||
@ -1940,6 +1942,10 @@ RuntimeService::Init()
|
||||
WorkerPrefChanged,
|
||||
PREF_INTERCEPTION_ENABLED,
|
||||
reinterpret_cast<void *>(WORKERPREF_INTERCEPTION_ENABLED))) ||
|
||||
NS_FAILED(Preferences::RegisterCallbackAndCall(
|
||||
WorkerPrefChanged,
|
||||
PREF_OPEN_WINDOW_ENABLED,
|
||||
reinterpret_cast<void *>(WORKERPREF_OPEN_WINDOW_ENABLED))) ||
|
||||
NS_FAILED(Preferences::RegisterCallbackAndCall(
|
||||
WorkerPrefChanged,
|
||||
PREF_INTERCEPTION_OPAQUE_ENABLED,
|
||||
@ -1960,6 +1966,10 @@ RuntimeService::Init()
|
||||
WorkerPrefChanged,
|
||||
PREF_PUSH_ENABLED,
|
||||
reinterpret_cast<void *>(WORKERPREF_PUSH))) ||
|
||||
NS_FAILED(Preferences::RegisterCallbackAndCall(
|
||||
WorkerPrefChanged,
|
||||
PREF_REQUESTCACHE_ENABLED,
|
||||
reinterpret_cast<void *>(WORKERPREF_REQUESTCACHE))) ||
|
||||
NS_FAILED(Preferences::RegisterCallbackAndCall(
|
||||
WorkerPrefChanged,
|
||||
PREF_REQUESTCONTEXT_ENABLED,
|
||||
@ -2183,6 +2193,10 @@ RuntimeService::Cleanup()
|
||||
WorkerPrefChanged,
|
||||
PREF_INTERCEPTION_ENABLED,
|
||||
reinterpret_cast<void *>(WORKERPREF_INTERCEPTION_ENABLED))) ||
|
||||
NS_FAILED(Preferences::UnregisterCallback(
|
||||
WorkerPrefChanged,
|
||||
PREF_OPEN_WINDOW_ENABLED,
|
||||
reinterpret_cast<void *>(WORKERPREF_OPEN_WINDOW_ENABLED))) ||
|
||||
NS_FAILED(Preferences::UnregisterCallback(
|
||||
WorkerPrefChanged,
|
||||
PREF_SERVICEWORKERS_ENABLED,
|
||||
@ -2203,6 +2217,10 @@ RuntimeService::Cleanup()
|
||||
WorkerPrefChanged,
|
||||
PREF_PUSH_ENABLED,
|
||||
reinterpret_cast<void *>(WORKERPREF_PUSH))) ||
|
||||
NS_FAILED(Preferences::UnregisterCallback(
|
||||
WorkerPrefChanged,
|
||||
PREF_REQUESTCACHE_ENABLED,
|
||||
reinterpret_cast<void *>(WORKERPREF_REQUESTCACHE))) ||
|
||||
NS_FAILED(Preferences::UnregisterCallback(
|
||||
WorkerPrefChanged,
|
||||
PREF_REQUESTCONTEXT_ENABLED,
|
||||
@ -2785,9 +2803,11 @@ RuntimeService::WorkerPrefChanged(const char* aPrefName, void* aClosure)
|
||||
#endif
|
||||
case WORKERPREF_INTERCEPTION_ENABLED:
|
||||
case WORKERPREF_INTERCEPTION_OPAQUE_ENABLED:
|
||||
case WORKERPREF_OPEN_WINDOW_ENABLED:
|
||||
case WORKERPREF_SERVICEWORKERS:
|
||||
case WORKERPREF_SERVICEWORKERS_TESTING:
|
||||
case WORKERPREF_PUSH:
|
||||
case WORKERPREF_REQUESTCACHE:
|
||||
case WORKERPREF_REQUESTCONTEXT:
|
||||
case WORKERPREF_OFFSCREENCANVAS:
|
||||
sDefaultPreferences[key] = Preferences::GetBool(aPrefName, false);
|
||||
|
@ -16,6 +16,15 @@
|
||||
#include "WorkerRunnable.h"
|
||||
#include "WorkerScope.h"
|
||||
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDOMChromeWindow.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsIWindowMediator.h"
|
||||
#include "nsIWebProgress.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::dom::workers;
|
||||
@ -199,6 +208,337 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class ResolveOpenWindowRunnable final : public WorkerRunnable
|
||||
{
|
||||
public:
|
||||
ResolveOpenWindowRunnable(PromiseWorkerProxy* aPromiseProxy,
|
||||
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
|
||||
const nsresult aStatus)
|
||||
: WorkerRunnable(aPromiseProxy->GetWorkerPrivate(), WorkerThreadModifyBusyCount)
|
||||
, mPromiseProxy(aPromiseProxy)
|
||||
, mClientInfo(Move(aClientInfo))
|
||||
, mStatus(aStatus)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aPromiseProxy);
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
Promise* promise = mPromiseProxy->WorkerPromise();
|
||||
if (NS_WARN_IF(NS_FAILED(mStatus))) {
|
||||
promise->MaybeReject(mStatus);
|
||||
} else if (mClientInfo) {
|
||||
RefPtr<ServiceWorkerWindowClient> client =
|
||||
new ServiceWorkerWindowClient(promise->GetParentObject(),
|
||||
*mClientInfo);
|
||||
promise->MaybeResolve(client);
|
||||
} else {
|
||||
promise->MaybeResolve(JS::NullHandleValue);
|
||||
}
|
||||
|
||||
mPromiseProxy->CleanUp(aCx);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<PromiseWorkerProxy> mPromiseProxy;
|
||||
UniquePtr<ServiceWorkerClientInfo> mClientInfo;
|
||||
const nsresult mStatus;
|
||||
};
|
||||
|
||||
class WebProgressListener final : public nsIWebProgressListener,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(WebProgressListener, nsIWebProgressListener)
|
||||
|
||||
WebProgressListener(PromiseWorkerProxy* aPromiseProxy,
|
||||
ServiceWorkerPrivate* aServiceWorkerPrivate,
|
||||
nsPIDOMWindow* aWindow,
|
||||
nsIURI* aBaseURI)
|
||||
: mPromiseProxy(aPromiseProxy)
|
||||
, mServiceWorkerPrivate(aServiceWorkerPrivate)
|
||||
, mWindow(aWindow)
|
||||
, mBaseURI(aBaseURI)
|
||||
{
|
||||
MOZ_ASSERT(aPromiseProxy);
|
||||
MOZ_ASSERT(aServiceWorkerPrivate);
|
||||
MOZ_ASSERT(aWindow);
|
||||
MOZ_ASSERT(aWindow->IsOuterWindow());
|
||||
MOZ_ASSERT(aBaseURI);
|
||||
AssertIsOnMainThread();
|
||||
|
||||
mServiceWorkerPrivate->StoreISupports(static_cast<nsIWebProgressListener*>(this));
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnStateChange(nsIWebProgress* aWebProgress,
|
||||
nsIRequest* aRequest,
|
||||
uint32_t aStateFlags, nsresult aStatus) override
|
||||
{
|
||||
if (!(aStateFlags & STATE_IS_DOCUMENT) ||
|
||||
!(aStateFlags & (STATE_STOP | STATE_TRANSFERRING))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Our caller keeps a strong reference, so it is safe to remove the listener
|
||||
// from ServiceWorkerPrivate.
|
||||
mServiceWorkerPrivate->RemoveISupports(static_cast<nsIWebProgressListener*>(this));
|
||||
aWebProgress->RemoveProgressListener(this);
|
||||
|
||||
MutexAutoLock lock(mPromiseProxy->Lock());
|
||||
if (mPromiseProxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
|
||||
UniquePtr<ServiceWorkerClientInfo> clientInfo;
|
||||
if (doc) {
|
||||
// Check same origin.
|
||||
nsCOMPtr<nsIScriptSecurityManager> securityManager =
|
||||
nsContentUtils::GetSecurityManager();
|
||||
nsresult rv = securityManager->CheckSameOriginURI(doc->GetOriginalURI(),
|
||||
mBaseURI, false);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
clientInfo.reset(new ServiceWorkerClientInfo(doc));
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<ResolveOpenWindowRunnable> r =
|
||||
new ResolveOpenWindowRunnable(mPromiseProxy,
|
||||
Move(clientInfo),
|
||||
NS_OK);
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
JSContext* cx = jsapi.cx();
|
||||
r->Dispatch(cx);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnProgressChange(nsIWebProgress* aWebProgress,
|
||||
nsIRequest* aRequest,
|
||||
int32_t aCurSelfProgress,
|
||||
int32_t aMaxSelfProgress,
|
||||
int32_t aCurTotalProgress,
|
||||
int32_t aMaxTotalProgress) override
|
||||
{
|
||||
MOZ_ASSERT(false, "Unexpected notification.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnLocationChange(nsIWebProgress* aWebProgress,
|
||||
nsIRequest* aRequest,
|
||||
nsIURI* aLocation,
|
||||
uint32_t aFlags) override
|
||||
{
|
||||
MOZ_ASSERT(false, "Unexpected notification.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnStatusChange(nsIWebProgress* aWebProgress,
|
||||
nsIRequest* aRequest,
|
||||
nsresult aStatus, const char16_t* aMessage) override
|
||||
{
|
||||
MOZ_ASSERT(false, "Unexpected notification.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnSecurityChange(nsIWebProgress* aWebProgress,
|
||||
nsIRequest* aRequest,
|
||||
uint32_t aState) override
|
||||
{
|
||||
MOZ_ASSERT(false, "Unexpected notification.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~WebProgressListener()
|
||||
{ }
|
||||
|
||||
RefPtr<PromiseWorkerProxy> mPromiseProxy;
|
||||
RefPtr<ServiceWorkerPrivate> mServiceWorkerPrivate;
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
nsCOMPtr<nsIURI> mBaseURI;
|
||||
};
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebProgressListener)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebProgressListener)
|
||||
NS_IMPL_CYCLE_COLLECTION(WebProgressListener, mPromiseProxy,
|
||||
mServiceWorkerPrivate, mWindow)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebProgressListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
class OpenWindowRunnable final : public nsRunnable
|
||||
{
|
||||
RefPtr<PromiseWorkerProxy> mPromiseProxy;
|
||||
nsString mUrl;
|
||||
nsString mScope;
|
||||
|
||||
public:
|
||||
OpenWindowRunnable(PromiseWorkerProxy* aPromiseProxy,
|
||||
const nsAString& aUrl,
|
||||
const nsAString& aScope)
|
||||
: mPromiseProxy(aPromiseProxy)
|
||||
, mUrl(aUrl)
|
||||
, mScope(aScope)
|
||||
{
|
||||
MOZ_ASSERT(aPromiseProxy);
|
||||
MOZ_ASSERT(aPromiseProxy->GetWorkerPrivate());
|
||||
aPromiseProxy->GetWorkerPrivate()->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
MutexAutoLock lock(mPromiseProxy->Lock());
|
||||
if (mPromiseProxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window;
|
||||
nsresult rv = OpenWindow(getter_AddRefs(window));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
MOZ_ASSERT(window);
|
||||
|
||||
WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
WorkerPrivate::LocationInfo& info = workerPrivate->GetLocationInfo();
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(baseURI), info.mOrigin);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
|
||||
nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
|
||||
|
||||
if (!webProgress) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
MOZ_ASSERT(swm);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal();
|
||||
MOZ_ASSERT(principal);
|
||||
RefPtr<ServiceWorkerRegistrationInfo> registration =
|
||||
swm->GetRegistration(principal, NS_ConvertUTF16toUTF8(mScope));
|
||||
if (NS_WARN_IF(!registration)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
RefPtr<ServiceWorkerInfo> serviceWorkerInfo =
|
||||
registration->GetServiceWorkerInfoById(workerPrivate->ServiceWorkerID());
|
||||
if (NS_WARN_IF(!serviceWorkerInfo)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWebProgressListener> listener =
|
||||
new WebProgressListener(mPromiseProxy, serviceWorkerInfo->WorkerPrivate(),
|
||||
window, baseURI);
|
||||
|
||||
rv = webProgress->AddProgressListener(listener,
|
||||
nsIWebProgress::NOTIFY_STATE_DOCUMENT);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<ResolveOpenWindowRunnable> resolveRunnable =
|
||||
new ResolveOpenWindowRunnable(mPromiseProxy, nullptr, rv);
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
NS_WARN_IF(!resolveRunnable->Dispatch(jsapi.cx()));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsresult
|
||||
OpenWindow(nsPIDOMWindow** aWindow)
|
||||
{
|
||||
WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
|
||||
|
||||
// [[1. Let url be the result of parsing url with entry settings object's API
|
||||
// base URL.]]
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
WorkerPrivate::LocationInfo& info = workerPrivate->GetLocationInfo();
|
||||
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(baseURI), info.mOrigin);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_ERROR_TYPE_ERR;
|
||||
}
|
||||
|
||||
rv = NS_NewURI(getter_AddRefs(uri), mUrl, nullptr, baseURI);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_ERROR_TYPE_ERR;
|
||||
}
|
||||
|
||||
// [[6.1 Open Window]]
|
||||
nsCOMPtr<nsIWindowMediator> wm = do_GetService(NS_WINDOWMEDIATOR_CONTRACTID,
|
||||
&rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Find the most recent browser window and open a new tab in it.
|
||||
nsCOMPtr<nsIDOMWindow> browserWindow;
|
||||
rv = wm->GetMostRecentWindow(MOZ_UTF16("navigator:browser"),
|
||||
getter_AddRefs(browserWindow));
|
||||
if (NS_WARN_IF(NS_FAILED(rv)) || !browserWindow) {
|
||||
// It is possible to be running without a browser window on Mac OS, so
|
||||
// we need to open a new chrome window.
|
||||
// TODO(catalinb): open new chrome window. Bug 1218080
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMChromeWindow> chromeWin = do_QueryInterface(browserWindow);
|
||||
if (NS_WARN_IF(!chromeWin)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIBrowserDOMWindow> bwin;
|
||||
chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
|
||||
|
||||
if (NS_WARN_IF(!bwin)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> win;
|
||||
rv = bwin->OpenURI(uri, nullptr,
|
||||
nsIBrowserDOMWindow::OPEN_DEFAULTWINDOW,
|
||||
nsIBrowserDOMWindow::OPEN_NEW,
|
||||
getter_AddRefs(win));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
NS_ENSURE_STATE(win);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> pWin = do_QueryInterface(win);
|
||||
pWin = pWin->GetOuterWindow();
|
||||
pWin.forget(aWindow);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
already_AddRefed<Promise>
|
||||
@ -237,15 +577,51 @@ ServiceWorkerClients::MatchAll(const ClientQueryOptions& aOptions,
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
ServiceWorkerClients::OpenWindow(const nsAString& aUrl)
|
||||
ServiceWorkerClients::OpenWindow(const nsAString& aUrl,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
ErrorResult result;
|
||||
RefPtr<Promise> promise = Promise::Create(mWorkerScope, result);
|
||||
if (NS_WARN_IF(result.Failed())) {
|
||||
// XXXcatalinb: This works only on non-multiprocess for now, bail if we're
|
||||
// running in a content process.
|
||||
if (XRE_IsContentProcess()) {
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
RefPtr<Promise> promise = Promise::Create(mWorkerScope, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aUrl.EqualsLiteral("about:blank")) {
|
||||
promise->MaybeReject(NS_ERROR_TYPE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// [[4. If this algorithm is not allowed to show a popup ..]]
|
||||
// In Gecko the service worker is allowed to show a popup only if the user
|
||||
// just clicked on a notification.
|
||||
if (!workerPrivate->GlobalScope()->WindowInteractionAllowed()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
RefPtr<PromiseWorkerProxy> promiseProxy =
|
||||
PromiseWorkerProxy::Create(workerPrivate, promise);
|
||||
|
||||
if (!promiseProxy) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsString scope;
|
||||
mWorkerScope->GetScope(scope);
|
||||
|
||||
RefPtr<OpenWindowRunnable> r = new OpenWindowRunnable(promiseProxy,
|
||||
aUrl, scope);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
MatchAll(const ClientQueryOptions& aOptions, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
OpenWindow(const nsAString& aUrl);
|
||||
OpenWindow(const nsAString& aUrl, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Claim(ErrorResult& aRv);
|
||||
|
@ -382,6 +382,21 @@ ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo()
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<ServiceWorkerInfo>
|
||||
ServiceWorkerRegistrationInfo::GetServiceWorkerInfoById(uint64_t aId)
|
||||
{
|
||||
RefPtr<ServiceWorkerInfo> serviceWorker;
|
||||
if (mInstallingWorker && mInstallingWorker->ID() == aId) {
|
||||
serviceWorker = mInstallingWorker;
|
||||
} else if (mWaitingWorker && mWaitingWorker->ID() == aId) {
|
||||
serviceWorker = mWaitingWorker;
|
||||
} else if (mActiveWorker && mActiveWorker->ID() == aId) {
|
||||
serviceWorker = mActiveWorker;
|
||||
}
|
||||
|
||||
return serviceWorker.forget();
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
// ServiceWorkerManager //
|
||||
//////////////////////////
|
||||
|
@ -96,6 +96,9 @@ public:
|
||||
return newest.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<ServiceWorkerInfo>
|
||||
GetServiceWorkerInfoById(uint64_t aId);
|
||||
|
||||
void
|
||||
StartControllingADocument()
|
||||
{
|
||||
|
@ -13,7 +13,13 @@ using namespace mozilla::dom;
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
NS_IMPL_ISUPPORTS0(ServiceWorkerPrivate)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ServiceWorkerPrivate)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ServiceWorkerPrivate)
|
||||
NS_IMPL_CYCLE_COLLECTION(ServiceWorkerPrivate, mSupportsArray)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerPrivate)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
// Tracks the "dom.disable_open_click_delay" preference. Modified on main
|
||||
// thread, read on worker threads.
|
||||
@ -67,6 +73,7 @@ ServiceWorkerPrivate::~ServiceWorkerPrivate()
|
||||
MOZ_ASSERT(!mWorkerPrivate);
|
||||
MOZ_ASSERT(!mTokenCount);
|
||||
MOZ_ASSERT(!mInfo);
|
||||
MOZ_ASSERT(mSupportsArray.IsEmpty());
|
||||
|
||||
mIdleWorkerTimer->Cancel();
|
||||
}
|
||||
@ -1149,6 +1156,10 @@ ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Sanity check: mSupportsArray should be empty if we're about to
|
||||
// spin up a new worker.
|
||||
MOZ_ASSERT(mSupportsArray.IsEmpty());
|
||||
|
||||
if (NS_WARN_IF(!mInfo)) {
|
||||
NS_WARNING("Trying to wake up a dead service worker.");
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -1225,6 +1236,23 @@ ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerPrivate::StoreISupports(nsISupports* aSupports)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
MOZ_ASSERT(!mSupportsArray.Contains(aSupports));
|
||||
|
||||
mSupportsArray.AppendElement(aSupports);
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerPrivate::RemoveISupports(nsISupports* aSupports)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
mSupportsArray.RemoveElement(aSupports);
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerPrivate::TerminateWorker()
|
||||
{
|
||||
@ -1244,6 +1272,7 @@ ServiceWorkerPrivate::TerminateWorker()
|
||||
jsapi.Init();
|
||||
NS_WARN_IF(!mWorkerPrivate->Terminate(jsapi.cx()));
|
||||
mWorkerPrivate = nullptr;
|
||||
mSupportsArray.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,8 @@ class ServiceWorkerPrivate final : public nsISupports
|
||||
friend class KeepAliveToken;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(ServiceWorkerPrivate)
|
||||
|
||||
explicit ServiceWorkerPrivate(ServiceWorkerInfo* aInfo);
|
||||
|
||||
@ -106,6 +107,12 @@ public:
|
||||
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
|
||||
bool aIsReload);
|
||||
|
||||
void
|
||||
StoreISupports(nsISupports* aSupports);
|
||||
|
||||
void
|
||||
RemoveISupports(nsISupports* aSupports);
|
||||
|
||||
// This will terminate the current running worker thread and drop the
|
||||
// workerPrivate reference.
|
||||
// Called by ServiceWorkerInfo when [[Clear Registration]] is invoked
|
||||
@ -177,6 +184,12 @@ private:
|
||||
RefPtr<KeepAliveToken> mKeepAliveToken;
|
||||
|
||||
uint64_t mTokenCount;
|
||||
|
||||
// Meant for keeping objects alive while handling requests from the worker
|
||||
// on the main thread. Access to this array is provided through
|
||||
// |StoreISupports| and |RemoveISupports|. Note that the array is also
|
||||
// cleared whenever the worker is terminated.
|
||||
nsTArray<nsCOMPtr<nsISupports>> mSupportsArray;
|
||||
};
|
||||
|
||||
} // namespace workers
|
||||
|
@ -1265,6 +1265,13 @@ public:
|
||||
return mPreferences[WORKERPREF_INTERCEPTION_ENABLED];
|
||||
}
|
||||
|
||||
bool
|
||||
OpenWindowEnabled() const
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
return mPreferences[WORKERPREF_OPEN_WINDOW_ENABLED];
|
||||
}
|
||||
|
||||
bool
|
||||
OpaqueInterceptionEnabled() const
|
||||
{
|
||||
@ -1307,6 +1314,13 @@ public:
|
||||
return mPreferences[WORKERPREF_PUSH];
|
||||
}
|
||||
|
||||
bool
|
||||
RequestCacheEnabled() const
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
return mPreferences[WORKERPREF_REQUESTCACHE];
|
||||
}
|
||||
|
||||
bool
|
||||
RequestContextEnabled() const
|
||||
{
|
||||
|
@ -634,6 +634,15 @@ ServiceWorkerGlobalScope::InterceptionEnabled(JSContext* aCx, JSObject* aObj)
|
||||
return worker->InterceptionEnabled();
|
||||
}
|
||||
|
||||
bool
|
||||
ServiceWorkerGlobalScope::OpenWindowEnabled(JSContext* aCx, JSObject* aObj)
|
||||
{
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
return worker->OpenWindowEnabled();
|
||||
}
|
||||
|
||||
WorkerDebuggerGlobalScope::WorkerDebuggerGlobalScope(
|
||||
WorkerPrivate* aWorkerPrivate)
|
||||
: mWorkerPrivate(aWorkerPrivate)
|
||||
|
@ -249,6 +249,9 @@ public:
|
||||
static bool
|
||||
InterceptionEnabled(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
static bool
|
||||
OpenWindowEnabled(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
void
|
||||
GetScope(nsString& aScope) const
|
||||
{
|
||||
|
@ -201,6 +201,7 @@ enum WorkerPreference
|
||||
WORKERPREF_DOM_CACHES, // dom.caches.enabled
|
||||
WORKERPREF_SERVICEWORKERS, // dom.serviceWorkers.enabled
|
||||
WORKERPREF_INTERCEPTION_ENABLED, // dom.serviceWorkers.interception.enabled
|
||||
WORKERPREF_OPEN_WINDOW_ENABLED, // dom.serviceWorkers.openWindow.enabled
|
||||
WORKERPREF_DOM_WORKERNOTIFICATION, // dom.webnotifications.workers.enabled
|
||||
WORKERPREF_DOM_SERVICEWORKERNOTIFICATION, // dom.webnotifications.serviceworker.enabled
|
||||
WORKERPREF_DOM_CACHES_TESTING, // dom.caches.testing.enabled
|
||||
@ -208,6 +209,7 @@ enum WorkerPreference
|
||||
WORKERPREF_INTERCEPTION_OPAQUE_ENABLED, // dom.serviceWorkers.interception.opaque.enabled
|
||||
WORKERPREF_PERFORMANCE_LOGGING_ENABLED, // dom.performance.enable_user_timing_logging
|
||||
WORKERPREF_PUSH, // dom.push.enabled
|
||||
WORKERPREF_REQUESTCACHE, // dom.requestcache.enabled
|
||||
WORKERPREF_REQUESTCONTEXT, // dom.requestcontext.enabled
|
||||
WORKERPREF_OFFSCREENCANVAS, // gfx.offscreencanvas.enabled
|
||||
WORKERPREF_COUNT
|
||||
|
19
dom/workers/test/779707.html
Normal file
19
dom/workers/test/779707.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
var x = new XMLHttpRequest();
|
||||
x.open('GET', "data:text/plain,2", false);
|
||||
x.send();
|
||||
|
||||
new Worker("data:text/javascript,3");
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();"></body>
|
||||
</html>
|
@ -1,2 +1,3 @@
|
||||
load 779707.html
|
||||
load 943516.html
|
||||
load 1158031.html
|
||||
|
@ -184,6 +184,8 @@ support-files =
|
||||
xslt/*
|
||||
unresolved_fetch_worker.js
|
||||
header_checker.sjs
|
||||
openWindow_worker.js
|
||||
redirect.sjs
|
||||
|
||||
[test_app_protocol.html]
|
||||
skip-if = release_build
|
||||
@ -283,3 +285,5 @@ skip-if = e10s # Bug 1214305
|
||||
[test_csp_upgrade-insecure_intercept.html]
|
||||
skip-if = e10s # Bug 1214305
|
||||
[test_serviceworker_header.html]
|
||||
[test_openWindow.html]
|
||||
skip-if = toolkit == "android" || toolkit == "gonk" || e10s
|
||||
|
90
dom/workers/test/serviceworkers/openWindow_worker.js
Normal file
90
dom/workers/test/serviceworkers/openWindow_worker.js
Normal file
@ -0,0 +1,90 @@
|
||||
// the worker won't shut down between events because we increased
|
||||
// the timeout values.
|
||||
var client;
|
||||
|
||||
function testForUrl(url, throwType, clientProperties, resultsArray) {
|
||||
return clients.openWindow(url)
|
||||
.then(function(e) {
|
||||
if (throwType != null) {
|
||||
resultsArray.push({
|
||||
result: false,
|
||||
message: "openWindow should throw " + throwType
|
||||
});
|
||||
} else if (clientProperties) {
|
||||
resultsArray.push({
|
||||
result: (e instanceof WindowClient),
|
||||
message: "openWindow should resolve to a WindowClient"
|
||||
});
|
||||
resultsArray.push({
|
||||
result: e.url == clientProperties.url,
|
||||
message: "Client url should be " + clientProperties.url
|
||||
});
|
||||
// Add more properties
|
||||
} else {
|
||||
resultsArray.push({
|
||||
result: e == null,
|
||||
message: "Open window should resolve to null. Got: " + e
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
if (throwType == null) {
|
||||
resultsArray.push({
|
||||
result: false,
|
||||
message: "Unexpected throw: " + err
|
||||
});
|
||||
} else {
|
||||
resultsArray.push({
|
||||
result: err.toString().indexOf(throwType) >= 0,
|
||||
message: "openWindow should throw: " + err
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onmessage = function(event) {
|
||||
client = event.source;
|
||||
|
||||
var results = [];
|
||||
var promises = [];
|
||||
promises.push(testForUrl("about:blank", "TypeError", null, results));
|
||||
promises.push(testForUrl("http://example.com", "InvalidAccessError", null, results));
|
||||
promises.push(testForUrl("_._*`InvalidURL", "InvalidAccessError", null, results));
|
||||
Promise.all(promises).then(function(e) {
|
||||
client.postMessage(results);
|
||||
});
|
||||
}
|
||||
|
||||
onnotificationclick = function(e) {
|
||||
var results = [];
|
||||
var promises = [];
|
||||
|
||||
promises.push(testForUrl("about:blank", "TypeError", null, results));
|
||||
promises.push(testForUrl("http://example.com", null, null, results));
|
||||
promises.push(testForUrl("http://mochi.test:8888/same_origin.html", null,
|
||||
{url: "http://mochi.test:8888/same_origin.html"}, results));
|
||||
|
||||
// redirect tests
|
||||
var redirect = "http://mochi.test:8888/tests/dom/workers/test/serviceworkers/redirect.sjs?"
|
||||
var baseURL = "http://mochi.test:8888/tests/dom/workers/test/serviceworkers/"
|
||||
promises.push(testForUrl(redirect + "same_origin_redirect.html", null,
|
||||
{url: baseURL + "same_origin_redirect.html"}, results));
|
||||
promises.push(testForUrl(redirect + "http://example.com/redirect_to_other_origin.html", null,
|
||||
null, results));
|
||||
|
||||
var redirect_xorigin = "http://example.com/tests/dom/workers/test/serviceworkers/redirect.sjs?"
|
||||
promises.push(testForUrl(redirect_xorigin + "xorigin_redirect.html", null,
|
||||
null, results));
|
||||
promises.push(testForUrl(redirect_xorigin + "http://mochi.test:8888/xorigin_to_same_origin.html", null,
|
||||
{url: "http://mochi.test:8888/xorigin_to_same_origin.html"}, results));
|
||||
|
||||
Promise.all(promises).then(function(e) {
|
||||
client.postMessage(results);
|
||||
});
|
||||
}
|
||||
|
||||
onfetch = function(e) {
|
||||
if (e.request.url.indexOf(same_origin) >= 0) {
|
||||
e.respondWith(new Response("same_origin_window"));
|
||||
}
|
||||
}
|
5
dom/workers/test/serviceworkers/redirect.sjs
Normal file
5
dom/workers/test/serviceworkers/redirect.sjs
Normal file
@ -0,0 +1,5 @@
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
response.setStatusLine(request.httpVersion, 301, "Moved Permanently");
|
||||
response.setHeader("Location", request.queryString, false);
|
||||
}
|
111
dom/workers/test/serviceworkers/test_openWindow.html
Normal file
111
dom/workers/test/serviceworkers/test_openWindow.html
Normal file
@ -0,0 +1,111 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1172870
|
||||
-->
|
||||
<head>
|
||||
<title>Bug 1172870 - Test clients.openWindow</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/tests/mochitest/notification/MockServices.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/tests/mochitest/notification/NotificationTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1172870">Bug 1172870</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
<script type="text/javascript">
|
||||
SimpleTest.requestFlakyTimeout("Mock alert service dispatches show and click events.");
|
||||
|
||||
function setup(ctx) {
|
||||
MockServices.register();
|
||||
|
||||
return navigator.serviceWorker.register("openWindow_worker.js", {scope: "./"})
|
||||
.then(function(swr) {
|
||||
ok(swr, "Registration successful");
|
||||
ctx.registration = swr;
|
||||
return ctx;
|
||||
});
|
||||
}
|
||||
|
||||
function waitForActiveServiceWorker(ctx) {
|
||||
return navigator.serviceWorker.ready.then(function(result) {
|
||||
ok(ctx.registration.active, "Service Worker is active");
|
||||
return ctx;
|
||||
});
|
||||
}
|
||||
|
||||
function setupMessageHandler(ctx) {
|
||||
return new Promise(function(res, rej) {
|
||||
navigator.serviceWorker.onmessage = function(event) {
|
||||
navigator.serviceWorker.onmessage = null;
|
||||
for (i = 0; i < event.data.length; i++) {
|
||||
ok(event.data[i].result, event.data[i].message);
|
||||
}
|
||||
res(ctx);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testPopupNotAllowed(ctx) {
|
||||
var p = setupMessageHandler(ctx);
|
||||
ok(ctx.registration.active, "Worker is active.");
|
||||
ctx.registration.active.postMessage("testNoPopup");
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
function testPopupAllowed(ctx) {
|
||||
var p = setupMessageHandler(ctx);
|
||||
ctx.registration.showNotification("testPopup");
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
function clear(ctx) {
|
||||
MockServices.unregister();
|
||||
|
||||
var browser = SpecialPowers.Services.wm.getMostRecentWindow("navigator:browser").gBrowser;
|
||||
|
||||
ok(browser.tabs.length == 7, "Total number of tabs is correct.");
|
||||
while (browser.tabs.length > 1) {
|
||||
browser.removeTab(browser.tabs[1]);
|
||||
}
|
||||
|
||||
return ctx.registration.unregister().then(function(result) {
|
||||
ctx.registration = null;
|
||||
ok(result, "Unregister was successful.");
|
||||
});
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
setup({})
|
||||
.then(waitForActiveServiceWorker)
|
||||
// Permission to allow popups persists for some time after a notification
|
||||
// click event, so the order here is important.
|
||||
.then(testPopupNotAllowed)
|
||||
.then(testPopupAllowed)
|
||||
.then(clear)
|
||||
.catch(function(e) {
|
||||
ok(false, "Some test failed with error " + e);
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.webnotifications.workers.enabled", true],
|
||||
["dom.webnotifications.serviceworker.enabled", true],
|
||||
["notification.prompt.testing", true],
|
||||
["dom.disable_open_click_delay", 1000],
|
||||
["dom.serviceWorkers.idle_timeout", 299999],
|
||||
["dom.serviceWorkers.idle_extended_timeout", 299999]
|
||||
]}, runTest);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -3,4 +3,4 @@ load 407062-1.html
|
||||
load 419563-1.xhtml
|
||||
load 428844-1.html
|
||||
load 461049-1.html
|
||||
asserts(0-1) asserts-if(winWidget||Android,0-2) load removing-editable-xslt.html # bug 500847
|
||||
load removing-editable-xslt.html
|
||||
|
15
editor/libeditor/crashtests/667321-1.html
Normal file
15
editor/libeditor/crashtests/667321-1.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
document.body.style.cssFloat = "left";
|
||||
document.createElement("div").appendChild(document.querySelector("legend"));
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="boom();"><fieldset><legend></legend><textarea></textarea></fieldset></body>
|
||||
</html>
|
@ -36,6 +36,7 @@ load 633709.xhtml
|
||||
load 636074-1.html
|
||||
load 639736-1.xhtml
|
||||
load 643786-1.html
|
||||
load 667321-1.html
|
||||
load 682650-1.html
|
||||
load 713427-1.html
|
||||
load 713427-2.xhtml
|
||||
|
@ -1209,7 +1209,7 @@ GetStringFromDataTransfer(nsIDOMDataTransfer *aDataTransfer, const nsAString& aT
|
||||
int32_t aIndex, nsAString& aOutputString)
|
||||
{
|
||||
nsCOMPtr<nsIVariant> variant;
|
||||
aDataTransfer->MozGetDataAt(aType, aIndex, getter_AddRefs(variant));
|
||||
DataTransfer::Cast(aDataTransfer)->GetDataAtNoSecurityCheck(aType, aIndex, getter_AddRefs(variant));
|
||||
if (variant)
|
||||
variant->GetAsAString(aOutputString);
|
||||
}
|
||||
@ -1244,7 +1244,7 @@ nsresult nsHTMLEditor::InsertFromDataTransfer(DataTransfer *aDataTransfer,
|
||||
type.EqualsLiteral(kPNGImageMime) ||
|
||||
type.EqualsLiteral(kGIFImageMime)) {
|
||||
nsCOMPtr<nsIVariant> variant;
|
||||
aDataTransfer->MozGetDataAt(type, aIndex, getter_AddRefs(variant));
|
||||
DataTransfer::Cast(aDataTransfer)->GetDataAtNoSecurityCheck(type, aIndex, getter_AddRefs(variant));
|
||||
if (variant) {
|
||||
nsCOMPtr<nsISupports> object;
|
||||
variant->GetAsISupports(getter_AddRefs(object));
|
||||
|
@ -145,8 +145,8 @@ nsresult nsPlaintextEditor::InsertFromDataTransfer(DataTransfer *aDataTransfer,
|
||||
bool aDoDeleteSelection)
|
||||
{
|
||||
nsCOMPtr<nsIVariant> data;
|
||||
aDataTransfer->MozGetDataAt(NS_LITERAL_STRING("text/plain"), aIndex,
|
||||
getter_AddRefs(data));
|
||||
DataTransfer::Cast(aDataTransfer)->GetDataAtNoSecurityCheck(NS_LITERAL_STRING("text/plain"), aIndex,
|
||||
getter_AddRefs(data));
|
||||
if (data) {
|
||||
nsAutoString insertText;
|
||||
data->GetAsAString(insertText);
|
||||
|
@ -7,7 +7,6 @@
|
||||
#define MOZILLA_GFX_SCALEFACTORS2D_H_
|
||||
|
||||
#include <ostream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
|
@ -112,11 +112,21 @@ SOURCES += [
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-attributes',
|
||||
'-Wno-shadow',
|
||||
'-Wno-sign-compare',
|
||||
'-Wno-unknown-pragmas',
|
||||
'-Wno-unreachable-code',
|
||||
]
|
||||
if CONFIG['CLANG_CXX']:
|
||||
CXXFLAGS += ['-Wno-unused-private-field']
|
||||
CXXFLAGS += [
|
||||
'-Wno-inconsistent-missing-override',
|
||||
'-Wno-unused-private-field',
|
||||
]
|
||||
else:
|
||||
CXXFLAGS += [
|
||||
'-Wno-shadow-compatible-local',
|
||||
'-Wno-shadow-local',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_DIRECTX_SDK_PATH'] and not CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
|
||||
CXXFLAGS += ['-I\'%s/include/\'' % CONFIG['MOZ_DIRECTX_SDK_PATH']]
|
||||
|
@ -260,11 +260,21 @@ if CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-attributes',
|
||||
'-Wno-shadow',
|
||||
'-Wno-sign-compare',
|
||||
'-Wno-unknown-pragmas',
|
||||
'-Wno-unreachable-code',
|
||||
]
|
||||
if CONFIG['CLANG_CXX']:
|
||||
CXXFLAGS += ['-Wno-unused-private-field']
|
||||
CXXFLAGS += [
|
||||
'-Wno-inconsistent-missing-override',
|
||||
'-Wno-unused-private-field',
|
||||
]
|
||||
else:
|
||||
CXXFLAGS += [
|
||||
'-Wno-shadow-compatible-local',
|
||||
'-Wno-shadow-local',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_DIRECTX_SDK_PATH'] and not CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
|
||||
CXXFLAGS += ['-I\'%s/include/\'' % CONFIG['MOZ_DIRECTX_SDK_PATH']]
|
||||
|
@ -16,11 +16,21 @@ UNIFIED_SOURCES += [
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-attributes',
|
||||
'-Wno-shadow',
|
||||
'-Wno-sign-compare',
|
||||
'-Wno-unknown-pragmas',
|
||||
'-Wno-unreachable-code',
|
||||
]
|
||||
if CONFIG['CLANG_CXX']:
|
||||
CXXFLAGS += ['-Wno-unused-private-field']
|
||||
CXXFLAGS += [
|
||||
'-Wno-inconsistent-missing-override',
|
||||
'-Wno-unused-private-field',
|
||||
]
|
||||
else:
|
||||
CXXFLAGS += [
|
||||
'-Wno-shadow-compatible-local',
|
||||
'-Wno-shadow-local',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_DIRECTX_SDK_PATH'] and not CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
|
||||
CXXFLAGS += ['-I\'%s/include/\'' % CONFIG['MOZ_DIRECTX_SDK_PATH']]
|
||||
|
@ -22,11 +22,21 @@ UNIFIED_SOURCES += [
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-attributes',
|
||||
'-Wno-shadow',
|
||||
'-Wno-sign-compare',
|
||||
'-Wno-unknown-pragmas',
|
||||
'-Wno-unreachable-code',
|
||||
]
|
||||
if CONFIG['CLANG_CXX']:
|
||||
CXXFLAGS += ['-Wno-unused-private-field']
|
||||
CXXFLAGS += [
|
||||
'-Wno-inconsistent-missing-override',
|
||||
'-Wno-unused-private-field',
|
||||
]
|
||||
else:
|
||||
CXXFLAGS += [
|
||||
'-Wno-shadow-compatible-local',
|
||||
'-Wno-shadow-local',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_DIRECTX_SDK_PATH'] and not CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
|
||||
CXXFLAGS += ['-I\'%s/include/\'' % CONFIG['MOZ_DIRECTX_SDK_PATH']]
|
||||
|
@ -736,7 +736,7 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators,
|
||||
}
|
||||
|
||||
/* The PDF CTM is transformed to the user space CTM when stroking
|
||||
* so the corect pen shape will be used. This also requires that
|
||||
* so the correct pen shape will be used. This also requires that
|
||||
* the path be transformed to user space when emitted. The
|
||||
* conversion of path coordinates to user space may cause rounding
|
||||
* errors. For example the device space point (1.234, 3.142) when
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include "TaskThrottler.h"
|
||||
|
||||
#include "base/message_loop.h"
|
||||
#include "mozilla/layers/APZThreadUtils.h"
|
||||
|
||||
#define TASK_LOG(...)
|
||||
// #define TASK_LOG(...) printf_stderr("TASK: " __VA_ARGS__)
|
||||
@ -49,8 +49,7 @@ TaskThrottler::PostTask(const tracked_objects::Location& aLocation,
|
||||
// even if we don't get a TaskComplete() until then.
|
||||
TimeDuration timeout = mMaxWait - TimeSinceLastRequest(aTimeStamp, lock);
|
||||
mTimeoutTask = NewRunnableMethod(this, &TaskThrottler::OnTimeout);
|
||||
MessageLoop::current()->PostDelayedTask(FROM_HERE, mTimeoutTask,
|
||||
timeout.ToMilliseconds());
|
||||
APZThreadUtils::RunDelayedTaskOnCurrentThread(mTimeoutTask, timeout);
|
||||
return;
|
||||
}
|
||||
// we've been waiting for more than the max-wait limit, so just fall through
|
||||
|
@ -81,6 +81,23 @@ APZThreadUtils::RunOnControllerThread(Task* aTask)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
APZThreadUtils::RunDelayedTaskOnCurrentThread(Task* aTask,
|
||||
const TimeDuration& aDelay)
|
||||
{
|
||||
if (MessageLoop* messageLoop = MessageLoop::current()) {
|
||||
messageLoop->PostDelayedTask(FROM_HERE, aTask, aDelay.ToMilliseconds());
|
||||
} else {
|
||||
#ifdef MOZ_ANDROID_APZ
|
||||
// Fennec does not have a MessageLoop::current() on the controller thread.
|
||||
AndroidBridge::Bridge()->PostTaskToUiThread(aTask, aDelay.ToMilliseconds());
|
||||
#else
|
||||
// Other platforms should.
|
||||
MOZ_RELEASE_ASSERT(false, "This non-Fennec platform should have a MessageLoop::current()");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(GenericTimerCallbackBase, nsITimerCallback)
|
||||
|
||||
} // namespace layers
|
||||
|
@ -7,6 +7,7 @@
|
||||
#define mozilla_layers_APZThreadUtils_h
|
||||
|
||||
#include "base/message_loop.h"
|
||||
#include "mozilla/TimeStamp.h" // for TimeDuration
|
||||
#include "nsITimer.h"
|
||||
|
||||
class Task;
|
||||
@ -50,6 +51,12 @@ public:
|
||||
* run immediately without getting queued.
|
||||
*/
|
||||
static void RunOnControllerThread(Task* aTask);
|
||||
|
||||
/**
|
||||
* Runs the given task on the current thread after a delay of |aDelay|.
|
||||
*/
|
||||
static void RunDelayedTaskOnCurrentThread(Task* aTask,
|
||||
const TimeDuration& aDelay);
|
||||
};
|
||||
|
||||
// A base class for GenericTimerCallback<Function>.
|
||||
|
@ -227,6 +227,11 @@ ContentHostTexture::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
|
||||
MOZ_ASSERT(t.mPictureRect.IsEqualInterior(
|
||||
nsIntRect(nsIntPoint(0, 0), nsIntSize(t.mTexture->GetSize()))),
|
||||
"Only default picture rect supported");
|
||||
|
||||
if (t.mTexture != mTextureHost) {
|
||||
mReceivedNewHost = true;
|
||||
}
|
||||
|
||||
mTextureHost = t.mTexture;
|
||||
mTextureHostOnWhite = nullptr;
|
||||
mTextureSourceOnWhite = nullptr;
|
||||
@ -330,6 +335,11 @@ ContentHostSingleBuffered::UpdateThebes(const ThebesBufferData& aData,
|
||||
|
||||
// updated is in screen coordinates. Convert it to buffer coordinates.
|
||||
nsIntRegion destRegion(aUpdated);
|
||||
|
||||
if (mReceivedNewHost) {
|
||||
destRegion.Or(destRegion, aOldValidRegionBack);
|
||||
mReceivedNewHost = false;
|
||||
}
|
||||
destRegion.MoveBy(-aData.rect().TopLeft());
|
||||
|
||||
if (!aData.rect().Contains(aUpdated.GetBounds()) ||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user