Merge m-c to f-t, a=release to defeat a buggy hook

This commit is contained in:
Phil Ringnalda 2015-04-04 11:14:26 -07:00
commit f425a31459
207 changed files with 3911 additions and 1660 deletions

View File

@ -166,7 +166,8 @@ ProcessGlobal.prototype = {
let args = message.arguments;
let stackTrace = '';
if (message.level == 'assert' || message.level == 'error' || message.level == 'trace') {
if (message.stacktrace &&
(message.level == 'assert' || message.level == 'error' || message.level == 'trace')) {
stackTrace = Array.map(message.stacktrace, formatStackFrame).join('\n');
} else {
stackTrace = formatStackFrame(message);

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1b1d86462d3150dceacff927536ded9fcc168419"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1b1d86462d3150dceacff927536ded9fcc168419"/>

View File

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "16383ec2bf3ed46f893b15b3fab2892e9fadc4e7",
"git_revision": "e370e6beecd28785beef8c7ff299cf788693f0cc",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "2b1fea55c45ae4b59eb077840bfe5361ecd48d54",
"revision": "e4abf3a2e6a68bafbeec52cdc2a388ff7b9adf3d",
"repo_path": "integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1b1d86462d3150dceacff927536ded9fcc168419"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -2982,6 +2982,14 @@
<gfxBlacklistEntry blockID="g511"> <os>WINNT 5.1</os> <vendor>0x8086</vendor> <feature>DIRECT3D_9_LAYERS, WEBGL_ANGLE</feature> <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus> <driverVersion>6.14.10.5218</driverVersion> <driverVersionComparator>LESS_THAN</driverVersionComparator> </gfxBlacklistEntry>
</gfxItems>
<certItems>
<certItem issuerName="MIGQMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDE2MDQGA1UEAxMtQ09NT0RPIFJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB">
<serialNumber>D9UltDPl4XVfSSqQOvdiwQ==</serialNumber>
</certItem>
<certItem issuerName="MDIxCzAJBgNVBAYTAkNOMQ4wDAYDVQQKEwVDTk5JQzETMBEGA1UEAxMKQ05OSUMgUk9PVA==">
<serialNumber>STMAjg==</serialNumber>
</certItem>
</certItems>
</blocklist>

View File

@ -54,6 +54,8 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
[test_signed_pkg_install.html]
[test_uninstall_errors.html]
[test_theme_role.html]
[test_third_party_homescreen.html]
skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
[test_web_app_install.html]
[test_widget.html]
skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app

View File

@ -0,0 +1,203 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id={1097468}
-->
<head>
<title>Test for Bug {1097468}</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.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={1097468}">Mozilla Bug {1097468}</a>
<script class="testbody" type="application/javascript;version=1.7">
var gManifestURL = "http://test/tests/dom/apps/tests/file_app.sjs?apptype=hosted&getmanifest=true";
var gGenerator = runTest();
const { Services } = SpecialPowers.Cu.import('resource://gre/modules/Services.jsm', {});
function runApp(aApp, aCallback) {
var ifr = document.createElement('iframe');
ifr.setAttribute('mozbrowser', 'true');
ifr.setAttribute('mozapp', aApp.manifestURL);
ifr.src = Services.io.newURI(aApp.manifestURL, null, null)
.resolve(aApp.manifest.launch_path);
ifr.addEventListener('mozbrowsershowmodalprompt', function onAlert(e) {
var message = e.detail.message;
info("Got message " + message);
if (message.startsWith("OK: ")) {
ok(true, message.substring(4, message.length));
} else if (message.startsWith("ERROR: ")) {
ok(false, message.substring(7, message.length));
} else if (message == "DONE") {
ifr.removeEventListener('mozbrowsershowmodalprompt', onAlert, false);
loadFrameScript(mm);
}
}, false);
document.body.appendChild(ifr);
var mm = SpecialPowers.getBrowserFrameMessageManager(ifr);
ok(mm, "mm is not null");
mm.addMessageListener('OK', function(msg) {
ok(true, "Message from app: " + SpecialPowers.wrap(msg).json);
});
mm.addMessageListener('KO', function(msg) {
ok(false, "Message from app: " + SpecialPowers.wrap(msg).json);
});
mm.addMessageListener('DONE', function() {
ok(true, "Message from app: complete");
document.body.removeChild(ifr);
aCallback();
});
// Test permission |homescreen-webapps-manage|
function frameScript()
{
function ok(p, msg) {
if (p) {
sendAsyncMessage("OK", msg);
} else {
sendAsyncMessage("KO", msg);
}
}
function is(a, b, msg) {
if (a == b) {
sendAsyncMessage("OK", a + " == " + b + " - " + msg);
} else {
sendAsyncMessage("KO", a + " != " + b + " - " + msg);
}
}
function finish() {
sendAsyncMessage("DONE", "");
}
if ('mgmt' in content.window.navigator.mozApps) {
ok(true, "get mgmt");
var mgmt = content.window.navigator.mozApps.mgmt;
is(typeof mgmt.getAll, "function", "get getAll");
is(typeof mgmt.uninstall, "function", "get uninstall");
is(typeof mgmt.oninstall, "object", "get oninstall");
is(typeof mgmt.onuninstall, "object", "get onuninstall");
is(typeof mgmt.onenabledstatechange, "object", "get onenabledstatechange");
[
"getNotInstalled",
"applyDownload",
"import",
"extractManifest",
"setEnabled"
].forEach(function(func) {
is(typeof mgmt[func], "undefined", "shouldn't get" + func);
});
} else {
ok(false, "can not get mgmt");
}
finish();
}
function loadFrameScript(mm) {
var script = "data:,(" + frameScript.toString() + ")();";
mm.loadFrameScript(script, /* allowDelayedLoad = */ false);
}
}
function go() {
SpecialPowers.pushPermissions(
[{ "type": "webapps-manage", "allow": 1, "context": document },
{ "type": "browser", "allow": 1, "context": document },
{ "type": "embed-apps", "allow": 1, "context": document }],
function() {
SpecialPowers.pushPrefEnv({'set': [["dom.mozBrowserFramesEnabled", true],
["dom.mozApps.homescreenURL",
gManifestURL]]}, continueTest)});
}
function continueTest() {
try {
gGenerator.next();
} catch (e if e instanceof StopIteration) {
finish();
}
}
function finish() {
SimpleTest.finish();
}
function cbError(aEvent) {
ok(false, "Error callback invoked " +
aEvent.target.error.name + " " + aEvent.target.error.message);
finish();
}
SimpleTest.waitForExplicitFinish();
/**
* Test third-party homescreen (permission |homescreen-webapps-manage|)
*/
function runTest() {
SpecialPowers.setAllAppsLaunchable(true);
SpecialPowers.autoConfirmAppInstall(continueTest);
yield undefined;
SpecialPowers.autoConfirmAppUninstall(continueTest);
yield undefined;
// Install a app.
var request = navigator.mozApps.install(gManifestURL, { });
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
var app = request.result;
ok(app, "App is non-null");
is(app.manifestURL, gManifestURL, "App manifest url is correct.");
var context = {"manifestURL": app.manifestURL, "isInBrowserElement": false};
SpecialPowers.pushPermissions([{"type": "homescreen-webapps-manage",
"allow": 1,
"context": context}], continueTest);
yield undefined;
// Launch the app.
info("Running " + app.manifestURL);
runApp(app, continueTest);
yield undefined;
SpecialPowers.popPermissions(continueTest);
yield undefined;
// Uninstall the app to cleanup after ourself.
navigator.mozApps.mgmt.onuninstall = function(event) {
var app = event.application;
is(app.manifestURL, gManifestURL, "App uninstall event ok.");
is(app.manifest.name, "Really Rapid Release (hosted)",
"App uninstall manifest ok.");
continueTest();
}
request = navigator.mozApps.mgmt.uninstall(app);
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
yield undefined;
is(request.result, gManifestURL, "App uninstalled.");
navigator.mozApps.mgmt.onuninstall = null;
}
addLoadEvent(go);
</script>
</pre>
</body>
</html>

View File

@ -23,6 +23,7 @@
#include "xpcprivate.h"
#include "nsContentUtils.h"
#include "nsDocShell.h"
#include "nsProxyRelease.h"
#include "nsIConsoleAPIStorage.h"
#include "nsIDOMWindowUtils.h"
@ -152,6 +153,8 @@ static const JSStructuredCloneCallbacks gConsoleCallbacks = {
class ConsoleCallData final
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ConsoleCallData)
ConsoleCallData()
: mMethodName(Console::MethodLog)
, mPrivate(false)
@ -238,6 +241,10 @@ public:
Maybe<ConsoleStackEntry> mTopStackFrame;
Maybe<nsTArray<ConsoleStackEntry>> mReifiedStack;
nsCOMPtr<nsIStackFrame> mStack;
private:
~ConsoleCallData()
{ }
};
// This class is used to clear any exception at the end of this method.
@ -284,16 +291,13 @@ public:
return false;
}
AutoSyncLoopHolder syncLoop(mWorkerPrivate);
mSyncLoopTarget = syncLoop.EventTarget();
if (NS_FAILED(NS_DispatchToMainThread(this))) {
JS_ReportError(cx,
"Failed to dispatch to main thread for the Console API!");
return false;
}
return syncLoop.Run();
return true;
}
private:
@ -314,14 +318,6 @@ private:
RunWithWindow(window);
}
nsRefPtr<MainThreadStopSyncLoopRunnable> response =
new MainThreadStopSyncLoopRunnable(mWorkerPrivate,
mSyncLoopTarget.forget(),
true);
if (!response->Dispatch(nullptr)) {
NS_WARNING("Failed to dispatch response!");
}
return NS_OK;
}
@ -388,9 +384,6 @@ protected:
// Raw pointer because this method is async and this object is kept alive by
// the caller.
Console* mConsole;
private:
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
};
// This runnable appends a CallData object into the Console queue running on
@ -406,7 +399,30 @@ public:
private:
~ConsoleCallDataRunnable()
{ }
{
class ReleaseCallData final : public nsRunnable
{
public:
explicit ReleaseCallData(nsRefPtr<ConsoleCallData>& aCallData)
{
mCallData.swap(aCallData);
}
NS_IMETHOD Run() override
{
mCallData = nullptr;
return NS_OK;
}
private:
nsRefPtr<ConsoleCallData> mCallData;
};
nsRefPtr<ReleaseCallData> runnable = new ReleaseCallData(mCallData);
if(NS_FAILED(NS_DispatchToMainThread(runnable))) {
NS_WARNING("Failed to dispatch a ReleaseCallData runnable. Leaking.");
}
}
bool
PreDispatch(JSContext* aCx) override
@ -514,7 +530,7 @@ private:
mConsole->ProcessCallData(mCallData);
}
ConsoleCallData* mCallData;
nsRefPtr<ConsoleCallData> mCallData;
JSAutoStructuredCloneBuffer mArguments;
ConsoleStructuredCloneData mData;
@ -566,6 +582,7 @@ private:
return false;
}
mArguments.Clear();
return true;
}
@ -959,7 +976,7 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
const nsAString& aMethodString,
const Sequence<JS::Value>& aData)
{
nsAutoPtr<ConsoleCallData> callData(new ConsoleCallData());
nsRefPtr<ConsoleCallData> callData(new ConsoleCallData());
ClearException ce(aCx);
@ -1078,8 +1095,6 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
return;
}
// Note: we can pass the reference of callData because this runnable calls
// ProcessCallData() synchronously.
nsRefPtr<ConsoleCallDataRunnable> runnable =
new ConsoleCallDataRunnable(this, callData);
runnable->Dispatch();

View File

@ -80,6 +80,17 @@ public:
Serialize(aRetval);
}
typedef void (*ParamFunc)(const nsString& aName, const nsString& aValue,
void* aClosure);
void
ForEach(ParamFunc aFunc, void* aClosure)
{
for (uint32_t i = 0; i < mSearchParams.Length(); ++i) {
aFunc(mSearchParams[i].mKey, mSearchParams[i].mValue, aClosure);
}
}
private:
void AppendInternal(const nsAString& aName, const nsAString& aValue);

View File

@ -17,11 +17,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=345339
src="http://mochi.test:8888/tests/dom/base/test/345339_iframe.html">
</iframe>
<pre id="test">
<script class="testbody" type="text/javascript">
<script class="testbody" type="text/javascript;version=1.7">
/** Test for Bug 345339 **/
SimpleTest.waitForExplicitFinish();
var filePath;
const testData = "Test data\n";
let file = new File([testData],
"345339_test.file",
{ type: "text/plain" });
function afterLoad() {
var iframeDoc = $("testframe").contentDocument;
@ -32,15 +35,7 @@ function afterLoad() {
iframeDoc.getElementById("password").value = "123456";
iframeDoc.getElementById("hidden").value = "gecko";
var file = SpecialPowers.Cc["@mozilla.org/file/directory_service;1"]
.getService(SpecialPowers.Ci.nsIProperties)
.get("TmpD", SpecialPowers.Ci.nsILocalFile);
file.append("345339_test.file");
// Only the file's path is used, so it doesn't need to be created.
// See also bug 1058977.
filePath = file.path;
SpecialPowers.wrap(iframeDoc).getElementById("file").value = filePath;
SpecialPowers.wrap(iframeDoc).getElementById("file").mozSetFileArray([file]);
/* Reload the page */
$("testframe").setAttribute("onload", "afterReload()");
@ -62,10 +57,26 @@ function afterReload() {
"password field value forgotten");
is(iframeDoc.getElementById("hidden").value, "gecko",
"hidden field value preserved");
is(SpecialPowers.wrap(iframeDoc).getElementById("file").value, filePath,
"file field value preserved");
// The new file object isn't ===, but it's extensionally equal:
let newFile = iframeDoc.getElementById("file").files[0];
for (let prop of ["name", "lastModified", "size", "type"]) {
is(newFile[prop], file[prop],
"file field " + prop + " property preserved");
}
let reader = new FileReader();
reader.onloadend = function() {
SimpleTest.finish();
};
reader.onload = function() {
is(reader.result, testData,
"file field contents preserved")
};
reader.onerror = function() {
is(reader.error, null,
"FileReader error");
};
reader.readAsText(newFile);
}
</script>
</pre>

View File

@ -73,3 +73,4 @@ MSG_DEF(MSG_INVALID_RESPONSE_STATUSCODE_ERROR, 0, JSEXN_RANGEERR, "Invalid respo
MSG_DEF(MSG_INVALID_REDIRECT_STATUSCODE_ERROR, 0, JSEXN_RANGEERR, "Invalid redirect status code.")
MSG_DEF(MSG_INVALID_URL_SCHEME, 2, JSEXN_TYPEERR, "{0} URL {1} must be either http:// or https://.")
MSG_DEF(MSG_RESPONSE_URL_IS_NULL, 0, JSEXN_TYPEERR, "Cannot set Response.finalURL when Response.url is null.")
MSG_DEF(MSG_BAD_FORMDATA, 0, JSEXN_TYPEERR, "Could not parse content as FormData.")

View File

@ -176,6 +176,16 @@ BluetoothProfileController::SetupProfiles(bool aAssignServiceClass)
bool isRemoteControl = IS_REMOTE_CONTROL(mTarget.cod);
bool isKeyboard = IS_KEYBOARD(mTarget.cod);
bool isPointingDevice = IS_POINTING_DEVICE(mTarget.cod);
bool isInvalid = IS_INVALID_COD(mTarget.cod);
// The value of CoD is invalid. Since the device didn't declare its class of
// device properly, we assume the device may support all of these profiles.
if (isInvalid) {
AddProfile(BluetoothHfpManager::Get());
AddProfile(BluetoothA2dpManager::Get());
AddProfile(BluetoothHidManager::Get());
return;
}
NS_ENSURE_TRUE_VOID(hasAudio || hasRendering || isPeripheral);

View File

@ -53,6 +53,17 @@ BEGIN_BLUETOOTH_NAMESPACE
// Pointing device: sub-field of minor device class (Bit 7)
#define IS_POINTING_DEVICE(cod) ((GET_MINOR_DEVICE_CLASS(cod) & 0x20) >> 5)
/**
* Check whether the value of CoD is invalid. (i.e. Bit 31 ~ Bit 24 != 0x0)
*
* According to Bluetooth core spec v4.1. Vol 2, Sec. 7.3, the data length of
* CoD (class of device) is 3 bytes. The two least significant bits are used to
* indicate 'format type'. The following 22 bits are used to indicate category
* of service class and device type. The remaining 8 bits (Bit 31 ~ Bit 24)
* should be unassigned bits, since BlueDroid uses uint32_t to store CoD.
*/
#define IS_INVALID_COD(cod) (cod >> 24)
class BluetoothProfileManagerBase;
class BluetoothReplyRunnable;
typedef void (*BluetoothProfileControllerCallback)();

View File

@ -173,6 +173,16 @@ BluetoothProfileController::SetupProfiles(bool aAssignServiceClass)
bool isRemoteControl = IS_REMOTE_CONTROL(mTarget.cod);
bool isKeyboard = IS_KEYBOARD(mTarget.cod);
bool isPointingDevice = IS_POINTING_DEVICE(mTarget.cod);
bool isInvalid = IS_INVALID_COD(mTarget.cod);
// The value of CoD is invalid. Since the device didn't declare its class of
// device properly, we assume the device may support all of these profiles.
if (isInvalid) {
AddProfile(BluetoothHfpManager::Get());
AddProfile(BluetoothA2dpManager::Get());
AddProfile(BluetoothHidManager::Get());
return;
}
NS_ENSURE_TRUE_VOID(hasAudio || hasRendering || isPeripheral);

View File

@ -53,6 +53,17 @@ BEGIN_BLUETOOTH_NAMESPACE
// Pointing device: sub-field of minor device class (Bit 7)
#define IS_POINTING_DEVICE(cod) ((GET_MINOR_DEVICE_CLASS(cod) & 0x20) >> 5)
/**
* Check whether the value of CoD is invalid. (i.e. Bit 31 ~ Bit 24 != 0x0)
*
* According to Bluetooth core spec v4.1. Vol 2, Sec. 7.3, the data length of
* CoD (class of device) is 3 bytes. The two least significant bits are used to
* indicate 'format type'. The following 22 bits are used to indicate category
* of service class and device type. The remaining 8 bits (Bit 31 ~ Bit 24)
* should be unassigned bits, since BlueDroid uses uint32_t to store CoD.
*/
#define IS_INVALID_COD(cod) (cod >> 24)
class BluetoothProfileManagerBase;
class BluetoothReplyRunnable;
typedef void (*BluetoothProfileControllerCallback)();

View File

@ -56,17 +56,50 @@ GetOrigin(nsIPrincipal* aPrincipal, nsAString& aOrigin, ErrorResult& aRv)
{
MOZ_ASSERT(aPrincipal);
uint16_t appStatus = aPrincipal->GetAppStatus();
bool unknownAppId;
aRv = aPrincipal->GetUnknownAppId(&unknownAppId);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
if (!unknownAppId) {
uint32_t appId;
aRv = aPrincipal->GetAppId(&appId);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
if (appId != nsIScriptSecurityManager::NO_APP_ID) {
// If we are in "app code", use manifest URL as unique origin since
// multiple apps can share the same origin but not same broadcast
// messages.
nsresult rv;
nsCOMPtr<nsIAppsService> appsService =
do_GetService("@mozilla.org/AppsService;1", &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return;
}
appsService->GetManifestURLByLocalId(appId, aOrigin);
return;
}
}
if (appStatus == nsIPrincipal::APP_STATUS_NOT_INSTALLED) {
nsAutoString tmp;
aRv = nsContentUtils::GetUTFOrigin(aPrincipal, tmp);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
// 'null' means an unknown origin (it can be chrome code or it can be some
// about: page).
aOrigin = tmp;
if (aOrigin.EqualsASCII("null")) {
if (!aOrigin.EqualsASCII("null")) {
return;
}
nsCOMPtr<nsIURI> uri;
aRv = aPrincipal->GetURI(getter_AddRefs(uri));
if (NS_WARN_IF(aRv.Failed())) {
@ -85,24 +118,6 @@ GetOrigin(nsIPrincipal* aPrincipal, nsAString& aOrigin, ErrorResult& aRv)
}
aOrigin = NS_ConvertUTF8toUTF16(spec);
}
return;
}
uint32_t appId = aPrincipal->GetAppId();
// If we are in "app code", use manifest URL as unique origin since
// multiple apps can share the same origin but not same broadcast messages.
nsresult rv;
nsCOMPtr<nsIAppsService> appsService =
do_GetService("@mozilla.org/AppsService;1", &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return;
}
appsService->GetManifestURLByLocalId(appId, aOrigin);
}
nsIPrincipal*

View File

@ -1,5 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
skip-if = e10s || buildapp == 'b2g'
support-files =
blank.html

View File

@ -0,0 +1,20 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>MozBrowser iframe</title>
</head>
<body>
<div id="container"></div>
<script type="application/javascript;version=1.7">
var ifr = document.createElement('iframe');
ifr.src = 'http://mochi.test:8888/tests/dom/broadcastchannel/tests/iframe_mozbrowser.html';
ifr.onload = function() { alert('DONE'); }
var domParent = document.getElementById('container');
domParent.appendChild(ifr);
</script>
</body>
</html>

View File

@ -0,0 +1,21 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>MozBrowser iframe</title>
</head>
<body>
<div id="container"></div>
<script type="application/javascript;version=1.7">
var ifr = document.createElement('iframe');
ifr.setAttribute('mozbrowser', true);
ifr.src = 'http://mochi.test:8888/tests/dom/broadcastchannel/tests/iframe_mozbrowser2.html';
ifr.onload = function() { alert('DONE'); }
var domParent = document.getElementById('container');
domParent.appendChild(ifr);
</script>
</body>
</html>

View File

@ -0,0 +1,15 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>MozBrowser iframe</title>
</head>
<body>
<script type="application/javascript;version=1.7">
var bc = new BroadcastChannel('foobar');
bc.postMessage('This is wrong!');
</script>
</body>
</html>

View File

@ -0,0 +1,15 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>MozBrowser iframe</title>
</head>
<body>
<script type="application/javascript;version=1.7">
var bc = new BroadcastChannel('foobar');
bc.postMessage('This is wrong!');
</script>
</body>
</html>

View File

@ -0,0 +1,6 @@
{
"name": "BroadcastChannel",
"description": "BroadcastChannel app",
"launch_path": "/tests/dom/broadcastchannel/tests/TESTTOKEN",
"icons": { "128": "default_icon" }
}

View File

@ -6,6 +6,12 @@ support-files =
broadcastchannel_worker.js
broadcastchannel_worker_alive.js
broadcastchannel_worker_any.js
file_mozbrowser.html
file_mozbrowser2.html
iframe_mozbrowser.html
iframe_mozbrowser2.html
server.sjs
manifest.webapp
[test_broadcastchannel_any.html]
[test_broadcastchannel_basic.html]
@ -15,3 +21,7 @@ support-files =
[test_broadcastchannel_sharedWorker.html]
[test_broadcastchannel_worker.html]
[test_broadcastchannel_worker_alive.html]
[test_broadcastchannel_mozbrowser.html]
skip-if = e10s || buildapp == 'b2g'
[test_broadcastchannel_mozbrowser2.html]
skip-if = e10s || buildapp == 'b2g'

View File

@ -0,0 +1,56 @@
var gBasePath = "tests/dom/broadcastchannel/tests/";
function handleRequest(request, response) {
var query = getQuery(request);
var testToken = '';
if ('testToken' in query) {
testToken = query.testToken;
}
var template = 'manifest.webapp';
if ('template' in query) {
template = query.template;
}
var template = gBasePath + template;
response.setHeader("Content-Type", "application/x-web-app-manifest+json", false);
response.write(readTemplate(template).replace(/TESTTOKEN/g, testToken));
}
// Copy-pasted incantations. There ought to be a better way to synchronously read
// a file into a string, but I guess we're trying to discourage that.
function readTemplate(path) {
var file = Components.classes["@mozilla.org/file/directory_service;1"].
getService(Components.interfaces.nsIProperties).
get("CurWorkD", Components.interfaces.nsILocalFile);
var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
createInstance(Components.interfaces.nsIFileInputStream);
var cis = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
createInstance(Components.interfaces.nsIConverterInputStream);
var split = path.split("/");
for(var i = 0; i < split.length; ++i) {
file.append(split[i]);
}
fis.init(file, -1, -1, false);
cis.init(fis, "UTF-8", 0, 0);
var data = "";
let str = {};
let read = 0;
do {
read = cis.readString(0xffffffff, str); // read as much as we can and put it in str.value
data += str.value;
} while (read != 0);
cis.close();
return data;
}
function getQuery(request) {
var query = {};
request.queryString.split('&').forEach(function (val) {
var [name, value] = val.split('=');
query[name] = unescape(value);
});
return query;
}

View File

@ -0,0 +1,137 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for BroadcastChannel - iframe mozbrowser</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div id="container"></div>
<script type="application/javascript">
var gHostedManifestURL = 'http://test/tests/dom/broadcastchannel/tests/server.sjs?testToken=file_mozbrowser.html';
var gApp;
function cbError() {
ok(false, "Error callback invoked");
finish();
}
function createBC() {
var bc = new BroadcastChannel('foobar');
bc.onmessage = function(e) {
is(e.data, "Done!", "A message has been received!");
nextStep();
}
nextStep();
}
function completeOperation() {
var bc = new BroadcastChannel('foobar');
bc.postMessage("Done!");
}
function installApp() {
var request = navigator.mozApps.install(gHostedManifestURL);
request.onerror = cbError;
request.onsuccess = function() {
gApp = request.result;
nextStep();
}
}
function uninstallApp() {
// Uninstall the app.
var request = navigator.mozApps.mgmt.uninstall(gApp);
request.onerror = cbError;
request.onsuccess = function() {
// All done.
info("All done");
nextStep();
}
}
function testApp() {
var ifr = document.createElement('iframe');
ifr.setAttribute('mozbrowser', 'true');
ifr.setAttribute('mozapp', gApp.manifestURL);
ifr.setAttribute('src', gApp.manifest.launch_path);
var domParent = document.getElementById('container');
// Set us up to listen for messages from the app.
var listener = function(e) {
ok(true, "Messaging from app complete");
ifr.removeEventListener('mozbrowsershowmodalprompt', listener);
domParent.removeChild(ifr);
nextStep();
}
// This event is triggered when the app calls "alert".
ifr.addEventListener('mozbrowsershowmodalprompt', listener, false);
domParent.appendChild(ifr);
}
var steps = [
// Permissions
function() {
SpecialPowers.pushPermissions(
[{ "type": "browser", "allow": 1, "context": document },
{ "type": "embed-apps", "allow": 1, "context": document },
{ "type": "webapps-manage", "allow": 1, "context": document }], nextStep);
},
function() {
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true],
["network.disable.ipc.security", true],
["browser.pagethumbnails.capturing_disabled", true],
["dom.mozBrowserFramesEnabled", true],
["dom.ipc.browser_frames.oop_by_default", false],
["dom.ipc.tabs.disabled", false],
["dom.testing.ignore_ipc_principal", true],
["security.mixed_content.block_active_content", false]]},
nextStep);
},
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(nextStep));
},
createBC,
// Installing the app
installApp,
// Run tests in app
testApp,
// Uninstall the app
uninstallApp,
// finish
completeOperation
];
function finish() {
SimpleTest.finish();
}
function nextStep() {
if (!steps.length) {
SimpleTest.finish();
return;
}
var step = steps.shift();
step();
}
SimpleTest.waitForExplicitFinish();
nextStep();
</script>
</body>
</html>

View File

@ -0,0 +1,137 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for BroadcastChannel - iframe mozbrowser</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div id="container"></div>
<script type="application/javascript">
var gHostedManifestURL = 'http://test/tests/dom/broadcastchannel/tests/server.sjs?testToken=file_mozbrowser2.html';
var gApp;
function cbError() {
ok(false, "Error callback invoked");
finish();
}
function createBC() {
var bc = new BroadcastChannel('foobar');
bc.onmessage = function(e) {
is(e.data, "Done!", "A message has been received!");
nextStep();
}
nextStep();
}
function completeOperation() {
var bc = new BroadcastChannel('foobar');
bc.postMessage("Done!");
}
function installApp() {
var request = navigator.mozApps.install(gHostedManifestURL);
request.onerror = cbError;
request.onsuccess = function() {
gApp = request.result;
nextStep();
}
}
function uninstallApp() {
// Uninstall the app.
var request = navigator.mozApps.mgmt.uninstall(gApp);
request.onerror = cbError;
request.onsuccess = function() {
// All done.
info("All done");
nextStep();
}
}
function testApp() {
var ifr = document.createElement('iframe');
ifr.setAttribute('mozbrowser', 'true');
ifr.setAttribute('mozapp', gApp.manifestURL);
ifr.setAttribute('src', gApp.manifest.launch_path);
var domParent = document.getElementById('container');
// Set us up to listen for messages from the app.
var listener = function(e) {
ok(true, "Messaging from app complete");
ifr.removeEventListener('mozbrowsershowmodalprompt', listener);
domParent.removeChild(ifr);
nextStep();
}
// This event is triggered when the app calls "alert".
ifr.addEventListener('mozbrowsershowmodalprompt', listener, false);
domParent.appendChild(ifr);
}
var steps = [
// Permissions
function() {
SpecialPowers.pushPermissions(
[{ "type": "browser", "allow": 1, "context": document },
{ "type": "embed-apps", "allow": 1, "context": document },
{ "type": "webapps-manage", "allow": 1, "context": document }], nextStep);
},
function() {
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true],
["network.disable.ipc.security", true],
["browser.pagethumbnails.capturing_disabled", true],
["dom.mozBrowserFramesEnabled", true],
["dom.ipc.browser_frames.oop_by_default", false],
["dom.ipc.tabs.disabled", false],
["dom.testing.ignore_ipc_principal", true],
["security.mixed_content.block_active_content", false]]},
nextStep);
},
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(nextStep));
},
createBC,
// Installing the app
installApp,
// Run tests in app
testApp,
// Uninstall the app
uninstallApp,
// finish
completeOperation
];
function finish() {
SimpleTest.finish();
}
function nextStep() {
if (!steps.length) {
SimpleTest.finish();
return;
}
var step = steps.shift();
step();
}
SimpleTest.waitForExplicitFinish();
nextStep();
</script>
</body>
</html>

View File

@ -172,6 +172,11 @@ BrowserElementChild.prototype = {
/* useCapture = */ true,
/* wantsUntrusted = */ false);
addEventListener('click',
this._ClickHandler.bind(this),
/* useCapture = */ false,
/* wantsUntrusted = */ false);
// This listens to unload events from our message manager, but /not/ from
// the |content| window. That's because the window's unload event doesn't
// bubble, and we're not using a capturing listener. If we'd used
@ -579,6 +584,18 @@ BrowserElementChild.prototype = {
sendAsyncMsg('scrollviewchange', detail);
},
_ClickHandler: function(e) {
let elem = e.target;
if (elem instanceof Ci.nsIDOMHTMLAnchorElement && elem.href) {
// Open in a new tab if middle click or ctrl/cmd-click.
if ((Services.appinfo.OS == 'Darwin' && e.metaKey) ||
(Services.appinfo.OS != 'Darwin' && e.ctrlKey) ||
e.button == 1) {
sendAsyncMsg('opentab', {url: elem.href});
}
}
},
_selectionStateChangedHandler: function(e) {
e.stopPropagation();
@ -1085,7 +1102,7 @@ BrowserElementChild.prototype = {
_updateVisibility: function() {
var visible = this._forcedVisible && this._ownerVisible;
if (docShell.isActive !== visible) {
if (docShell && docShell.isActive !== visible) {
docShell.isActive = visible;
sendAsyncMsg('visibilitychange', {visible: visible});
}

View File

@ -214,7 +214,8 @@ BrowserElementParent.prototype = {
"metachange": this._fireEventFromMsg,
"resize": this._fireEventFromMsg,
"activitydone": this._fireEventFromMsg,
"scroll": this._fireEventFromMsg
"scroll": this._fireEventFromMsg,
"opentab": this._fireEventFromMsg
};
this._mm.addMessageListener('browser-element-api:call', function(aMsg) {

View File

@ -0,0 +1,69 @@
/* Any copyright is dedicated to the public domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Bug 1144015 - test middle/ctrl/cmd-click on a link.
"use strict";
SimpleTest.waitForExplicitFinish();
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
function runTest() {
let iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', 'true');
document.body.appendChild(iframe);
let x = 2;
let y = 2;
// First we force a reflow so that getChildProcessOffset actually returns
// meaningful data.
iframe.getBoundingClientRect();
// We need to make sure the event coordinates are actually inside the iframe,
// relative to the chome window.
let tabParent = SpecialPowers.wrap(iframe)
.QueryInterface(SpecialPowers.Ci.nsIFrameLoaderOwner)
.frameLoader.tabParent;
if (tabParent) {
let offsetX = {};
let offsetY = {};
tabParent.getChildProcessOffset(offsetX, offsetY);
x -= offsetX.value;
y -= offsetY.value;
}
let sendCtrlClick = () => {
let nsIDOMWindowUtils = SpecialPowers.Ci.nsIDOMWindowUtils;
let mod = nsIDOMWindowUtils.MODIFIER_META |
nsIDOMWindowUtils.MODIFIER_CONTROL;
iframe.sendMouseEvent('mousedown', x, y, 0, 1, mod);
iframe.sendMouseEvent('mouseup', x, y, 0, 1, mod);
}
let onCtrlClick = e => {
is(e.detail.url, 'http://example.com/', 'URL matches');
iframe.removeEventListener('mozbrowseropentab', onCtrlClick);
iframe.addEventListener('mozbrowseropentab', onMiddleClick);
sendMiddleClick();
}
let sendMiddleClick = () => {
iframe.sendMouseEvent('mousedown', x, y, 1, 1, 0);
iframe.sendMouseEvent('mouseup', x, y, 1, 1, 0);
}
let onMiddleClick= e => {
is(e.detail.url, 'http://example.com/', 'URL matches');
iframe.removeEventListener('mozbrowseropentab', onMiddleClick);
SimpleTest.finish();
}
iframe.addEventListener('mozbrowserloadend', e => {
iframe.addEventListener('mozbrowseropentab', onCtrlClick);
sendCtrlClick();
});
iframe.src = 'data:text/html,<body style="margin:0"><a href="http://example.com">click here</a></body>';
}
addEventListener('testready', runTest);

View File

@ -7,6 +7,7 @@ skip-if = os == "android" || (toolkit == "cocoa" && debug) || buildapp == 'mulet
support-files =
browserElement_OpenMixedProcess.js
file_browserElement_OpenMixedProcess.html
browserElement_OpenTab.js
[test_browserElement_oop_ThemeColor.html]
[test_browserElement_inproc_ErrorSecurity.html]
@ -60,6 +61,8 @@ skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_oop_OpenWindowRejected.html]
skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_oop_Opensearch.html]
[test_browserElement_oop_OpenTab.html]
skip-if = (toolkit == 'gonk') # Disabled on emulator. See bug 1144015 comment 8
[test_browserElement_oop_PrivateBrowsing.html]
[test_browserElement_oop_PromptCheck.html]
[test_browserElement_oop_PromptConfirm.html]

View File

@ -38,6 +38,7 @@ support-files =
browserElement_Metachange.js
browserElement_NextPaint.js
browserElement_OpenNamed.js
browserElement_OpenTab.js
browserElement_OpenWindow.js
browserElement_OpenWindowDifferentOrigin.js
browserElement_OpenWindowInFrame.js
@ -168,6 +169,8 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
[test_browserElement_inproc_NextPaint.html]
[test_browserElement_inproc_OpenNamed.html]
skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_inproc_OpenTab.html]
disabled = won't work as Firefox desktop will intercept ctrl-click
[test_browserElement_inproc_OpenWindow.html]
skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_inproc_OpenWindowDifferentOrigin.html]

View File

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

View File

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

View File

@ -113,6 +113,7 @@
#include "nsSVGLength2.h"
#include "nsDeviceContext.h"
#include "nsFontMetrics.h"
#include "Units.h"
#undef free // apparently defined by some windows header, clashing with a free()
// method in SkTypes.h
@ -1349,7 +1350,9 @@ CanvasRenderingContext2D::EnsureTarget(RenderingMode aRenderingMode)
}
if (layerManager) {
if (mode == RenderingMode::OpenGLBackendMode && CheckSizeForSkiaGL(size)) {
if (mode == RenderingMode::OpenGLBackendMode &&
gfxPlatform::GetPlatform()->UseAcceleratedSkiaCanvas() &&
CheckSizeForSkiaGL(size)) {
DemoteOldestContextIfNecessary();
#if USE_SKIA_GPU
@ -4461,7 +4464,8 @@ CanvasRenderingContext2D::DrawDirectlyToCanvas(
// FLAG_CLAMP is added for increased performance, since we never tile here.
uint32_t modifiedFlags = image.mDrawingFlags | imgIContainer::FLAG_CLAMP;
SVGImageContext svgContext(scaledImageSize, Nothing(), CurrentState().globalAlpha);
CSSIntSize sz(scaledImageSize.width, scaledImageSize.height); // XXX hmm is scaledImageSize really in CSS pixels?
SVGImageContext svgContext(sz, Nothing(), CurrentState().globalAlpha);
auto result = image.mImgContainer->
Draw(context, scaledImageSize,

View File

@ -12,8 +12,10 @@
#include "nsIUnicodeDecoder.h"
#include "nsIUnicodeEncoder.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsDOMString.h"
#include "nsNetUtil.h"
#include "nsReadableUtils.h"
#include "nsStreamUtils.h"
#include "nsStringStream.h"
@ -515,6 +517,382 @@ ExtractFromURLSearchParams(const URLSearchParams& aParams,
aContentType = NS_LITERAL_CSTRING("application/x-www-form-urlencoded;charset=UTF-8");
return NS_NewStringInputStream(aStream, serialized);
}
void
FillFormData(const nsString& aName, const nsString& aValue, void* aFormData)
{
MOZ_ASSERT(aFormData);
nsFormData* fd = static_cast<nsFormData*>(aFormData);
fd->Append(aName, aValue);
}
/**
* A simple multipart/form-data parser as defined in RFC 2388 and RFC 2046.
* This does not respect any encoding specified per entry, using UTF-8
* throughout. This is as the Fetch spec states in the consume body algorithm.
* Borrows some things from Necko's nsMultiMixedConv, but is simpler since
* unlike Necko we do not have to deal with receiving incomplete chunks of data.
*
* This parser will fail the entire parse on any invalid entry, so it will
* never return a partially filled FormData.
* The content-disposition header is used to figure out the name and filename
* entries. The inclusion of the filename parameter decides if the entry is
* inserted into the nsFormData as a string or a File.
*
* File blobs are copies of the underlying data string since we cannot adopt
* char* chunks embedded within the larger body without significant effort.
* FIXME(nsm): Bug 1127552 - We should add telemetry to calls to formData() and
* friends to figure out if Fetch ends up copying big blobs to see if this is
* worth optimizing.
*/
class MOZ_STACK_CLASS FormDataParser
{
private:
nsRefPtr<nsFormData> mFormData;
nsCString mMimeType;
nsCString mData;
// Entry state, reset in START_PART.
nsCString mName;
nsCString mFilename;
nsCString mContentType;
enum
{
START_PART,
PARSE_HEADER,
PARSE_BODY,
} mState;
nsIGlobalObject* mParentObject;
// Reads over a boundary and sets start to the position after the end of the
// boundary. Returns false if no boundary is found immediately.
bool
PushOverBoundary(const nsACString& aBoundaryString,
nsACString::const_iterator& aStart,
nsACString::const_iterator& aEnd)
{
// We copy the end iterator to keep the original pointing to the real end
// of the string.
nsACString::const_iterator end(aEnd);
const char* beginning = aStart.get();
if (FindInReadable(aBoundaryString, aStart, end)) {
// We either should find the body immediately, or after 2 chars with the
// 2 chars being '-', everything else is failure.
if ((aStart.get() - beginning) == 0) {
aStart.advance(aBoundaryString.Length());
return true;
}
if ((aStart.get() - beginning) == 2) {
if (*(--aStart) == '-' && *(--aStart) == '-') {
aStart.advance(aBoundaryString.Length() + 2);
return true;
}
}
}
return false;
}
// Reads over a CRLF and positions start after it.
bool
PushOverLine(nsACString::const_iterator& aStart)
{
if (*aStart == nsCRT::CR && (aStart.size_forward() > 1) && *(++aStart) == nsCRT::LF) {
++aStart; // advance to after CRLF
return true;
}
return false;
}
bool
FindCRLF(nsACString::const_iterator& aStart,
nsACString::const_iterator& aEnd)
{
nsACString::const_iterator end(aEnd);
return FindInReadable(NS_LITERAL_CSTRING("\r\n"), aStart, end);
}
bool
ParseHeader(nsACString::const_iterator& aStart,
nsACString::const_iterator& aEnd,
bool* aWasEmptyHeader)
{
MOZ_ASSERT(aWasEmptyHeader);
// Set it to a valid value here so we don't forget later.
*aWasEmptyHeader = false;
const char* beginning = aStart.get();
nsACString::const_iterator end(aEnd);
if (!FindCRLF(aStart, end)) {
return false;
}
if (aStart.get() == beginning) {
*aWasEmptyHeader = true;
return true;
}
nsAutoCString header(beginning, aStart.get() - beginning);
nsACString::const_iterator headerStart, headerEnd;
header.BeginReading(headerStart);
header.EndReading(headerEnd);
if (!FindCharInReadable(':', headerStart, headerEnd)) {
return false;
}
nsAutoCString headerName(StringHead(header, headerStart.size_backward()));
headerName.CompressWhitespace();
if (!NS_IsValidHTTPToken(headerName)) {
return false;
}
nsAutoCString headerValue(Substring(++headerStart, headerEnd));
if (!NS_IsReasonableHTTPHeaderValue(headerValue)) {
return false;
}
headerValue.CompressWhitespace();
if (headerName.LowerCaseEqualsLiteral("content-disposition")) {
nsCCharSeparatedTokenizer tokenizer(headerValue, ';');
bool seenFormData = false;
while (tokenizer.hasMoreTokens()) {
const nsDependentCSubstring& token = tokenizer.nextToken();
if (token.IsEmpty()) {
continue;
}
if (token.EqualsLiteral("form-data")) {
seenFormData = true;
continue;
}
if (seenFormData &&
StringBeginsWith(token, NS_LITERAL_CSTRING("name="))) {
mName = StringTail(token, token.Length() - 5);
mName.Trim(" \"");
continue;
}
if (seenFormData &&
StringBeginsWith(token, NS_LITERAL_CSTRING("filename="))) {
mFilename = StringTail(token, token.Length() - 9);
mFilename.Trim(" \"");
continue;
}
}
if (mName.IsVoid()) {
// Could not parse a valid entry name.
return false;
}
} else if (headerName.LowerCaseEqualsLiteral("content-type")) {
mContentType = headerValue;
}
return true;
}
// The end of a body is marked by a CRLF followed by the boundary. So the
// CRLF is part of the boundary and not the body, but any prior CRLFs are
// part of the body. This will position the iterator at the beginning of the
// boundary (after the CRLF).
bool
ParseBody(const nsACString& aBoundaryString,
nsACString::const_iterator& aStart,
nsACString::const_iterator& aEnd)
{
const char* beginning = aStart.get();
// Find the boundary marking the end of the body.
nsACString::const_iterator end(aEnd);
if (!FindInReadable(aBoundaryString, aStart, end)) {
return false;
}
// We found a boundary, strip the just prior CRLF, and consider
// everything else the body section.
if (aStart.get() - beginning < 2) {
// Only the first entry can have a boundary right at the beginning. Even
// an empty body will have a CRLF before the boundary. So this is
// a failure.
return false;
}
// Check that there is a CRLF right before the boundary.
aStart.advance(-2);
// Skip optional hyphens.
if (*aStart == '-' && *(aStart.get()+1) == '-') {
if (aStart.get() - beginning < 2) {
return false;
}
aStart.advance(-2);
}
if (*aStart != nsCRT::CR || *(aStart.get()+1) != nsCRT::LF) {
return false;
}
nsAutoCString body(beginning, aStart.get() - beginning);
// Restore iterator to after the \r\n as we promised.
// We do not need to handle the extra hyphens case since our boundary
// parser in PushOverBoundary()
aStart.advance(2);
if (!mFormData) {
mFormData = new nsFormData();
}
NS_ConvertUTF8toUTF16 name(mName);
if (mFilename.IsVoid()) {
mFormData->Append(name, NS_ConvertUTF8toUTF16(body));
} else {
// Unfortunately we've to copy the data first since all our strings are
// going to free it. We also need fallible alloc, so we can't just use
// ToNewCString().
char* copy = static_cast<char*>(NS_Alloc(body.Length()));
if (!copy) {
NS_WARNING("Failed to copy File entry body.");
return false;
}
nsCString::const_iterator bodyIter, bodyEnd;
body.BeginReading(bodyIter);
body.EndReading(bodyEnd);
char *p = copy;
while (bodyIter != bodyEnd) {
*p++ = *bodyIter++;
}
p = nullptr;
nsRefPtr<File> file =
File::CreateMemoryFile(mParentObject,
reinterpret_cast<void *>(copy), body.Length(),
NS_ConvertUTF8toUTF16(mFilename),
NS_ConvertUTF8toUTF16(mContentType), /* aLastModifiedDate */ 0);
Optional<nsAString> dummy;
mFormData->Append(name, *file, dummy);
}
return true;
}
public:
FormDataParser(const nsACString& aMimeType, const nsACString& aData, nsIGlobalObject* aParent)
: mMimeType(aMimeType), mData(aData), mState(START_PART), mParentObject(aParent)
{
}
bool
Parse()
{
// Determine boundary from mimetype.
const char* boundaryId = nullptr;
boundaryId = strstr(mMimeType.BeginWriting(), "boundary");
if (!boundaryId) {
return false;
}
boundaryId = strchr(boundaryId, '=');
if (!boundaryId) {
return false;
}
// Skip over '='.
boundaryId++;
char *attrib = (char *) strchr(boundaryId, ';');
if (attrib) *attrib = '\0';
nsAutoCString boundaryString(boundaryId);
if (attrib) *attrib = ';';
boundaryString.Trim(" \"");
if (boundaryString.Length() == 0) {
return false;
}
nsACString::const_iterator start, end;
mData.BeginReading(start);
// This should ALWAYS point to the end of data.
// Helpers make copies.
mData.EndReading(end);
while (start != end) {
switch(mState) {
case START_PART:
mName.SetIsVoid(true);
mFilename.SetIsVoid(true);
mContentType = NS_LITERAL_CSTRING("text/plain");
// MUST start with boundary.
if (!PushOverBoundary(boundaryString, start, end)) {
return false;
}
if (start != end && *start == '-') {
// End of data.
if (!mFormData) {
mFormData = new nsFormData();
}
return true;
}
if (!PushOverLine(start)) {
return false;
}
mState = PARSE_HEADER;
break;
case PARSE_HEADER:
bool emptyHeader;
if (!ParseHeader(start, end, &emptyHeader)) {
return false;
}
if (!PushOverLine(start)) {
return false;
}
mState = emptyHeader ? PARSE_BODY : PARSE_HEADER;
break;
case PARSE_BODY:
if (mName.IsVoid()) {
NS_WARNING("No content-disposition header with a valid name was "
"found. Failing at body parse.");
return false;
}
if (!ParseBody(boundaryString, start, end)) {
return false;
}
mState = START_PART;
break;
default:
MOZ_CRASH("Invalid case");
}
}
NS_NOTREACHED("Should never reach here.");
return false;
}
already_AddRefed<nsFormData> FormData()
{
return mFormData.forget();
}
};
} // anonymous namespace
nsresult
@ -1142,6 +1520,56 @@ FetchBody<Derived>::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength
autoFree.Reset();
return;
}
case CONSUME_FORMDATA: {
nsCString data;
data.Adopt(reinterpret_cast<char*>(aResult), aResultLength);
autoFree.Reset();
NS_NAMED_LITERAL_CSTRING(formDataMimeType, NS_LITERAL_CSTRING("multipart/form-data"));
// Allow semicolon separated boundary/encoding suffix like multipart/form-data; boundary=
// but disallow multipart/form-datafoobar.
bool isValidFormDataMimeType = StringBeginsWith(mMimeType, formDataMimeType);
if (isValidFormDataMimeType && mMimeType.Length() > formDataMimeType.Length()) {
isValidFormDataMimeType = mMimeType[formDataMimeType.Length()] == ';';
}
if (isValidFormDataMimeType) {
FormDataParser parser(mMimeType, data, DerivedClass()->GetParentObject());
if (!parser.Parse()) {
ErrorResult result;
result.ThrowTypeError(MSG_BAD_FORMDATA);
localPromise->MaybeReject(result);
return;
}
nsRefPtr<nsFormData> fd = parser.FormData();
MOZ_ASSERT(fd);
localPromise->MaybeResolve(fd);
} else {
NS_NAMED_LITERAL_CSTRING(urlDataMimeType, NS_LITERAL_CSTRING("application/x-www-form-urlencoded"));
bool isValidUrlEncodedMimeType = StringBeginsWith(mMimeType, urlDataMimeType);
if (isValidUrlEncodedMimeType && mMimeType.Length() > urlDataMimeType.Length()) {
isValidUrlEncodedMimeType = mMimeType[urlDataMimeType.Length()] == ';';
}
if (isValidUrlEncodedMimeType) {
nsRefPtr<URLSearchParams> params = new URLSearchParams();
params->ParseInput(data, /* aObserver */ nullptr);
nsRefPtr<nsFormData> fd = new nsFormData(DerivedClass()->GetParentObject());
params->ForEach(FillFormData, static_cast<void*>(fd));
localPromise->MaybeResolve(fd);
} else {
ErrorResult result;
result.ThrowTypeError(MSG_BAD_FORMDATA);
localPromise->MaybeReject(result);
}
}
return;
}
case CONSUME_TEXT:
// fall through handles early exit.
case CONSUME_JSON: {
@ -1216,15 +1644,15 @@ FetchBody<Response>::ConsumeBody(ConsumeType aType, ErrorResult& aRv);
template <class Derived>
void
FetchBody<Derived>::SetMimeType(ErrorResult& aRv)
FetchBody<Derived>::SetMimeType()
{
// Extract mime type.
ErrorResult result;
nsTArray<nsCString> contentTypeValues;
MOZ_ASSERT(DerivedClass()->GetInternalHeaders());
DerivedClass()->GetInternalHeaders()->GetAll(NS_LITERAL_CSTRING("Content-Type"), contentTypeValues, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
DerivedClass()->GetInternalHeaders()->GetAll(NS_LITERAL_CSTRING("Content-Type"),
contentTypeValues, result);
MOZ_ALWAYS_TRUE(!result.Failed());
// HTTP ABNF states Content-Type may have only one value.
// This is from the "parse a header value" of the fetch spec.
@ -1236,10 +1664,10 @@ FetchBody<Derived>::SetMimeType(ErrorResult& aRv)
template
void
FetchBody<Request>::SetMimeType(ErrorResult& aRv);
FetchBody<Request>::SetMimeType();
template
void
FetchBody<Response>::SetMimeType(ErrorResult& aRv);
FetchBody<Response>::SetMimeType();
} // namespace dom
} // namespace mozilla

View File

@ -113,6 +113,12 @@ public:
return ConsumeBody(CONSUME_BLOB, aRv);
}
already_AddRefed<Promise>
FormData(ErrorResult& aRv)
{
return ConsumeBody(CONSUME_FORMDATA, aRv);
}
already_AddRefed<Promise>
Json(ErrorResult& aRv)
{
@ -154,13 +160,13 @@ protected:
virtual ~FetchBody();
void
SetMimeType(ErrorResult& aRv);
SetMimeType();
private:
enum ConsumeType
{
CONSUME_ARRAYBUFFER,
CONSUME_BLOB,
// FormData not supported right now,
CONSUME_FORMDATA,
CONSUME_JSON,
CONSUME_TEXT,
};

View File

@ -34,6 +34,7 @@ Request::Request(nsIGlobalObject* aOwner, InternalRequest* aRequest)
, mOwner(aOwner)
, mRequest(aRequest)
{
SetMimeType();
}
Request::~Request()
@ -264,7 +265,7 @@ Request::Constructor(const GlobalObject& aGlobal,
}
nsRefPtr<Request> domRequest = new Request(global, request);
domRequest->SetMimeType(aRv);
domRequest->SetMimeType();
return domRequest.forget();
}

View File

@ -38,6 +38,7 @@ Response::Response(nsIGlobalObject* aGlobal, InternalResponse* aInternalResponse
, mOwner(aGlobal)
, mInternalResponse(aInternalResponse)
{
SetMimeType();
}
Response::~Response()
@ -188,7 +189,7 @@ Response::Constructor(const GlobalObject& aGlobal,
}
}
r->SetMimeType(aRv);
r->SetMimeType();
return r.forget();
}

View File

@ -1831,7 +1831,7 @@ HTMLInputElement::SetValue(const nsAString& aValue, ErrorResult& aRv)
}
Sequence<nsString> list;
list.AppendElement(aValue);
MozSetFileNameArray(list);
MozSetFileNameArray(list, aRv);
return;
}
else {
@ -2352,8 +2352,13 @@ HTMLInputElement::MozSetFileArray(const Sequence<OwningNonNull<File>>& aFiles)
}
void
HTMLInputElement::MozSetFileNameArray(const Sequence< nsString >& aFileNames)
HTMLInputElement::MozSetFileNameArray(const Sequence< nsString >& aFileNames, ErrorResult& aRv)
{
if (XRE_GetProcessType() == GeckoProcessType_Content) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
nsTArray<nsRefPtr<File>> files;
for (uint32_t i = 0; i < aFileNames.Length(); ++i) {
nsCOMPtr<nsIFile> file;
@ -2397,8 +2402,9 @@ HTMLInputElement::MozSetFileNameArray(const char16_t** aFileNames, uint32_t aLen
list.AppendElement(nsDependentString(aFileNames[i]));
}
MozSetFileNameArray(list);
return NS_OK;
ErrorResult rv;
MozSetFileNameArray(list, rv);
return rv.ErrorCode();
}
bool
@ -2445,8 +2451,9 @@ HTMLInputElement::SetUserInput(const nsAString& aValue)
{
Sequence<nsString> list;
list.AppendElement(aValue);
MozSetFileNameArray(list);
return NS_OK;
ErrorResult rv;
MozSetFileNameArray(list, rv);
return rv.ErrorCode();
} else {
nsresult rv = SetValueInternal(aValue, true, true);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -715,7 +715,7 @@ public:
void MozGetFileNameArray(nsTArray< nsString >& aFileNames);
void MozSetFileNameArray(const Sequence< nsString >& aFileNames);
void MozSetFileNameArray(const Sequence< nsString >& aFileNames, ErrorResult& aRv);
void MozSetFileArray(const Sequence<OwningNonNull<File>>& aFiles);
HTMLInputElement* GetOwnerNumberControl();

View File

@ -39,7 +39,7 @@ skip-if(Android||B2G) == 649134-2.html 649134-2-ref.html
# (Fuzzy necessary due to pixel-wise comparison of different JPEGs.
# The vast majority of the fuzziness comes from Linux and WinXP.)
fuzzy(1,149) == bug917595-iframe-1.html bug917595-1-ref.html
skip-if(B2G) fuzzy-if(!B2G,3,640) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869
skip-if(B2G||Mulet) fuzzy-if((!B2G&&!Mulet),3,640) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869 # Bug 1150490 disabling on Mulet as on B2G
# Test support for SVG-as-image in <picture> elements.
pref(dom.image.picture.enabled,true) pref(dom.image.srcset.enabled,true) == bug1106522-1.html bug1106522-ref.html

View File

@ -0,0 +1,6 @@
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.importGlobalProperties(["File"]);
addMessageListener("files.open", function (message) {
sendAsyncMessage("files.opened", message.map(path => new File(path)));
});

View File

@ -68,12 +68,10 @@ skip-if = buildapp == 'mulet'
[test_label_control_attribute.html]
[test_label_input_controls.html]
[test_max_attribute.html]
skip-if = e10s
[test_maxlength_attribute.html]
[test_meter_element.html]
[test_meter_pseudo-classes.html]
[test_min_attribute.html]
skip-if = e10s
[test_mozistextfield.html]
[test_novalidate_attribute.html]
[test_option_disabled.html]
@ -85,14 +83,12 @@ skip-if = e10s
[test_radio_in_label.html]
[test_radio_radionodelist.html]
[test_required_attribute.html]
skip-if = e10s
[test_restore_form_elements.html]
[test_save_restore_radio_groups.html]
[test_select_selectedOptions.html]
[test_select_validation.html]
[test_set_range_text.html]
[test_step_attribute.html]
skip-if = e10s
[test_stepup_stepdown.html]
[test_textarea_attributes_reflection.html]
[test_validation.html]

View File

@ -175,14 +175,9 @@ for (var test of data) {
checkValidity(input, true, apply, apply);
break;
case 'file':
var dirSvc = SpecialPowers.Cc["@mozilla.org/file/directory_service;1"]
.getService(SpecialPowers.Ci.nsIProperties);
var file = dirSvc.get("ProfD", SpecialPowers.Ci.nsIFile);
file.append('635499_file');
// Only the file's path is used, so it doesn't need to be created.
// See also bug 1058977.
var file = new File([''], '635499_file');
SpecialPowers.wrap(input).value = file.path;
SpecialPowers.wrap(input).mozSetFileArray([file]);
checkValidity(input, true, apply, apply);
break;

View File

@ -173,14 +173,9 @@ for (var test of data) {
checkValidity(input, true, apply, apply);
break;
case 'file':
var dirSvc = SpecialPowers.Cc["@mozilla.org/file/directory_service;1"]
.getService(SpecialPowers.Ci.nsIProperties);
var file = dirSvc.get("ProfD", SpecialPowers.Ci.nsIFile);
file.append('635499_file');
// Only the file's path is used, so it doesn't need to be created.
// See also bug 1058977.
var file = new File([''], '635499_file');
SpecialPowers.wrap(input).value = file.path;
SpecialPowers.wrap(input).mozSetFileArray([file]);
checkValidity(input, true, apply, apply);
break;

View File

@ -41,9 +41,12 @@ function completeValidityCheck(element, alwaysValid, isBarred)
} else if (element.type == 'url') {
element.pattern = "http://.*\\.com$";
element.value = "http://mozilla.com";
} else if (element.type == 'file') {
element.pattern = "foo";
SpecialPowers.wrap(element).mozSetFileArray([new File(["foo"], "foo")]);
} else {
element.pattern = "foo";
SpecialPowers.wrap(element).value = "foo";
element.value = "foo";
}
checkValidPattern(element, true, isBarred);
@ -56,9 +59,12 @@ function completeValidityCheck(element, alwaysValid, isBarred)
} else if (element.type == 'url') {
element.pattern = "http://.*\\.com$";
element.value = "http://mozilla.org";
} else if (element.type == 'file') {
element.pattern = "foo";
SpecialPowers.wrap(element).mozSetFileArray([new File(["bar"], "bar")]);
} else {
element.pattern = "foo";
SpecialPowers.wrap(element).value = "bar";
element.value = "bar";
}
if (!alwaysValid) {

View File

@ -314,18 +314,7 @@ function checkInputRequiredValidityForFile()
element.type = 'file'
document.forms[0].appendChild(element);
function createFile(fileName) {
var dirSvc = SpecialPowers.Cc["@mozilla.org/file/directory_service;1"]
.getService(SpecialPowers.Ci.nsIProperties);
var testFile = dirSvc.get("ProfD", SpecialPowers.Ci.nsIFile);
testFile.append(fileName);
// Only the file's path is used, so it doesn't need to be created.
// See also bug 1058977.
return testFile;
}
var file = createFile("345822_file");
var file = new File([""], "345822_file");
SpecialPowers.wrap(element).value = "";
element.required = false;
@ -334,7 +323,7 @@ function checkInputRequiredValidityForFile()
element.required = true;
checkSufferingFromBeingMissing(element, true);
SpecialPowers.wrap(element).value = file.path;
SpecialPowers.wrap(element).mozSetFileArray([file]);
checkNotSufferingFromBeingMissing(element);
SpecialPowers.wrap(element).value = "";
@ -344,7 +333,7 @@ function checkInputRequiredValidityForFile()
checkNotSufferingFromBeingMissing(element);
element.focus();
SpecialPowers.wrap(element).value = file.path;
SpecialPowers.wrap(element).mozSetFileArray([file]);
element.required = true;
element.blur();
element.form.reset();

View File

@ -128,14 +128,9 @@ for (var test of data) {
checkValidity(input, true, apply);
break;
case 'file':
var dirSvc = SpecialPowers.Cc["@mozilla.org/file/directory_service;1"]
.getService(SpecialPowers.Ci.nsIProperties);
var file = dirSvc.get("ProfD", SpecialPowers.Ci.nsIFile);
file.append('635499_file');
// Only the file's path is used, so it doesn't need to be created.
// See also bug 1058977.
var file = new File([''], '635499_file');
SpecialPowers.wrap(input).value = file.path;
SpecialPowers.wrap(input).mozSetFileArray([file]);
checkValidity(input, true, apply);
break;

View File

@ -178,6 +178,7 @@ support-files =
file_srcdoc.html
file_window_open_close_outer.html
file_window_open_close_inner.html
formSubmission_chrome.js
form_submit_server.sjs
formData_worker.js
formData_test.js
@ -459,7 +460,7 @@ skip-if = (toolkit == 'gonk' && debug) || e10s #debug-only failure
[test_embed_attributes_reflection.html]
[test_formData.html]
[test_formSubmission.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT # b2g(NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) b2g-debug(NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) b2g-desktop(NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT # b2g(NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) b2g-debug(NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) b2g-desktop(NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
[test_formSubmission2.html]
skip-if = toolkit == 'android'
[test_formelements.html]

View File

@ -18,48 +18,52 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=143220
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<script class="testbody" type="text/javascript;version=1.7">
/** Test for Bug 143220 **/
var leafName;
var fullPath;
SimpleTest.waitForExplicitFinish();
const helperURL = SimpleTest.getTestFileURL("simpleFileOpener.js");
const helper = SpecialPowers.loadChromeScript(helperURL);
helper.addMessageListener("fail", function onFail(message) {
is(message, null, "chrome script failed");
SimpleTest.finish();
});
helper.addMessageListener("file.opened", onFileOpened);
helper.sendAsyncMessage("file.open", "test_bug143220.txt");
function onFileOpened(message) {
const { leafName, fullPath, domFile } = message;
function initVals() {
var dirSvc = SpecialPowers.Cc["@mozilla.org/file/directory_service;1"]
.getService(SpecialPowers.Ci.nsIProperties);
var file = dirSvc.get("XpcomLib", SpecialPowers.Ci.nsILocalFile);
isnot(file, null, "Must have file here");
function initControl1() {
SpecialPowers.wrap($("i1")).mozSetFileArray([domFile]);
}
leafName = file.leafName;
fullPath = file.path;
}
function initControl2() {
SpecialPowers.wrap($("i2")).mozSetFileArray([domFile]);
}
function initControl1() {
SpecialPowers.wrap($("i1")).value = fullPath;
is(SpecialPowers.wrap($("i1")).value, fullPath, "Should have set full path 1");
}
function initControl2() {
SpecialPowers.wrap($("i2")).value = fullPath;
is(SpecialPowers.wrap($("i2")).value, fullPath, "Should have set full path 2");
}
initVals();
// Check that we can't just set the value
try {
// Check that we can't just set the value
try {
$("i1").value = fullPath;
is(0, 1, "Should have thrown exception on set!");
} catch(e) {
} catch(e) {
is($("i1").value, "", "Shouldn't have value here");
}
initControl1();
initControl2();
is($("i1").value, leafName, "Leaking full value?");
is($("i2").value, leafName, "Leaking full value?");
helper.addMessageListener("file.removed", onFileRemoved);
helper.sendAsyncMessage("file.remove", null);
}
initControl1();
initControl2();
is($("i1").value, leafName, "Leaking full value?");
is($("i2").value, leafName, "Leaking full value?");
function onFileRemoved() {
helper.destroy();
SimpleTest.finish();
}
</script>
</pre>

View File

@ -399,41 +399,59 @@ t_6_v</textarea>
SimpleTest.waitForExplicitFinish();
var myFile1, myFile2, emptyFile;
const placeholder_myFile1 = {};
const placeholder_myFile2 = {};
const placeholder_emptyFile = {};
(function setFileNames() {
var myFile1, myFile2, emptyFile;
let openerURL = SimpleTest.getTestFileURL("formSubmission_chrome.js");
let opener = SpecialPowers.loadChromeScript(openerURL);
{
let xhr = new XMLHttpRequest;
xhr.open("GET", "/dynamic/getMyDirectory.sjs", false);
xhr.send();
var basePath = xhr.responseText;
let basePath = xhr.responseText;
singleFile = basePath + "file_formSubmission_text.txt";
multiFile = [basePath + "file_formSubmission_text.txt",
basePath + "file_formSubmission_img.jpg"];
opener.addMessageListener("files.opened", onFilesOpened);
opener.sendAsyncMessage("files.open", [
basePath + "file_formSubmission_text.txt",
basePath + "file_formSubmission_img.jpg",
]);
}
function onFilesOpened(files) {
let [textFile, imageFile] = files;
opener.destroy();
let singleFile = textFile;
let multiFile = [textFile, imageFile];
var addList = document.getElementsByClassName("setfile");
let i = 0;
var input;
while (input = addList[i++]) {
if (input.classList.contains("multi")) {
SpecialPowers.wrap(input).mozSetFileNameArray(multiFile, multiFile.length);
SpecialPowers.wrap(input).mozSetFileArray(multiFile);
}
else {
SpecialPowers.wrap(input).value = singleFile;
SpecialPowers.wrap(input).mozSetFileArray([singleFile]);
}
}
input = document.createElement("input");
input.type = "file";
input.multiple = true;
SpecialPowers.wrap(input).mozSetFileNameArray(multiFile, multiFile.length);
SpecialPowers.wrap(input).mozSetFileArray(multiFile);
myFile1 = input.files[0];
myFile2 = input.files[1];
is(myFile1.size, 20, "File1 size");
is(myFile2.size, 2711, "File2 size");
emptyFile = { name: "", type: "application/octet-stream" };
})();
// Now, actually run the tests; see below.
onFilesSet();
};
var expectedSub = [
// Default input
@ -495,13 +513,13 @@ var expectedSub = [
// Reset button
// Unknown button
// File
{ name: "file_1", value: myFile1 },
{ name: "file_2", value: emptyFile },
{ name: "file_1", value: placeholder_myFile1 },
{ name: "file_2", value: placeholder_emptyFile },
// Multiple file
{ name: "file_3", value: myFile1 },
{ name: "file_4", value: myFile1 },
{ name: "file_4", value: myFile2 },
{ name: "file_5", value: emptyFile },
{ name: "file_3", value: placeholder_myFile1 },
{ name: "file_4", value: placeholder_myFile1 },
{ name: "file_4", value: placeholder_myFile2 },
{ name: "file_5", value: placeholder_emptyFile },
// Textarea
{ name: "t1", value: "t_1_v" },
{ name: "t2", value: "" },
@ -562,12 +580,12 @@ var expectedSub = [
{ name: "msel_31", value: "msel_31_v1" },
];
expectedAugment = [
var expectedAugment = [
{ name: "aName", value: "aValue" },
//{ name: "aNameBool", value: "false" },
{ name: "aNameNum", value: "9.2" },
{ name: "aNameFile1", value: myFile1 },
{ name: "aNameFile2", value: myFile2 },
{ name: "aNameFile1", value: placeholder_myFile1 },
{ name: "aNameFile2", value: placeholder_myFile2 },
//{ name: "aNameObj", value: "[object XMLHttpRequest]" },
//{ name: "aNameNull", value: "null" },
//{ name: "aNameUndef", value: "undefined" },
@ -661,10 +679,13 @@ function setDisabled(list, state) {
});
}
var gen = runTest();
addLoadEvent(function() {
var gen;
function onFilesSet() {
gen = runTest();
addLoadEvent(function() {
gen.next();
});
});
}
function runTest() {
// Set up the expectedSub array
@ -676,17 +697,17 @@ function runTest() {
yield undefined; // Wait for both FileReaders. We don't care which order they finish.
yield undefined;
function fileFixup(o) {
if (o.value == myFile1) {
if (o.value === placeholder_myFile1) {
o.value = fileReader1.result;
o.fileName = myFile1.name;
o.contentType = myFile1.type;
}
else if (o.value == myFile2) {
else if (o.value === placeholder_myFile2) {
o.value = fileReader2.result;
o.fileName = myFile2.name;
o.contentType = myFile2.type;
}
else if (o.value == emptyFile) {
else if (o.value === placeholder_emptyFile) {
o.value = "";
o.fileName = emptyFile.name;
o.contentType = emptyFile.type;

View File

@ -1235,13 +1235,14 @@ StartMacOSContentSandbox()
MacSandboxInfo info;
info.type = MacSandboxType_Content;
info.appPath.Assign(appPath);
info.appBinaryPath.Assign(appBinaryPath);
info.appDir.Assign(appDir);
info.level = Preferences::GetInt("security.sandbox.content.level");
info.appPath.assign(appPath.get());
info.appBinaryPath.assign(appBinaryPath.get());
info.appDir.assign(appDir.get());
nsAutoCString err;
std::string err;
if (!mozilla::StartMacSandbox(info, err)) {
NS_WARNING(err.get());
NS_WARNING(err.c_str());
MOZ_CRASH("sandbox_init() failed");
}
}

View File

@ -1579,13 +1579,14 @@ TabParent::RecvNotifyIMEFocus(const bool& aFocus,
nsIMEUpdatePreference* aPreference,
uint32_t* aSeqno)
{
*aSeqno = mIMESeqno;
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
*aPreference = nsIMEUpdatePreference();
return true;
}
*aSeqno = mIMESeqno;
mIMETabParent = aFocus ? this : nullptr;
mIMESelectionAnchor = 0;
mIMESelectionFocus = 0;

View File

@ -111,6 +111,12 @@ FAIL_ON_WARNINGS = True
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_TARGET'] == 'Darwin':
USE_LIBS += [
'mozsandbox',
]
LOCAL_INCLUDES += [
'/caps',
'/chrome',

View File

@ -228,32 +228,31 @@ GetAppPaths(nsCString &aAppPath, nsCString &aAppBinaryPath)
return true;
}
void
GMPChild::StartMacSandbox()
bool
GMPChild::SetMacSandboxInfo()
{
if (!mGMPLoader) {
return false;
}
nsAutoCString pluginDirectoryPath, pluginFilePath;
if (!GetPluginPaths(mPluginPath, pluginDirectoryPath, pluginFilePath)) {
MOZ_CRASH("Error scanning plugin path");
return false;
}
nsAutoCString appPath, appBinaryPath;
if (!GetAppPaths(appPath, appBinaryPath)) {
MOZ_CRASH("Error resolving child process path");
return false;
}
MacSandboxInfo info;
info.type = MacSandboxType_Plugin;
info.pluginInfo.type = MacSandboxPluginType_GMPlugin_Default;
info.pluginInfo.pluginPath.Assign(pluginDirectoryPath);
mPluginBinaryPath.Assign(pluginFilePath);
info.pluginInfo.pluginBinaryPath.Assign(pluginFilePath);
info.appPath.Assign(appPath);
info.appBinaryPath.Assign(appBinaryPath);
info.pluginInfo.pluginPath.assign(pluginDirectoryPath.get());
info.pluginInfo.pluginBinaryPath.assign(pluginFilePath.get());
info.appPath.assign(appPath.get());
info.appBinaryPath.assign(appBinaryPath.get());
nsAutoCString err;
if (!mozilla::StartMacSandbox(info, err)) {
NS_WARNING(err.get());
MOZ_CRASH("sandbox_init() failed");
}
mGMPLoader->SetSandboxInfo(&info);
return true;
}
#endif // XP_MACOSX && MOZ_GMP_SANDBOX
@ -364,24 +363,6 @@ GMPChild::PreLoadLibraries(const std::string& aPluginPath)
}
#endif
#if defined(MOZ_GMP_SANDBOX)
#if defined(XP_MACOSX)
class MacOSXSandboxStarter : public SandboxStarter {
public:
explicit MacOSXSandboxStarter(GMPChild* aGMPChild)
: mGMPChild(aGMPChild)
{}
virtual void Start(const char* aLibPath) override {
mGMPChild->StartMacSandbox();
}
private:
GMPChild* mGMPChild;
};
#endif
#endif // MOZ_GMP_SANDBOX
bool
GMPChild::GetLibPath(nsACString& aOutLibPath)
{
@ -427,8 +408,10 @@ GMPChild::RecvStartPlugin()
}
#if defined(MOZ_GMP_SANDBOX) && defined(XP_MACOSX)
nsAutoPtr<SandboxStarter> starter(new MacOSXSandboxStarter(this));
mGMPLoader->SetStartSandboxStarter(starter);
if (!SetMacSandboxInfo()) {
NS_WARNING("Failed to set Mac GMP sandbox info");
return false;
}
#endif
if (!mGMPLoader->Load(libPath.get(),

View File

@ -44,7 +44,7 @@ public:
void ShutdownComplete() override;
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
void StartMacSandbox();
bool SetMacSandboxInfo();
#endif
private:
@ -89,9 +89,6 @@ private:
MessageLoop* mGMPMessageLoop;
std::string mPluginPath;
std::string mVoucherPath;
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
nsCString mPluginBinaryPath;
#endif
std::string mNodeId;
GMPLoader* mGMPLoader;
nsTArray<uint8_t> mPluginVoucher;

View File

@ -80,10 +80,8 @@ public:
virtual void Shutdown() override;
#ifdef SANDBOX_NOT_STATICALLY_LINKED_INTO_PLUGIN_CONTAINER
virtual void SetStartSandboxStarter(SandboxStarter* aStarter) override {
mSandboxStarter = aStarter;
}
#if defined(XP_MACOSX)
virtual void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) override;
#endif
private:
@ -220,8 +218,8 @@ GMPLoaderImpl::Load(const char* aLibPath,
// Start the sandbox now that we've generated the device bound node id.
// This must happen after the node id is bound to the device id, as
// generating the device id requires privileges.
if (mSandboxStarter) {
mSandboxStarter->Start(aLibPath);
if (mSandboxStarter && !mSandboxStarter->Start(aLibPath)) {
return false;
}
// Load the GMP.
@ -277,6 +275,15 @@ GMPLoaderImpl::Shutdown()
}
}
#if defined(XP_MACOSX)
void
GMPLoaderImpl::SetSandboxInfo(MacSandboxInfo* aSandboxInfo)
{
if (mSandboxStarter) {
mSandboxStarter->SetSandboxInfo(aSandboxInfo);
}
}
#endif
} // namespace gmp
} // namespace mozilla

View File

@ -10,18 +10,24 @@
#include <stdint.h>
#include "gmp-entrypoints.h"
#if defined(XP_MACOSX)
#include "mozilla/Sandbox.h"
#endif
namespace mozilla {
namespace gmp {
class SandboxStarter {
public:
virtual ~SandboxStarter() {}
virtual void Start(const char* aLibPath) = 0;
};
virtual bool Start(const char* aLibPath) = 0;
#if defined(XP_MACOSX)
#define SANDBOX_NOT_STATICALLY_LINKED_INTO_PLUGIN_CONTAINER 1
// On OS X we need to set Mac-specific sandbox info just before we start the
// sandbox, which we don't yet know when the GMPLoader and SandboxStarter
// objects are created.
virtual void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) = 0;
#endif
};
// Encapsulates generating the device-bound node id, activating the sandbox,
// loading the GMP, and passing the node id to the GMP (in that order).
@ -59,10 +65,11 @@ public:
// plugin library.
virtual void Shutdown() = 0;
#ifdef SANDBOX_NOT_STATICALLY_LINKED_INTO_PLUGIN_CONTAINER
// Encapsulates starting the sandbox on Linux and MacOSX.
// TODO: Remove this, and put sandbox in plugin-container on all platforms.
virtual void SetStartSandboxStarter(SandboxStarter* aStarter) = 0;
#if defined(XP_MACOSX)
// On OS X we need to set Mac-specific sandbox info just before we start the
// sandbox, which we don't yet know when the GMPLoader and SandboxStarter
// objects are created.
virtual void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) = 0;
#endif
};

View File

@ -144,9 +144,6 @@ GetStrokeDashData(SVGContentUtils::AutoStrokeOptions* aStrokeOptions,
// stroke to essentially be continuous or to be nonexistent in which case
// we can avoid expensive stroking operations (the underlying platform
// graphics libraries don't seem to optimize for this).
if (totalLengthOfDashes <= 0 && totalLengthOfGaps <= 0) {
return eNoStroke;
}
if (totalLengthOfGaps <= 0) {
return eContinuousStroke;
}

View File

@ -992,14 +992,39 @@ void NetworkUtils::removeDefaultRoute(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
char command[MAX_COMMAND_SIZE];
// FIXME: (Bug 1121795) We only remove the first gateway to the default route.
// For dual stack (ipv4/ipv6) device, one of the gateway would
// not be added to the default route.
snprintf(command, MAX_COMMAND_SIZE - 1, "network route remove %d %s 0.0.0.0/0 %s",
GET_FIELD(mNetId), GET_CHAR(mIfname), GET_CHAR(mGateways[0]));
if (GET_FIELD(mLoopIndex) >= GET_FIELD(mGateways).Length()) {
aCallback(aChain, false, aResult);
return;
}
doCommand(command, aChain, aCallback);
char command[MAX_COMMAND_SIZE];
nsTArray<nsString>& gateways = GET_FIELD(mGateways);
NS_ConvertUTF16toUTF8 autoGateway(gateways[GET_FIELD(mLoopIndex)]);
int type = getIpType(autoGateway.get());
snprintf(command, MAX_COMMAND_SIZE - 1, "network route remove %d %s %s/0 %s",
GET_FIELD(mNetId), GET_CHAR(mIfname),
type == AF_INET6 ? "::" : "0.0.0.0", autoGateway.get());
struct MyCallback {
static void callback(CommandCallback::CallbackType aOriginalCallback,
CommandChain* aChain,
bool aError,
mozilla::dom::NetworkResultOptions& aResult)
{
NS_ConvertUTF16toUTF8 reason(aResult.mResultReason);
NU_DBG("removeDefaultRoute's reason: %s", reason.get());
if (aError && !reason.EqualsASCII("removeRoute() failed (No such process)")) {
return aOriginalCallback(aChain, aError, aResult);
}
GET_FIELD(mLoopIndex)++;
return removeDefaultRoute(aChain, aOriginalCallback, aResult);
}
};
CommandCallback wrappedCallback(MyCallback::callback, aCallback);
doCommand(command, aChain, wrappedCallback);
}
void NetworkUtils::setInterfaceDns(CommandChain* aChain,
@ -1147,13 +1172,19 @@ void NetworkUtils::addDefaultRouteToNetwork(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
char command[MAX_COMMAND_SIZE];
if (GET_FIELD(mLoopIndex) >= GET_FIELD(mGateways).Length()) {
aCallback(aChain, false, aResult);
return;
}
// FIXME: (Bug 1121795) We only add the first gateway to the default route.
// For dual stack (ipv4/ipv6) device, one of the gateway would
// not be added to the default route.
snprintf(command, MAX_COMMAND_SIZE - 1, "network route add %d %s 0.0.0.0/0 %s",
GET_FIELD(mNetId), GET_CHAR(mIfname), GET_CHAR(mGateways[0]));
char command[MAX_COMMAND_SIZE];
nsTArray<nsString>& gateways = GET_FIELD(mGateways);
NS_ConvertUTF16toUTF8 autoGateway(gateways[GET_FIELD(mLoopIndex)]);
int type = getIpType(autoGateway.get());
snprintf(command, MAX_COMMAND_SIZE - 1, "network route add %d %s %s/0 %s",
GET_FIELD(mNetId), GET_CHAR(mIfname),
type == AF_INET6 ? "::" : "0.0.0.0", autoGateway.get());
struct MyCallback {
static void callback(CommandCallback::CallbackType aOriginalCallback,
@ -1163,11 +1194,12 @@ void NetworkUtils::addDefaultRouteToNetwork(CommandChain* aChain,
{
NS_ConvertUTF16toUTF8 reason(aResult.mResultReason);
NU_DBG("addDefaultRouteToNetwork's reason: %s", reason.get());
if (aError && reason.EqualsASCII("addRoute() failed (File exists)")) {
NU_DBG("Ignore \"File exists\" error when adding host route.");
return aOriginalCallback(aChain, false, aResult);
if (aError && !reason.EqualsASCII("addRoute() failed (File exists)")) {
return aOriginalCallback(aChain, aError, aResult);
}
aOriginalCallback(aChain, aError, aResult);
GET_FIELD(mLoopIndex)++;
return addDefaultRouteToNetwork(aChain, aOriginalCallback, aResult);
}
};
@ -1810,8 +1842,9 @@ CommandResult NetworkUtils::setDefaultRoute(NetworkParams& aOptions)
}
aOptions.mNetId = netIdInfo.mNetId;
aOptions.mLoopIndex = 0;
runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler);
return CommandResult::Pending();
}
@ -1893,6 +1926,7 @@ CommandResult NetworkUtils::removeDefaultRoute(NetworkParams& aOptions)
NU_DBG("Obtained netid %d for interface %s", netIdInfo.mNetId, GET_CHAR(mIfname));
aOptions.mNetId = netIdInfo.mNetId;
aOptions.mLoopIndex = 0;
runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler);
return CommandResult::Pending();

View File

@ -146,6 +146,8 @@ public:
COPY_OPT_FIELD(mDns1_long, 0)
COPY_OPT_FIELD(mDns2_long, 0)
mLoopIndex = 0;
#undef COPY_SEQUENCE_FIELD
#undef COPY_OPT_STRING_FIELD
#undef COPY_OPT_FIELD
@ -199,6 +201,7 @@ public:
// Auxiliary information required to carry accros command chain.
int mNetId; // A locally defined id per interface.
uint32_t mLoopIndex; // Loop index for adding/removing multiple gateways.
};
// CommandChain store the necessary information to execute command one by one.

View File

@ -47,40 +47,3 @@ function testScript(script) {
});
}
// Utilities
// =========
// Helper that uses FileReader or FileReaderSync based on context and returns
// a Promise that resolves with the text or rejects with error.
function readAsText(blob) {
if (typeof FileReader !== "undefined") {
return new Promise(function(resolve, reject) {
var fs = new FileReader();
fs.onload = function() {
resolve(fs.result);
}
fs.onerror = reject;
fs.readAsText(blob);
});
} else {
var fs = new FileReaderSync();
return Promise.resolve(fs.readAsText(blob));
}
}
function readAsArrayBuffer(blob) {
if (typeof FileReader !== "undefined") {
return new Promise(function(resolve, reject) {
var fs = new FileReader();
fs.onload = function() {
resolve(fs.result);
}
fs.onerror = reject;
fs.readAsArrayBuffer(blob);
});
} else {
var fs = new FileReaderSync();
return Promise.resolve(fs.readAsArrayBuffer(blob));
}
}

View File

@ -4,9 +4,11 @@ support-files =
test_fetch_basic.js
test_fetch_basic_http.js
test_fetch_cors.js
test_formdataparsing.js
test_headers_common.js
test_request.js
test_response.js
utils.js
worker_wrapper.js
[test_headers.html]
@ -14,5 +16,6 @@ support-files =
[test_fetch_basic.html]
[test_fetch_basic_http.html]
[test_fetch_cors.html]
[test_formdataparsing.html]
[test_request.html]
[test_response.html]

View File

@ -13,6 +13,7 @@
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script type="text/javascript" src="utils.js"> </script>
<script type="text/javascript" src="fetch_test_framework.js"> </script>
<script class="testbody" type="text/javascript">
testScript("test_fetch_basic.js");

View File

@ -13,6 +13,7 @@
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script type="text/javascript" src="utils.js"> </script>
<script type="text/javascript" src="fetch_test_framework.js"> </script>
<script class="testbody" type="text/javascript">
testScript("test_fetch_basic_http.js");

View File

@ -13,6 +13,7 @@
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script type="text/javascript" src="utils.js"> </script>
<script type="text/javascript" src="fetch_test_framework.js"> </script>
<script class="testbody" type="text/javascript">
testScript("test_fetch_cors.js");

View File

@ -0,0 +1,23 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1109751 - Test FormData parsing</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script type="text/javascript" src="utils.js"> </script>
<script type="text/javascript" src="fetch_test_framework.js"> </script>
<script class="testbody" type="text/javascript">
testScript("test_formdataparsing.js");
</script>
</body>
</html>

View File

@ -0,0 +1,283 @@
var boundary = "1234567891011121314151617";
// fn(body) should create a Body subclass with content body treated as
// FormData and return it.
function testFormDataParsing(fn) {
function makeTest(shouldPass, input, testFn) {
var obj = fn(input);
return obj.formData().then(function(fd) {
ok(shouldPass, "Expected test to be valid FormData for " + input);
if (testFn) {
return testFn(fd);
}
}, function(e) {
if (shouldPass) {
ok(false, "Expected test to pass for " + input);
} else {
ok(e.name == "TypeError", "Error should be a TypeError.");
}
});
}
// [shouldPass?, input, testFn]
var tests =
[
[ true,
boundary +
'\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' +
boundary + '-',
function(fd) {
is(fd.get("greeting"), '"hello"');
}
],
[ false,
// Invalid disposition.
boundary +
'\r\nContent-Disposition: form-datafoobar; name="greeting"\r\n\r\n"hello"\r\n' +
boundary + '-',
],
[ true,
'--' +
boundary +
'\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' +
boundary + '-',
function(fd) {
is(fd.get("greeting"), '"hello"');
}
],
[ false,
boundary + "\r\n\r\n" + boundary + '-',
],
[ false,
// No valid ending.
boundary + "\r\n\r\n" + boundary,
],
[ false,
// One '-' prefix is not allowed. 2 or none.
'-' +
boundary +
'\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' +
boundary + '-',
],
[ false,
'invalid' +
boundary +
'\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' +
boundary + '-',
],
[ false,
boundary + 'suffix' +
'\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' +
boundary + '-',
],
[ false,
boundary + 'suffix' +
'\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' +
boundary + '-',
],
[ false,
// Partial boundary
boundary.substr(3) +
'\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' +
boundary + '-',
],
[ false,
boundary +
// Missing '\n' at beginning.
'\rContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' +
boundary + '-',
],
[ false,
boundary +
// No form-data.
'\r\nContent-Disposition: mixed; name="greeting"\r\n\r\n"hello"\r\n' +
boundary + '-',
],
[ false,
boundary +
// No headers.
'\r\n\r\n"hello"\r\n' +
boundary + '-',
],
[ false,
boundary +
// No content-disposition.
'\r\nContent-Dispositypo: form-data; name="greeting"\r\n\r\n"hello"\r\n' +
boundary + '-',
],
[ false,
boundary +
// No name.
'\r\nContent-Disposition: form-data;\r\n\r\n"hello"\r\n' +
boundary + '-',
],
[ false,
boundary +
// Missing empty line between headers and body.
'\r\nContent-Disposition: form-data; name="greeting"\r\n"hello"\r\n' +
boundary + '-',
],
[ false,
// Empty entry followed by valid entry.
boundary + "\r\n\r\n" + boundary +
'\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' +
boundary + '-',
],
[ false,
boundary +
// Header followed by empty line, but empty body not followed by
// newline.
'\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n' +
boundary + '-',
],
[ true,
boundary +
// Empty body followed by newline.
'\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n\r\n' +
boundary + '-',
function(fd) {
is(fd.get("greeting"), "", "Empty value is allowed.");
}
],
[ false,
boundary +
// Value is boundary itself.
'\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n' +
boundary + '\r\n' +
boundary + '-',
],
[ false,
boundary +
// Variant of above with no valid ending boundary.
'\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n' +
boundary
],
[ true,
boundary +
// Unquoted filename with empty body.
'\r\nContent-Disposition: form-data; name="file"; filename=file1.txt\r\n\r\n\r\n' +
boundary + '-',
function(fd) {
var f = fd.get("file");
ok(f instanceof File, "Entry with filename attribute should be read as File.");
is(f.name, "file1.txt", "Filename should match.");
is(f.type, "text/plain", "Default content-type should be text/plain.");
return readAsText(f).then(function(text) {
is(text, "", "File should be empty.");
});
}
],
[ true,
boundary +
// Quoted filename with empty body.
'\r\nContent-Disposition: form-data; name="file"; filename="file1.txt"\r\n\r\n\r\n' +
boundary + '-',
function(fd) {
var f = fd.get("file");
ok(f instanceof File, "Entry with filename attribute should be read as File.");
is(f.name, "file1.txt", "Filename should match.");
is(f.type, "text/plain", "Default content-type should be text/plain.");
return readAsText(f).then(function(text) {
is(text, "", "File should be empty.");
});
}
],
[ false,
boundary +
// Invalid filename
'\r\nContent-Disposition: form-data; name="file"; filename="[\n@;xt"\r\n\r\n\r\n' +
boundary + '-',
],
[ true,
boundary +
'\r\nContent-Disposition: form-data; name="file"; filename="[@;xt"\r\n\r\n\r\n' +
boundary + '-',
function(fd) {
var f = fd.get("file");
ok(f instanceof File, "Entry with filename attribute should be read as File.");
is(f.name, "[@", "Filename should match.");
}
],
[ true,
boundary +
'\r\nContent-Disposition: form-data; name="file"; filename="file with spaces"\r\n\r\n\r\n' +
boundary + '-',
function(fd) {
var f = fd.get("file");
ok(f instanceof File, "Entry with filename attribute should be read as File.");
is(f.name, "file with spaces", "Filename should match.");
}
],
[ true,
boundary + '\r\n' +
'Content-Disposition: form-data; name="file"; filename="xml.txt"\r\n' +
'content-type : application/xml\r\n' +
'\r\n' +
'<body>foobar\r\n\r\n</body>\r\n' +
boundary + '-',
function(fd) {
var f = fd.get("file");
ok(f instanceof File, "Entry with filename attribute should be read as File.");
is(f.name, "xml.txt", "Filename should match.");
is(f.type, "application/xml", "content-type should be application/xml.");
return readAsText(f).then(function(text) {
is(text, "<body>foobar\r\n\r\n</body>", "File should have correct text.");
});
}
],
];
var promises = [];
for (var i = 0; i < tests.length; ++i) {
var test = tests[i];
promises.push(makeTest(test[0], test[1], test[2]));
}
return Promise.all(promises);
}
function makeRequest(body) {
var req = new Request("", { method: 'post', body: body,
headers: {
'Content-Type': 'multipart/form-data; boundary=' + boundary
}});
return req;
}
function makeResponse(body) {
var res = new Response(body, { headers: {
'Content-Type': 'multipart/form-data; boundary=' + boundary
}});
return res;
}
function runTest() {
return Promise.all([testFormDataParsing(makeRequest),
testFormDataParsing(makeResponse)]);
}

View File

@ -8,6 +8,7 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script type="text/javascript" src="utils.js"> </script>
<script type="text/javascript" src="fetch_test_framework.js"> </script>
<script class="testbody" type="text/javascript">
testScript("test_headers_common.js");

View File

@ -13,6 +13,7 @@
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script type="text/javascript" src="utils.js"> </script>
<script type="text/javascript" src="fetch_test_framework.js"> </script>
<script class="testbody" type="text/javascript">
testScript("test_request.js");

View File

@ -220,8 +220,8 @@ function testBodyUsed() {
});
}
var text = "κόσμε";
function testBodyCreation() {
var text = "κόσμε";
var req1 = new Request("", { method: 'post', body: text });
var p1 = req1.text().then(function(v) {
ok(typeof v === "string", "Should resolve to string");
@ -243,6 +243,8 @@ function testBodyCreation() {
is(v, text, "Extracted string should match");
});
// FormData has its own function since it has blobs and files.
var params = new URLSearchParams();
params.append("item", "Geckos");
params.append("feature", "stickyfeet");
@ -258,6 +260,39 @@ function testBodyCreation() {
return Promise.all([p1, p2, p2b, pblob, p3]);
}
function testFormDataBodyCreation() {
var f1 = new FormData();
f1.append("key", "value");
f1.append("foo", "bar");
var r1 = new Request("", { method: 'post', body: f1 })
// Since f1 is serialized immediately, later additions should not show up.
f1.append("more", "stuff");
var p1 = r1.formData().then(function(fd) {
ok(fd instanceof FormData, "Valid FormData extracted.");
ok(fd.has("key"), "key should exist.");
ok(fd.has("foo"), "foo should exist.");
ok(!fd.has("more"), "more should not exist.");
});
f1.append("blob", new Blob([text]));
var r2 = new Request("", { method: 'post', body: f1 });
f1.delete("key");
var p2 = r2.formData().then(function(fd) {
ok(fd instanceof FormData, "Valid FormData extracted.");
ok(fd.has("more"), "more should exist.");
var b = fd.get("blob");
ok(b instanceof Blob, "blob entry should be a Blob.");
return readAsText(b).then(function(output) {
is(output, text, "Blob contents should match.");
});
});
return Promise.all([p1, p2]);
}
function testBodyExtraction() {
var text = "κόσμε";
var newReq = function() { return new Request("", { method: 'post', body: text }); }
@ -283,7 +318,92 @@ function testBodyExtraction() {
var dec = new TextDecoder();
is(dec.decode(new Uint8Array(v)), text, "UTF-8 decoded ArrayBuffer should match original");
});
})
}).then(function() {
return newReq().formData().then(function(v) {
ok(false, "invalid FormData read should fail.");
}, function(e) {
ok(e.name == "TypeError", "invalid FormData read should fail.");
});
});
}
function testFormDataBodyExtraction() {
// URLSearchParams translates to application/x-www-form-urlencoded.
var params = new URLSearchParams();
params.append("item", "Geckos");
params.append("feature", "stickyfeet");
params.append("quantity", "700");
params.append("quantity", "800");
var req = new Request("", { method: 'POST', body: params });
var p1 = req.formData().then(function(fd) {
ok(fd.has("item"), "Has entry 'item'.");
ok(fd.has("feature"), "Has entry 'feature'.");
var entries = fd.getAll("quantity");
is(entries.length, 2, "Entries with same name are correctly handled.");
is(entries[0], "700", "Entries with same name are correctly handled.");
is(entries[1], "800", "Entries with same name are correctly handled.");
});
var f1 = new FormData();
f1.append("key", "value");
f1.append("foo", "bar");
f1.append("blob", new Blob([text]));
var r2 = new Request("", { method: 'post', body: f1 });
var p2 = r2.formData().then(function(fd) {
ok(fd.has("key"), "Has entry 'key'.");
ok(fd.has("foo"), "Has entry 'foo'.");
ok(fd.has("blob"), "Has entry 'blob'.");
var entries = fd.getAll("blob");
is(entries.length, 1, "getAll returns all items.");
is(entries[0].name, "blob", "Filename should be blob.");
});
var ws = "\r\n\r\n\r\n\r\n";
f1.set("key", new File([ws], 'file name has spaces.txt', { type: 'new/lines' }));
var r3 = new Request("", { method: 'post', body: f1 });
var p3 = r3.formData().then(function(fd) {
ok(fd.has("foo"), "Has entry 'foo'.");
ok(fd.has("blob"), "Has entry 'blob'.");
var entries = fd.getAll("blob");
is(entries.length, 1, "getAll returns all items.");
is(entries[0].name, "blob", "Filename should be blob.");
ok(fd.has("key"), "Has entry 'key'.");
var f = fd.get("key");
ok(f instanceof File, "entry should be a File.");
is(f.name, "file name has spaces.txt", "File name should match.");
is(f.type, "new/lines", "File type should match.");
is(f.size, ws.length, "File size should match.");
return readAsText(f).then(function(text) {
is(text, ws, "File contents should match.");
});
});
// Override header and ensure parse fails.
var boundary = "1234567891011121314151617";
var body = boundary +
'\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' +
boundary + '-';
var r4 = new Request("", { method: 'post', body: body, headers: {
"Content-Type": "multipart/form-datafoobar; boundary="+boundary,
}});
var p4 = r4.formData().then(function() {
ok(false, "Invalid mimetype should fail.");
}, function() {
ok(true, "Invalid mimetype should fail.");
});
var r5 = new Request("", { method: 'POST', body: params, headers: {
"Content-Type": "application/x-www-form-urlencodedfoobar",
}});
var p5 = r5.formData().then(function() {
ok(false, "Invalid mimetype should fail.");
}, function() {
ok(true, "Invalid mimetype should fail.");
});
return Promise.all([p1, p2, p3, p4]);
}
// mode cannot be set to "CORS-with-forced-preflight" from javascript.
@ -320,6 +440,8 @@ function runTest() {
.then(testBodyCreation)
.then(testBodyUsed)
.then(testBodyExtraction)
.then(testFormDataBodyCreation)
.then(testFormDataBodyExtraction)
.then(testUsedRequest)
.then(testClone())
// Put more promise based tests here.

View File

@ -13,6 +13,7 @@
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script type="text/javascript" src="utils.js"> </script>
<script type="text/javascript" src="fetch_test_framework.js"> </script>
<script class="testbody" type="text/javascript">
testScript("test_response.js");

View File

@ -0,0 +1,37 @@
// Utilities
// =========
// Helper that uses FileReader or FileReaderSync based on context and returns
// a Promise that resolves with the text or rejects with error.
function readAsText(blob) {
if (typeof FileReader !== "undefined") {
return new Promise(function(resolve, reject) {
var fs = new FileReader();
fs.onload = function() {
resolve(fs.result);
}
fs.onerror = reject;
fs.readAsText(blob);
});
} else {
var fs = new FileReaderSync();
return Promise.resolve(fs.readAsText(blob));
}
}
function readAsArrayBuffer(blob) {
if (typeof FileReader !== "undefined") {
return new Promise(function(resolve, reject) {
var fs = new FileReader();
fs.onload = function() {
resolve(fs.result);
}
fs.onerror = reject;
fs.readAsArrayBuffer(blob);
});
} else {
var fs = new FileReaderSync();
return Promise.resolve(fs.readAsArrayBuffer(blob));
}
}

View File

@ -1,3 +1,5 @@
importScripts("utils.js");
function ok(a, msg) {
postMessage({type: 'status', status: !!a, msg: a + ": " + msg });
}

View File

@ -24,7 +24,7 @@ enum LocaleResourceType {
[NoInterfaceObject, NavigatorProperty="mozApps",
JSImplementation="@mozilla.org/webapps;1"]
interface DOMApplicationsRegistry {
[CheckPermissions="webapps-manage"]
[CheckPermissions="webapps-manage homescreen-webapps-manage"]
readonly attribute DOMApplicationsManager mgmt;
DOMRequest install(DOMString url, optional InstallParameters params);
DOMRequest installPackage(DOMString url, optional InstallParameters params);
@ -116,16 +116,22 @@ interface DOMApplication : EventTarget {
[JSImplementation="@mozilla.org/webapps/manager;1",
ChromeOnly,
CheckPermissions="webapps-manage"]
CheckPermissions="webapps-manage homescreen-webapps-manage"]
interface DOMApplicationsManager : EventTarget {
DOMRequest getAll();
[CheckPermissions="webapps-manage"]
DOMRequest getNotInstalled();
[CheckPermissions="webapps-manage"]
void applyDownload(DOMApplication app);
DOMRequest uninstall(DOMApplication app);
[CheckPermissions="webapps-manage"]
Promise<DOMApplication> import(Blob blob);
[CheckPermissions="webapps-manage"]
Promise<any> extractManifest(Blob blob);
[CheckPermissions="webapps-manage"]
void setEnabled(DOMApplication app, boolean state);
Promise<Blob> getIcon(DOMApplication app, DOMString iconID,
optional DOMString entryPoint);

View File

@ -17,8 +17,8 @@ interface Body {
Promise<ArrayBuffer> arrayBuffer();
[Throws]
Promise<Blob> blob();
// FIXME(nsm): Bug 739173 FormData is not supported in workers.
// Promise<FormData> formData();
[Throws]
Promise<FormData> formData();
[Throws]
Promise<JSON> json();
[Throws]

View File

@ -151,7 +151,7 @@ partial interface HTMLInputElement {
[ChromeOnly]
sequence<DOMString> mozGetFileNameArray();
[ChromeOnly]
[ChromeOnly, Throws]
void mozSetFileNameArray(sequence<DOMString> fileNames);
[ChromeOnly]

View File

@ -156,6 +156,12 @@ public:
SetLayer(aLayer);
mAttached = true;
mKeepAttached = aFlags & KEEP_ATTACHED;
// If we already have a textureHost before, use that in this moment.
RefPtr<TextureHost> frontBuffer = GetAsTextureHost();
if (frontBuffer) {
UseTextureHost(frontBuffer);
}
}
// Detach this compositable host from its layer.
// If we are used for async video, then it is not safe to blindly detach since

View File

@ -345,7 +345,7 @@ UnclipViewport(const SVGImageContext& aOldContext,
// Map the viewport to the inner image. (Note that we don't take the aSize
// parameter of Draw into account, just the clipping region.)
nsIntSize vSize(aOldContext.GetViewportSize());
CSSIntSize vSize(aOldContext.GetViewportSize());
vSize.width = ceil(vSize.width * double(innerSize.width) / clipSize.width);
vSize.height = ceil(vSize.height * double(innerSize.height) / clipSize.height);

View File

@ -241,7 +241,7 @@ static SVGImageContext
OrientViewport(const SVGImageContext& aOldContext,
const Orientation& aOrientation)
{
nsIntSize viewportSize(aOldContext.GetViewportSize());
CSSIntSize viewportSize(aOldContext.GetViewportSize());
if (aOrientation.SwapsWidthAndHeight()) {
swap(viewportSize.width, viewportSize.height);
}

View File

@ -719,11 +719,16 @@ struct SVGDrawingParameters
, region(aRegion)
, filter(aFilter)
, svgContext(aSVGContext)
, viewportSize(aSVGContext ? aSVGContext->GetViewportSize() : aSize)
, viewportSize(aSize)
, animationTime(aAnimationTime)
, flags(aFlags)
, opacity(aSVGContext ? aSVGContext->GetGlobalOpacity() : 1.0)
{ }
{
if (aSVGContext) {
CSSIntSize sz = aSVGContext->GetViewportSize();
viewportSize = nsIntSize(sz.width, sz.height); // XXX losing unit
}
}
gfxContext* context;
IntSize size;

View File

@ -73,6 +73,11 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_TARGET'] == 'Linux':
if '-flto' in CONFIG['OS_CXXFLAGS'] and not CONFIG['CLANG_CXX']:
LDFLAGS += ['--param lto-partitions=1']
if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_TARGET'] == 'Darwin':
USE_LIBS += [
'mozsandbox',
]
if CONFIG['_MSC_VER']:
# Always enter a Windows program through wmain, whether or not we're
# a console application.

View File

@ -80,10 +80,11 @@ static bool gIsSandboxEnabled = false;
class WinSandboxStarter : public mozilla::gmp::SandboxStarter {
public:
virtual void Start(const char *aLibPath) override {
virtual bool Start(const char *aLibPath) override {
if (gIsSandboxEnabled) {
sandbox::SandboxFactory::GetTargetServices()->LowerToken();
}
return true;
}
};
#endif
@ -101,23 +102,41 @@ public:
return nullptr;
}
}
virtual void Start(const char *aLibPath) override {
virtual bool Start(const char *aLibPath) override {
mozilla::SetMediaPluginSandbox(aLibPath);
return true;
}
};
#endif
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
class MacSandboxStarter : public mozilla::gmp::SandboxStarter {
public:
virtual bool Start(const char *aLibPath) override {
std::string err;
bool rv = mozilla::StartMacSandbox(mInfo, err);
if (!rv) {
fprintf(stderr, "sandbox_init() failed! Error \"%s\"\n", err.c_str());
}
return rv;
}
virtual void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) override {
mInfo = *aSandboxInfo;
}
private:
MacSandboxInfo mInfo;
};
#endif
mozilla::gmp::SandboxStarter*
MakeSandboxStarter()
{
// Note: MacOSX creates its SandboxStarter inside xul code; it
// needs to change to statically link its sandbox code into
// plugin-container. Once it does that, we can create the
// SandboxStarter for it here.
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
return new WinSandboxStarter();
#elif defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
return LinuxSandboxStarter::Make();
#elif defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
return new MacSandboxStarter();
#else
return nullptr;
#endif

View File

@ -134,12 +134,12 @@ AsmJSModule::trace(JSTracer* trc)
globals_[i].trace(trc);
for (unsigned i = 0; i < exits_.length(); i++) {
if (exitIndexToGlobalDatum(i).fun)
MarkObject(trc, &exitIndexToGlobalDatum(i).fun, "asm.js imported function");
TraceEdge(trc, &exitIndexToGlobalDatum(i).fun, "asm.js imported function");
}
for (unsigned i = 0; i < exports_.length(); i++)
exports_[i].trace(trc);
for (unsigned i = 0; i < names_.length(); i++)
MarkStringUnbarriered(trc, &names_[i].name(), "asm.js module function name");
TraceManuallyBarrieredEdge(trc, &names_[i].name(), "asm.js module function name");
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
for (unsigned i = 0; i < profiledFunctions_.length(); i++)
profiledFunctions_[i].trace(trc);
@ -149,13 +149,13 @@ AsmJSModule::trace(JSTracer* trc)
perfProfiledBlocksFunctions_[i].trace(trc);
#endif
if (globalArgumentName_)
MarkStringUnbarriered(trc, &globalArgumentName_, "asm.js global argument name");
TraceManuallyBarrieredEdge(trc, &globalArgumentName_, "asm.js global argument name");
if (importArgumentName_)
MarkStringUnbarriered(trc, &importArgumentName_, "asm.js import argument name");
TraceManuallyBarrieredEdge(trc, &importArgumentName_, "asm.js import argument name");
if (bufferArgumentName_)
MarkStringUnbarriered(trc, &bufferArgumentName_, "asm.js buffer argument name");
TraceManuallyBarrieredEdge(trc, &bufferArgumentName_, "asm.js buffer argument name");
if (maybeHeap_)
gc::MarkObject(trc, &maybeHeap_, "asm.js heap");
TraceEdge(trc, &maybeHeap_, "asm.js heap");
}
void

View File

@ -258,7 +258,7 @@ class AsmJSModule
void trace(JSTracer* trc) {
if (name_)
MarkStringUnbarriered(trc, &name_, "asm.js global name");
TraceManuallyBarrieredEdge(trc, &name_, "asm.js global name");
MOZ_ASSERT_IF(pod.which_ == Variable && pod.u.var.initKind_ == InitConstant,
!pod.u.var.u.numLit_.scalarValue().isMarkable());
}
@ -476,9 +476,9 @@ class AsmJSModule
}
void trace(JSTracer* trc) {
MarkStringUnbarriered(trc, &name_, "asm.js export name");
TraceManuallyBarrieredEdge(trc, &name_, "asm.js export name");
if (maybeFieldName_)
MarkStringUnbarriered(trc, &maybeFieldName_, "asm.js export field");
TraceManuallyBarrieredEdge(trc, &maybeFieldName_, "asm.js export field");
}
public:
@ -680,7 +680,7 @@ class AsmJSModule
void trace(JSTracer* trc) {
if (name)
MarkStringUnbarriered(trc, &name, "asm.js profiled function name");
TraceManuallyBarrieredEdge(trc, &name, "asm.js profiled function name");
}
size_t serializedSize() const;

View File

@ -1628,7 +1628,7 @@ OutlineTypedObject::obj_trace(JSTracer* trc, JSObject* object)
{
OutlineTypedObject& typedObj = object->as<OutlineTypedObject>();
MarkShape(trc, &typedObj.shape_, "OutlineTypedObject_shape");
TraceEdge(trc, &typedObj.shape_, "OutlineTypedObject_shape");
if (!typedObj.owner_)
return;
@ -1641,7 +1641,7 @@ OutlineTypedObject::obj_trace(JSTracer* trc, JSObject* object)
// Mark the owner, watching in case it is moved by the tracer.
JSObject* oldOwner = typedObj.owner_;
gc::MarkObjectUnbarriered(trc, &typedObj.owner_, "typed object owner");
TraceManuallyBarrieredEdge(trc, &typedObj.owner_, "typed object owner");
JSObject* owner = typedObj.owner_;
uint8_t* oldData = typedObj.outOfLineTypedMem();
@ -2141,7 +2141,7 @@ InlineTypedObject::obj_trace(JSTracer* trc, JSObject* object)
{
InlineTypedObject& typedObj = object->as<InlineTypedObject>();
MarkShape(trc, &typedObj.shape_, "InlineTypedObject_shape");
TraceEdge(trc, &typedObj.shape_, "InlineTypedObject_shape");
// Inline transparent objects do not have references and do not need more
// tracing. If there is an entry in the compartment's LazyArrayBufferTable,
@ -2946,7 +2946,7 @@ MemoryTracingVisitor::visitReference(ReferenceTypeDescr& descr, uint8_t* mem)
{
HeapPtrObject* objectPtr = reinterpret_cast<js::HeapPtrObject*>(mem);
if (*objectPtr)
gc::MarkObject(trace_, objectPtr, "reference-obj");
TraceEdge(trace_, objectPtr, "reference-obj");
return;
}
@ -2954,7 +2954,7 @@ MemoryTracingVisitor::visitReference(ReferenceTypeDescr& descr, uint8_t* mem)
{
HeapPtrString* stringPtr = reinterpret_cast<js::HeapPtrString*>(mem);
if (*stringPtr)
gc::MarkString(trace_, stringPtr, "reference-str");
TraceEdge(trace_, stringPtr, "reference-str");
return;
}
}

View File

@ -1128,7 +1128,7 @@ ObjectBox::trace(JSTracer* trc)
{
ObjectBox* box = this;
while (box) {
MarkObjectRoot(trc, &box->object, "parser.object");
TraceRoot(trc, &box->object, "parser.object");
if (box->isFunctionBox())
box->asFunctionBox()->bindings.trace(trc);
box = box->traceLink;

View File

@ -231,16 +231,10 @@ template <> struct MapTypeToTraceKind<UnownedBaseShape> { static const JSGCTrace
template <> struct MapTypeToTraceKind<jit::JitCode> { static const JSGCTraceKind kind = JSTRACE_JITCODE; };
template <> struct MapTypeToTraceKind<ObjectGroup> { static const JSGCTraceKind kind = JSTRACE_OBJECT_GROUP; };
// Direct value access used by the write barriers and the jits.
void
MarkValueForBarrier(JSTracer* trc, Value* v, const char* name);
// These three declarations are also present in gc/Marking.h, via the DeclMarker
// macro. Not great, but hard to avoid.
void
MarkStringUnbarriered(JSTracer* trc, JSString** str, const char* name);
void
MarkSymbolUnbarriered(JSTracer* trc, JS::Symbol** sym, const char* name);
// Marking.h depends on these barrier definitions, so we need a separate
// entry point for marking to implement the pre-barrier.
void MarkValueForBarrier(JSTracer* trc, Value* v, const char* name);
void MarkIdForBarrier(JSTracer* trc, jsid* idp, const char* name);
} // namespace gc
@ -283,6 +277,13 @@ ZoneOfValueFromAnyThread(const JS::Value& value)
return js::gc::TenuredCell::fromPointer(value.toGCThing())->zoneFromAnyThread();
}
MOZ_ALWAYS_INLINE JS::Zone*
ZoneOfIdFromAnyThread(const jsid& id)
{
MOZ_ASSERT(JSID_IS_GCTHING(id));
return js::gc::TenuredCell::fromPointer(JSID_TO_GCTHING(id).asCell())->zoneFromAnyThread();
}
void
ValueReadBarrier(const Value& value);
@ -387,19 +388,13 @@ struct InternalGCMethods<jsid>
static bool isMarkable(jsid id) { return JSID_IS_STRING(id) || JSID_IS_SYMBOL(id); }
static void preBarrier(jsid id) {
if (JSID_IS_STRING(id)) {
JSString* str = JSID_TO_STRING(id);
JS::shadow::Zone* shadowZone = ShadowZoneOfStringFromAnyThread(str);
if (JSID_IS_GCTHING(id)) {
JS::Zone* zone = ZoneOfIdFromAnyThread(id);
JS::shadow::Zone* shadowZone = JS::shadow::Zone::asShadowZone(zone);
if (shadowZone->needsIncrementalBarrier()) {
js::gc::MarkStringUnbarriered(shadowZone->barrierTracer(), &str, "write barrier");
MOZ_ASSERT(str == JSID_TO_STRING(id));
}
} else if (JSID_IS_SYMBOL(id)) {
JS::Symbol* sym = JSID_TO_SYMBOL(id);
JS::shadow::Zone* shadowZone = ShadowZoneOfSymbolFromAnyThread(sym);
if (shadowZone->needsIncrementalBarrier()) {
js::gc::MarkSymbolUnbarriered(shadowZone->barrierTracer(), &sym, "write barrier");
MOZ_ASSERT(sym == JSID_TO_SYMBOL(id));
jsid tmp(id);
js::gc::MarkIdForBarrier(shadowZone->barrierTracer(), &tmp, "id write barrier");
MOZ_ASSERT(tmp == id);
}
}
}

View File

@ -292,13 +292,6 @@ SetMaybeAliveFlag(JSObject* thing)
thing->compartment()->maybeAlive = true;
}
template<>
void
SetMaybeAliveFlag(NativeObject* thing)
{
thing->compartment()->maybeAlive = true;
}
template<>
void
SetMaybeAliveFlag(JSScript* thing)
@ -342,6 +335,7 @@ FOR_EACH_GC_LAYOUT(NAMES)
D(PlainObject*) \
D(SavedFrame*) \
D(ScopeObject*) \
D(ScriptSourceObject*) \
D(SharedArrayBufferObject*) \
D(SharedTypedArrayObject*) \
D(JSScript*) \
@ -394,6 +388,13 @@ template <> struct PtrBaseGCType<Value> { typedef Value type; };
template <> struct PtrBaseGCType<jsid> { typedef jsid type; };
template <typename T> struct PtrBaseGCType<T*> { typedef typename BaseGCType<T>::type* type; };
template <typename T>
typename PtrBaseGCType<T>::type*
ConvertToBase(T* thingp)
{
return reinterpret_cast<typename PtrBaseGCType<T>::type*>(thingp);
}
template <typename T> void DispatchToTracer(JSTracer* trc, T* thingp, const char* name, size_t i);
template <typename T> void DoTracing(JS::CallbackTracer* trc, T* thingp, const char* name, size_t i);
template <typename T> void DoMarking(GCMarker* gcmarker, T thing);
@ -404,16 +405,14 @@ template <typename T>
void
js::TraceEdge(JSTracer* trc, BarrieredBase<T>* thingp, const char* name)
{
auto layout = reinterpret_cast<typename PtrBaseGCType<T>::type*>(thingp->unsafeGet());
DispatchToTracer(trc, layout, name, JSTracer::InvalidIndex);
DispatchToTracer(trc, ConvertToBase(thingp->unsafeGet()), name, JSTracer::InvalidIndex);
}
template <typename T>
void
js::TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name)
{
auto layout = reinterpret_cast<typename PtrBaseGCType<T>::type*>(thingp);
DispatchToTracer(trc, layout, name, JSTracer::InvalidIndex);
DispatchToTracer(trc, ConvertToBase(thingp), name, JSTracer::InvalidIndex);
}
template <typename T>
@ -421,28 +420,27 @@ void
js::TraceRoot(JSTracer* trc, T* thingp, const char* name)
{
JS_ROOT_MARKING_ASSERT(trc);
auto layout = reinterpret_cast<typename PtrBaseGCType<T>::type*>(thingp);
DispatchToTracer(trc, layout, name, JSTracer::InvalidIndex);
DispatchToTracer(trc, ConvertToBase(thingp), name, JSTracer::InvalidIndex);
}
template <typename T>
void
js::TraceRange(JSTracer* trc, size_t len, BarrieredBase<T>* thingp, const char* name)
js::TraceRange(JSTracer* trc, size_t len, BarrieredBase<T>* vec, const char* name)
{
for (auto i : MakeRange(len)) {
auto layout = reinterpret_cast<typename PtrBaseGCType<T>::type*>(&thingp[i]);
DispatchToTracer(trc, layout, name, i);
if (InternalGCMethods<T>::isMarkable(vec[i].get()))
DispatchToTracer(trc, ConvertToBase(vec[i].unsafeGet()), name, i);
}
}
template <typename T>
void
js::TraceRootRange(JSTracer* trc, size_t len, T* thingp, const char* name)
js::TraceRootRange(JSTracer* trc, size_t len, T* vec, const char* name)
{
JS_ROOT_MARKING_ASSERT(trc);
for (auto i : MakeRange(len)) {
auto layout = reinterpret_cast<typename PtrBaseGCType<T>::type*>(&thingp[i]);
DispatchToTracer(trc, layout, name, i);
if (InternalGCMethods<T>::isMarkable(vec[i]))
DispatchToTracer(trc, ConvertToBase(&vec[i]), name, i);
}
}
@ -797,8 +795,14 @@ namespace gc {
template <typename T>
static inline void
CheckIsMarkedThing(T** thingp)
CheckIsMarkedThing(T* thingp)
{
#define IS_SAME_TYPE_OR(name, type) mozilla::IsSame<type*, T>::value ||
static_assert(
FOR_EACH_GC_LAYOUT(IS_SAME_TYPE_OR)
false, "Only the base cell layout types are allowed into marking/tracing internals");
#undef IS_SAME_TYPE_OR
#ifdef DEBUG
MOZ_ASSERT(thingp);
MOZ_ASSERT(*thingp);
@ -811,7 +815,7 @@ CheckIsMarkedThing(T** thingp)
template <typename T>
static bool
IsMarked(T** thingp)
IsMarkedInternal(T* thingp)
{
CheckIsMarkedThing(thingp);
JSRuntime* rt = (*thingp)->runtimeFromAnyThread();
@ -829,12 +833,50 @@ IsMarked(T** thingp)
return (*thingp)->asTenured().isMarked();
}
template <>
bool
IsMarkedInternal<Value>(Value* valuep)
{
bool rv = true; // Non-markable types are always live.
if (valuep->isString()) {
JSString* str = valuep->toString();
rv = IsMarkedInternal(&str);
valuep->setString(str);
} else if (valuep->isObject()) {
JSObject* obj = &valuep->toObject();
rv = IsMarkedInternal(&obj);
valuep->setObject(*obj);
} else if (valuep->isSymbol()) {
JS::Symbol* sym = valuep->toSymbol();
rv = IsMarkedInternal(&sym);
valuep->setSymbol(sym);
}
return rv;
}
template <>
bool
IsMarkedInternal<jsid>(jsid* idp)
{
bool rv = true; // Non-markable types are always live.
if (JSID_IS_STRING(*idp)) {
JSString* str = JSID_TO_STRING(*idp);
rv = IsMarkedInternal(&str);
*idp = NON_INTEGER_ATOM_TO_JSID(reinterpret_cast<JSAtom*>(str));
} else if (JSID_IS_SYMBOL(*idp)) {
JS::Symbol* sym = JSID_TO_SYMBOL(*idp);
rv = IsMarkedInternal(&sym);
*idp = SYMBOL_TO_JSID(sym);
}
return rv;
}
template <typename T>
static bool
IsAboutToBeFinalized(T** thingp)
IsAboutToBeFinalizedInternal(T* thingp)
{
CheckIsMarkedThing(thingp);
T* thing = *thingp;
T thing = *thingp;
JSRuntime* rt = thing->runtimeFromAnyThread();
/* Permanent atoms are never finalized by non-owning runtimes. */
@ -863,6 +905,97 @@ IsAboutToBeFinalized(T** thingp)
return false;
}
template <>
bool
IsAboutToBeFinalizedInternal<Value>(Value* valuep)
{
bool rv = false; // Non-markable types are always live.
if (valuep->isString()) {
JSString* str = (JSString*)valuep->toGCThing();
rv = IsAboutToBeFinalizedInternal(&str);
valuep->setString(str);
} else if (valuep->isObject()) {
JSObject* obj = (JSObject*)valuep->toGCThing();
rv = IsAboutToBeFinalizedInternal(&obj);
valuep->setObject(*obj);
} else if (valuep->isSymbol()) {
JS::Symbol* sym = valuep->toSymbol();
rv = IsAboutToBeFinalizedInternal(&sym);
valuep->setSymbol(sym);
}
return rv;
}
template <>
bool
IsAboutToBeFinalizedInternal<jsid>(jsid* idp)
{
bool rv = false; // Non-markable types are always live.
if (JSID_IS_STRING(*idp)) {
JSString* str = JSID_TO_STRING(*idp);
rv = IsAboutToBeFinalizedInternal(&str);
*idp = NON_INTEGER_ATOM_TO_JSID(reinterpret_cast<JSAtom*>(str));
} else if (JSID_IS_SYMBOL(*idp)) {
JS::Symbol* sym = JSID_TO_SYMBOL(*idp);
rv = IsAboutToBeFinalizedInternal(&sym);
*idp = SYMBOL_TO_JSID(sym);
}
return rv;
}
template <typename T>
bool
IsMarkedUnbarriered(T* thingp)
{
return IsMarkedInternal(ConvertToBase(thingp));
}
template <typename T>
bool
IsMarked(BarrieredBase<T>* thingp)
{
return IsMarkedInternal(ConvertToBase(thingp->unsafeGet()));
}
template <typename T>
bool
IsMarked(ReadBarriered<T>* thingp)
{
return IsMarkedInternal(ConvertToBase(thingp->unsafeGet()));
}
template <typename T>
bool
IsAboutToBeFinalizedUnbarriered(T* thingp)
{
return IsAboutToBeFinalizedInternal(ConvertToBase(thingp));
}
template <typename T>
bool
IsAboutToBeFinalized(BarrieredBase<T>* thingp)
{
return IsAboutToBeFinalizedInternal(ConvertToBase(thingp->unsafeGet()));
}
template <typename T>
bool
IsAboutToBeFinalized(ReadBarriered<T>* thingp)
{
return IsAboutToBeFinalizedInternal(ConvertToBase(thingp->unsafeGet()));
}
// Instantiate a copy of the Tracing templates for each derived type.
#define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(type) \
template bool IsMarkedUnbarriered<type>(type*); \
template bool IsMarked<type>(BarrieredBase<type>*); \
template bool IsMarked<type>(ReadBarriered<type>*); \
template bool IsAboutToBeFinalizedUnbarriered<type>(type*); \
template bool IsAboutToBeFinalized<type>(BarrieredBase<type>*); \
template bool IsAboutToBeFinalized<type>(ReadBarriered<type>*);
FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS)
#undef INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS
template <typename T>
T*
UpdateIfRelocated(JSRuntime* rt, T** thingp)
@ -922,25 +1055,25 @@ Mark##base##RootRange(JSTracer* trc, size_t len, type** vec, const char* name)
bool \
Is##base##Marked(type** thingp) \
{ \
return IsMarked<type>(thingp); \
return IsMarkedUnbarriered<type*>(thingp); \
} \
\
bool \
Is##base##Marked(BarrieredBase<type*>* thingp) \
{ \
return IsMarked<type>(thingp->unsafeGet()); \
return IsMarked<type*>(thingp); \
} \
\
bool \
Is##base##AboutToBeFinalized(type** thingp) \
{ \
return IsAboutToBeFinalized<type>(thingp); \
return IsAboutToBeFinalizedUnbarriered<type*>(thingp); \
} \
\
bool \
Is##base##AboutToBeFinalized(BarrieredBase<type*>* thingp) \
{ \
return IsAboutToBeFinalized<type>(thingp->unsafeGet()); \
return IsAboutToBeFinalized<type*>(thingp); \
} \
\
type * \
@ -955,37 +1088,6 @@ Update##base##IfRelocated(JSRuntime* rt, type** thingp)
return UpdateIfRelocated<type>(rt, thingp); \
}
DeclMarkerImpl(BaseShape, BaseShape)
DeclMarkerImpl(BaseShape, UnownedBaseShape)
DeclMarkerImpl(JitCode, jit::JitCode)
DeclMarkerImpl(Object, NativeObject)
DeclMarkerImpl(Object, ArrayObject)
DeclMarkerImpl(Object, ArgumentsObject)
DeclMarkerImpl(Object, ArrayBufferObject)
DeclMarkerImpl(Object, ArrayBufferObjectMaybeShared)
DeclMarkerImpl(Object, ArrayBufferViewObject)
DeclMarkerImpl(Object, DebugScopeObject)
DeclMarkerImpl(Object, GlobalObject)
DeclMarkerImpl(Object, JSObject)
DeclMarkerImpl(Object, JSFunction)
DeclMarkerImpl(Object, NestedScopeObject)
DeclMarkerImpl(Object, PlainObject)
DeclMarkerImpl(Object, SavedFrame)
DeclMarkerImpl(Object, ScopeObject)
DeclMarkerImpl(Object, SharedArrayBufferObject)
DeclMarkerImpl(Object, SharedTypedArrayObject)
DeclMarkerImpl(Script, JSScript)
DeclMarkerImpl(LazyScript, LazyScript)
DeclMarkerImpl(Shape, Shape)
DeclMarkerImpl(String, JSAtom)
DeclMarkerImpl(String, JSString)
DeclMarkerImpl(String, JSFlatString)
DeclMarkerImpl(String, JSLinearString)
DeclMarkerImpl(String, PropertyName)
DeclMarkerImpl(Symbol, JS::Symbol)
DeclMarkerImpl(ObjectGroup, js::ObjectGroup)
} /* namespace gc */
} /* namespace js */
@ -1087,50 +1189,6 @@ MarkValueInternal(JSTracer* trc, Value* v)
}
}
bool
gc::IsValueMarked(Value* v)
{
MOZ_ASSERT(v->isMarkable());
bool rv;
if (v->isString()) {
JSString* str = (JSString*)v->toGCThing();
rv = IsMarked<JSString>(&str);
v->setString(str);
} else if (v->isObject()) {
JSObject* obj = (JSObject*)v->toGCThing();
rv = IsMarked<JSObject>(&obj);
v->setObject(*obj);
} else {
MOZ_ASSERT(v->isSymbol());
JS::Symbol* sym = v->toSymbol();
rv = IsMarked<JS::Symbol>(&sym);
v->setSymbol(sym);
}
return rv;
}
bool
gc::IsValueAboutToBeFinalized(Value* v)
{
MOZ_ASSERT(v->isMarkable());
bool rv;
if (v->isString()) {
JSString* str = (JSString*)v->toGCThing();
rv = IsAboutToBeFinalized<JSString>(&str);
v->setString(str);
} else if (v->isObject()) {
JSObject* obj = (JSObject*)v->toGCThing();
rv = IsAboutToBeFinalized<JSObject>(&obj);
v->setObject(*obj);
} else {
MOZ_ASSERT(v->isSymbol());
JS::Symbol* sym = v->toSymbol();
rv = IsAboutToBeFinalized<JS::Symbol>(&sym);
v->setSymbol(sym);
}
return rv;
}
/*** Type Marking ***/
void
@ -1157,12 +1215,6 @@ TypeSet::MarkTypeUnbarriered(JSTracer* trc, TypeSet::Type* v, const char* name)
/*** Slot Marking ***/
bool
gc::IsSlotMarked(HeapSlot* s)
{
return IsMarked(s);
}
void
gc::MarkObjectSlots(JSTracer* trc, NativeObject* obj, uint32_t start, uint32_t nslots)
{
@ -1226,10 +1278,16 @@ ShouldMarkCrossCompartment(JSTracer* trc, JSObject* src, Value val)
/*** Special Marking ***/
void
gc::MarkValueForBarrier(JSTracer* trc, Value* v, const char* name)
gc::MarkValueForBarrier(JSTracer* trc, Value* valuep, const char* name)
{
MOZ_ASSERT(!trc->runtime()->isHeapBusy());
TraceManuallyBarrieredEdge(trc, v, name);
TraceManuallyBarrieredEdge(trc, valuep, name);
}
void
gc::MarkIdForBarrier(JSTracer* trc, jsid* idp, const char* name)
{
TraceManuallyBarrieredEdge(trc, idp, name);
}
/*** Push Mark Stack ***/
@ -1271,11 +1329,11 @@ void
BaseShape::markChildren(JSTracer* trc)
{
if (isOwned())
gc::MarkBaseShape(trc, &unowned_, "base");
TraceEdge(trc, &unowned_, "base");
JSObject* global = compartment()->unsafeUnbarrieredMaybeGlobal();
if (global)
MarkObjectUnbarriered(trc, &global, "global");
TraceManuallyBarrieredEdge(trc, &global, "global");
}
static void
@ -1476,7 +1534,7 @@ gc::MarkCycleCollectorChildren(JSTracer* trc, Shape* shape)
*/
JSObject* global = shape->compartment()->unsafeUnbarrieredMaybeGlobal();
MOZ_ASSERT(global);
MarkObjectUnbarriered(trc, &global, "global");
TraceManuallyBarrieredEdge(trc, &global, "global");
do {
MOZ_ASSERT(global == shape->compartment()->unsafeUnbarrieredMaybeGlobal());
@ -1488,13 +1546,13 @@ gc::MarkCycleCollectorChildren(JSTracer* trc, Shape* shape)
if (shape->hasGetterObject()) {
JSObject* tmp = shape->getterObject();
MarkObjectUnbarriered(trc, &tmp, "getter");
TraceManuallyBarrieredEdge(trc, &tmp, "getter");
MOZ_ASSERT(tmp == shape->getterObject());
}
if (shape->hasSetterObject()) {
JSObject* tmp = shape->setterObject();
MarkObjectUnbarriered(trc, &tmp, "setter");
TraceManuallyBarrieredEdge(trc, &tmp, "setter");
MOZ_ASSERT(tmp == shape->setterObject());
}
@ -1548,7 +1606,7 @@ gc::MarkChildren(JSTracer* trc, ObjectGroup* group)
}
if (group->proto().isObject())
MarkObject(trc, &group->protoRaw(), "group_proto");
TraceEdge(trc, &group->protoRaw(), "group_proto");
if (group->newScript())
group->newScript()->trace(trc);
@ -1560,17 +1618,17 @@ gc::MarkChildren(JSTracer* trc, ObjectGroup* group)
group->unboxedLayout().trace(trc);
if (ObjectGroup* unboxedGroup = group->maybeOriginalUnboxedGroup()) {
MarkObjectGroupUnbarriered(trc, &unboxedGroup, "group_original_unboxed_group");
TraceManuallyBarrieredEdge(trc, &unboxedGroup, "group_original_unboxed_group");
group->setOriginalUnboxedGroup(unboxedGroup);
}
if (JSObject* descr = group->maybeTypeDescr()) {
MarkObjectUnbarriered(trc, &descr, "group_type_descr");
TraceManuallyBarrieredEdge(trc, &descr, "group_type_descr");
group->setTypeDescr(&descr->as<TypeDescr>());
}
if (JSObject* fun = group->maybeInterpretedFunction()) {
MarkObjectUnbarriered(trc, &fun, "group_function");
TraceManuallyBarrieredEdge(trc, &fun, "group_function");
group->setInterpretedFunction(&fun->as<JSFunction>());
}
}

View File

@ -62,12 +62,12 @@ TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name);
// Trace all edges contained in the given array.
template <typename T>
void
TraceRange(JSTracer* trc, size_t len, BarrieredBase<T>* thingp, const char* name);
TraceRange(JSTracer* trc, size_t len, BarrieredBase<T>* vec, const char* name);
// Trace all root edges in the given array.
template <typename T>
void
TraceRootRange(JSTracer* trc, size_t len, T* thingp, const char* name);
TraceRootRange(JSTracer* trc, size_t len, T* vec, const char* name);
// Trace an edge that crosses compartment boundaries. If the compartment of the
// destination thing is not being GC'd, then the edge will not be traced.
@ -142,37 +142,6 @@ bool Is##base##AboutToBeFinalized(type** thingp);
bool Is##base##AboutToBeFinalized(BarrieredBase<type*>* thingp); \
type* Update##base##IfRelocated(JSRuntime* rt, BarrieredBase<type*>* thingp); \
type* Update##base##IfRelocated(JSRuntime* rt, type** thingp);
DeclMarker(BaseShape, BaseShape)
DeclMarker(BaseShape, UnownedBaseShape)
DeclMarker(JitCode, jit::JitCode)
DeclMarker(Object, NativeObject)
DeclMarker(Object, ArrayObject)
DeclMarker(Object, ArgumentsObject)
DeclMarker(Object, ArrayBufferObject)
DeclMarker(Object, ArrayBufferObjectMaybeShared)
DeclMarker(Object, ArrayBufferViewObject)
DeclMarker(Object, DebugScopeObject)
DeclMarker(Object, GlobalObject)
DeclMarker(Object, JSObject)
DeclMarker(Object, JSFunction)
DeclMarker(Object, NestedScopeObject)
DeclMarker(Object, PlainObject)
DeclMarker(Object, SavedFrame)
DeclMarker(Object, ScopeObject)
DeclMarker(Object, SharedArrayBufferObject)
DeclMarker(Object, SharedTypedArrayObject)
DeclMarker(Script, JSScript)
DeclMarker(LazyScript, LazyScript)
DeclMarker(Shape, Shape)
DeclMarker(String, JSAtom)
DeclMarker(String, JSString)
DeclMarker(String, JSFlatString)
DeclMarker(String, JSLinearString)
DeclMarker(String, PropertyName)
DeclMarker(Symbol, JS::Symbol)
DeclMarker(ObjectGroup, ObjectGroup)
#undef DeclMarker
void
@ -206,19 +175,8 @@ MarkGCThingRoot(JSTracer* trc, void** thingp, const char* name);
void
MarkGCThingUnbarriered(JSTracer* trc, void** thingp, const char* name);
/*** Value Marking ***/
bool
IsValueMarked(Value* v);
bool
IsValueAboutToBeFinalized(Value* v);
/*** Slot Marking ***/
bool
IsSlotMarked(HeapSlot* s);
void
MarkObjectSlots(JSTracer* trc, NativeObject* obj, uint32_t start, uint32_t nslots);
@ -238,48 +196,28 @@ PushArena(GCMarker* gcmarker, ArenaHeader* aheader);
/*** Generic ***/
template <typename T>
static bool
IsMarked(T** thingp);
bool
IsMarkedUnbarriered(T* thingp);
inline bool
IsMarked(BarrieredBase<Value>* v)
{
if (!v->isMarkable())
return true;
return IsValueMarked(v->unsafeGet());
}
template <typename T>
bool
IsMarked(BarrieredBase<T>* thingp);
inline bool
IsMarked(BarrieredBase<JSObject*>* objp)
{
return IsObjectMarked(objp);
}
template <typename T>
bool
IsMarked(ReadBarriered<T>* thingp);
inline bool
IsMarked(BarrieredBase<JSScript*>* scriptp)
{
return IsScriptMarked(scriptp);
}
template <typename T>
bool
IsAboutToBeFinalizedUnbarriered(T* thingp);
inline bool
IsAboutToBeFinalized(BarrieredBase<Value>* v)
{
if (!v->isMarkable())
return false;
return IsValueAboutToBeFinalized(v->unsafeGet());
}
template <typename T>
bool
IsAboutToBeFinalized(BarrieredBase<T>* thingp);
inline bool
IsAboutToBeFinalized(BarrieredBase<JSObject*>* objp)
{
return IsObjectAboutToBeFinalized(objp);
}
inline bool
IsAboutToBeFinalized(BarrieredBase<JSScript*>* scriptp)
{
return IsScriptAboutToBeFinalized(scriptp);
}
template <typename T>
bool
IsAboutToBeFinalized(ReadBarriered<T>* thingp);
inline bool
IsAboutToBeFinalized(const js::jit::VMFunction** vmfunc)
@ -291,12 +229,6 @@ IsAboutToBeFinalized(const js::jit::VMFunction** vmfunc)
return false;
}
inline bool
IsAboutToBeFinalized(ReadBarrieredJitCode code)
{
return IsJitCodeAboutToBeFinalized(code.unsafeGet());
}
inline Cell*
ToMarkable(const Value& v)
{

View File

@ -94,16 +94,16 @@ template<class T>
static void
MarkExactStackRootsAcrossTypes(T context, JSTracer* trc)
{
MarkExactStackRootList<JSObject*, MarkObjectRoot>(trc, context, "exact-object");
MarkExactStackRootList<Shape*, MarkShapeRoot>(trc, context, "exact-shape");
MarkExactStackRootList<BaseShape*, MarkBaseShapeRoot>(trc, context, "exact-baseshape");
MarkExactStackRootList<ObjectGroup*, MarkObjectGroupRoot>(
MarkExactStackRootList<JSObject*, TraceRoot>(trc, context, "exact-object");
MarkExactStackRootList<Shape*, TraceRoot>(trc, context, "exact-shape");
MarkExactStackRootList<BaseShape*, TraceRoot>(trc, context, "exact-baseshape");
MarkExactStackRootList<ObjectGroup*, TraceRoot>(
trc, context, "exact-objectgroup");
MarkExactStackRootList<JSString*, MarkStringRoot>(trc, context, "exact-string");
MarkExactStackRootList<JS::Symbol*, MarkSymbolRoot>(trc, context, "exact-symbol");
MarkExactStackRootList<jit::JitCode*, MarkJitCodeRoot>(trc, context, "exact-jitcode");
MarkExactStackRootList<JSScript*, MarkScriptRoot>(trc, context, "exact-script");
MarkExactStackRootList<LazyScript*, MarkLazyScriptRoot>(trc, context, "exact-lazy-script");
MarkExactStackRootList<JSString*, TraceRoot>(trc, context, "exact-string");
MarkExactStackRootList<JS::Symbol*, TraceRoot>(trc, context, "exact-symbol");
MarkExactStackRootList<jit::JitCode*, TraceRoot>(trc, context, "exact-jitcode");
MarkExactStackRootList<JSScript*, TraceRoot>(trc, context, "exact-script");
MarkExactStackRootList<LazyScript*, TraceRoot>(trc, context, "exact-lazy-script");
MarkExactStackRootList<jsid, TraceRoot>(trc, context, "exact-id");
MarkExactStackRootList<Value, TraceRoot>(trc, context, "exact-value");
MarkExactStackRootList<TypeSet::Type, TypeSet::MarkTypeRoot>(trc, context, "TypeSet::Type");
@ -172,32 +172,32 @@ AutoGCRooter::trace(JSTracer* trc)
case SHAPEVECTOR: {
AutoShapeVector::VectorImpl& vector = static_cast<js::AutoShapeVector*>(this)->vector;
MarkShapeRootRange(trc, vector.length(), const_cast<Shape**>(vector.begin()),
TraceRootRange(trc, vector.length(), const_cast<Shape**>(vector.begin()),
"js::AutoShapeVector.vector");
return;
}
case OBJVECTOR: {
AutoObjectVector::VectorImpl& vector = static_cast<AutoObjectVector*>(this)->vector;
MarkObjectRootRange(trc, vector.length(), vector.begin(), "js::AutoObjectVector.vector");
TraceRootRange(trc, vector.length(), vector.begin(), "js::AutoObjectVector.vector");
return;
}
case FUNVECTOR: {
AutoFunctionVector::VectorImpl& vector = static_cast<AutoFunctionVector*>(this)->vector;
MarkObjectRootRange(trc, vector.length(), vector.begin(), "js::AutoFunctionVector.vector");
TraceRootRange(trc, vector.length(), vector.begin(), "js::AutoFunctionVector.vector");
return;
}
case STRINGVECTOR: {
AutoStringVector::VectorImpl& vector = static_cast<AutoStringVector*>(this)->vector;
MarkStringRootRange(trc, vector.length(), vector.begin(), "js::AutoStringVector.vector");
TraceRootRange(trc, vector.length(), vector.begin(), "js::AutoStringVector.vector");
return;
}
case NAMEVECTOR: {
AutoNameVector::VectorImpl& vector = static_cast<AutoNameVector*>(this)->vector;
MarkStringRootRange(trc, vector.length(), vector.begin(), "js::AutoNameVector.vector");
TraceRootRange(trc, vector.length(), vector.begin(), "js::AutoNameVector.vector");
return;
}
@ -213,17 +213,17 @@ AutoGCRooter::trace(JSTracer* trc)
case SCRIPTVECTOR: {
AutoScriptVector::VectorImpl& vector = static_cast<AutoScriptVector*>(this)->vector;
MarkScriptRootRange(trc, vector.length(), vector.begin(), "js::AutoScriptVector.vector");
TraceRootRange(trc, vector.length(), vector.begin(), "js::AutoScriptVector.vector");
return;
}
case OBJOBJHASHMAP: {
AutoObjectObjectHashMap::HashMapImpl& map = static_cast<AutoObjectObjectHashMap*>(this)->map;
for (AutoObjectObjectHashMap::Enum e(map); !e.empty(); e.popFront()) {
MarkObjectRoot(trc, &e.front().value(), "AutoObjectObjectHashMap value");
TraceRoot(trc, &e.front().value(), "AutoObjectObjectHashMap value");
trc->setTracingLocation((void*)&e.front().key());
JSObject* key = e.front().key();
MarkObjectRoot(trc, &key, "AutoObjectObjectHashMap key");
TraceRoot(trc, &key, "AutoObjectObjectHashMap key");
if (key != e.front().key())
e.rekeyFront(key);
}
@ -235,7 +235,7 @@ AutoGCRooter::trace(JSTracer* trc)
AutoObjectUnsigned32HashMap::HashMapImpl& map = self->map;
for (AutoObjectUnsigned32HashMap::Enum e(map); !e.empty(); e.popFront()) {
JSObject* key = e.front().key();
MarkObjectRoot(trc, &key, "AutoObjectUnsignedHashMap key");
TraceRoot(trc, &key, "AutoObjectUnsignedHashMap key");
if (key != e.front().key())
e.rekeyFront(key);
}
@ -247,7 +247,7 @@ AutoGCRooter::trace(JSTracer* trc)
AutoObjectHashSet::HashSetImpl& set = self->set;
for (AutoObjectHashSet::Enum e(set); !e.empty(); e.popFront()) {
JSObject* obj = e.front();
MarkObjectRoot(trc, &obj, "AutoObjectHashSet value");
TraceRoot(trc, &obj, "AutoObjectHashSet value");
if (obj != e.front())
e.rekeyFront(obj);
}
@ -330,31 +330,31 @@ void
StackShape::trace(JSTracer* trc)
{
if (base)
MarkBaseShapeRoot(trc, (BaseShape**) &base, "StackShape base");
TraceRoot(trc, &base, "StackShape base");
TraceRoot(trc, (jsid*) &propid, "StackShape id");
if ((attrs & JSPROP_GETTER) && rawGetter)
MarkObjectRoot(trc, (JSObject**)&rawGetter, "StackShape getter");
TraceRoot(trc, (JSObject**)&rawGetter, "StackShape getter");
if ((attrs & JSPROP_SETTER) && rawSetter)
MarkObjectRoot(trc, (JSObject**)&rawSetter, "StackShape setter");
TraceRoot(trc, (JSObject**)&rawSetter, "StackShape setter");
}
void
JSPropertyDescriptor::trace(JSTracer* trc)
{
if (obj)
MarkObjectRoot(trc, &obj, "Descriptor::obj");
TraceRoot(trc, &obj, "Descriptor::obj");
TraceRoot(trc, &value, "Descriptor::value");
if ((attrs & JSPROP_GETTER) && getter) {
JSObject* tmp = JS_FUNC_TO_DATA_PTR(JSObject*, getter);
MarkObjectRoot(trc, &tmp, "Descriptor::get");
TraceRoot(trc, &tmp, "Descriptor::get");
getter = JS_DATA_TO_FUNC_PTR(JSGetterOp, tmp);
}
if ((attrs & JSPROP_SETTER) && setter) {
JSObject* tmp = JS_FUNC_TO_DATA_PTR(JSObject*, setter);
MarkObjectRoot(trc, &tmp, "Descriptor::set");
TraceRoot(trc, &tmp, "Descriptor::set");
setter = JS_DATA_TO_FUNC_PTR(JSSetterOp, tmp);
}
}
@ -369,22 +369,20 @@ struct PersistentRootedMarker
typedef mozilla::LinkedList<Element> List;
typedef void (*MarkFunc)(JSTracer* trc, T* ref, const char* name);
template <MarkFunc Mark>
static void
markChainIfNotNull(JSTracer* trc, List& list, const char* name)
{
for (Element* r = list.getFirst(); r; r = r->getNext()) {
if (r->get())
Mark(trc, r->address(), name);
TraceRoot(trc, r->address(), name);
}
}
template <MarkFunc Mark>
static void
markChain(JSTracer* trc, List& list, const char* name)
{
for (Element* r = list.getFirst(); r; r = r->getNext())
Mark(trc, r->address(), name);
TraceRoot(trc, r->address(), name);
}
};
}
@ -396,19 +394,19 @@ js::gc::MarkPersistentRootedChains(JSTracer* trc)
JSRuntime* rt = trc->runtime();
// Mark the PersistentRooted chains of types that may be null.
PersistentRootedMarker<JSFunction*>::markChainIfNotNull<MarkObjectRoot>(
trc, rt->functionPersistentRooteds, "PersistentRooted<JSFunction*>");
PersistentRootedMarker<JSObject*>::markChainIfNotNull<MarkObjectRoot>(
trc, rt->objectPersistentRooteds, "PersistentRooted<JSObject*>");
PersistentRootedMarker<JSScript*>::markChainIfNotNull<MarkScriptRoot>(
trc, rt->scriptPersistentRooteds, "PersistentRooted<JSScript*>");
PersistentRootedMarker<JSString*>::markChainIfNotNull<MarkStringRoot>(
trc, rt->stringPersistentRooteds, "PersistentRooted<JSString*>");
PersistentRootedMarker<JSFunction*>::markChainIfNotNull(trc, rt->functionPersistentRooteds,
"PersistentRooted<JSFunction*>");
PersistentRootedMarker<JSObject*>::markChainIfNotNull(trc, rt->objectPersistentRooteds,
"PersistentRooted<JSObject*>");
PersistentRootedMarker<JSScript*>::markChainIfNotNull(trc, rt->scriptPersistentRooteds,
"PersistentRooted<JSScript*>");
PersistentRootedMarker<JSString*>::markChainIfNotNull(trc, rt->stringPersistentRooteds,
"PersistentRooted<JSString*>");
// Mark the PersistentRooted chains of types that are never null.
PersistentRootedMarker<jsid>::markChain<TraceRoot>(trc, rt->idPersistentRooteds,
PersistentRootedMarker<jsid>::markChain(trc, rt->idPersistentRooteds,
"PersistentRooted<jsid>");
PersistentRootedMarker<Value>::markChain<TraceRoot>(trc, rt->valuePersistentRooteds,
PersistentRootedMarker<Value>::markChain(trc, rt->valuePersistentRooteds,
"PersistentRooted<Value>");
}
@ -453,17 +451,15 @@ js::gc::GCRuntime::markRuntime(JSTracer* trc,
}
if (rt->asyncStackForNewActivations)
MarkObjectRoot(trc, &rt->asyncStackForNewActivations,
"asyncStackForNewActivations");
TraceRoot(trc, &rt->asyncStackForNewActivations, "asyncStackForNewActivations");
if (rt->asyncCauseForNewActivations)
MarkStringRoot(trc, &rt->asyncCauseForNewActivations,
"asyncCauseForNewActivations");
TraceRoot(trc, &rt->asyncCauseForNewActivations, "asyncCauseForNewActivations");
if (rt->scriptAndCountsVector) {
ScriptAndCountsVector& vec = *rt->scriptAndCountsVector;
for (size_t i = 0; i < vec.length(); i++)
MarkScriptRoot(trc, &vec[i].script, "scriptAndCountsVector");
TraceRoot(trc, &vec[i].script, "scriptAndCountsVector");
}
if (!rt->isBeingDestroyed() && !trc->runtime()->isHeapMinorCollecting()) {
@ -489,7 +485,7 @@ js::gc::GCRuntime::markRuntime(JSTracer* trc,
for (ZoneCellIterUnderGC i(zone, AllocKind::SCRIPT); !i.done(); i.next()) {
JSScript* script = i.get<JSScript>();
if (script->hasScriptCounts()) {
MarkScriptRoot(trc, &script, "profilingScripts");
TraceRoot(trc, &script, "profilingScripts");
MOZ_ASSERT(script == i.get<JSScript>());
}
}

View File

@ -69,7 +69,7 @@ StoreBuffer::CellPtrEdge::mark(JSTracer* trc) const
return;
MOZ_ASSERT(GetGCThingTraceKind(*edge) == JSTRACE_OBJECT);
MarkObjectRoot(trc, reinterpret_cast<JSObject**>(edge), "store buffer edge");
TraceRoot(trc, reinterpret_cast<JSObject**>(edge), "store buffer edge");
}
void

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