mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Merge inbound to m-c. a=merge
This commit is contained in:
commit
125f61c64f
@ -525,6 +525,8 @@ addEventListener("DOMServiceWorkerFocusClient", function(event) {
|
||||
}, false);
|
||||
|
||||
ContentWebRTC.init();
|
||||
addMessageListener("rtcpeer:Allow", ContentWebRTC);
|
||||
addMessageListener("rtcpeer:Deny", ContentWebRTC);
|
||||
addMessageListener("webrtc:Allow", ContentWebRTC);
|
||||
addMessageListener("webrtc:Deny", ContentWebRTC);
|
||||
addMessageListener("webrtc:StopSharing", ContentWebRTC);
|
||||
|
@ -682,6 +682,11 @@
|
||||
// If the browser is loading it must not be crashed anymore
|
||||
this.mTab.removeAttribute("crashed");
|
||||
|
||||
// If the browser was playing audio, we should remove the playing state.
|
||||
if (this.mTab.hasAttribute("soundplaying")) {
|
||||
this.mTab.removeAttribute("soundplaying");
|
||||
this.mTabBrowser._tabAttrModified(this.mTab, ["soundplaying"]);
|
||||
}
|
||||
// If the browser was previously muted, we should restore the muted state.
|
||||
if (this.mTab.hasAttribute("muted")) {
|
||||
this.mTab.linkedBrowser.mute();
|
||||
@ -3366,6 +3371,8 @@
|
||||
let tab = this.tabbrowser.getTabForBrowser(browser);
|
||||
this.setTabState(tab, this.STATE_LOADED);
|
||||
|
||||
this.finishTabSwitch();
|
||||
|
||||
if (this.loadingTab === tab) {
|
||||
clearTimeout(this.loadTimer);
|
||||
this.loadTimer = null;
|
||||
|
@ -227,6 +227,39 @@ function* test_click_on_pinned_tab_after_mute() {
|
||||
}, test_on_browser);
|
||||
}
|
||||
|
||||
// This test only does something useful in e10s!
|
||||
function* test_cross_process_load() {
|
||||
function* test_on_browser(browser) {
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
|
||||
// Start playback.
|
||||
yield ContentTask.spawn(browser, {}, function* () {
|
||||
let audio = content.document.querySelector("audio");
|
||||
audio.play();
|
||||
});
|
||||
|
||||
// Wait for playback to start.
|
||||
yield wait_for_tab_playing_event(tab, true);
|
||||
|
||||
let soundPlayingStoppedPromise = BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false,
|
||||
event => event.detail.changed.indexOf("soundplaying") >= 0
|
||||
);
|
||||
|
||||
// Go to a different process.
|
||||
browser.loadURI("about:");
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
yield soundPlayingStoppedPromise;
|
||||
|
||||
ok(!tab.hasAttribute("soundplaying"), "Tab should not be playing sound any more");
|
||||
}
|
||||
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: PAGE
|
||||
}, test_on_browser);
|
||||
}
|
||||
|
||||
function* test_on_browser(browser) {
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
|
||||
@ -248,8 +281,6 @@ function* test_on_browser(browser) {
|
||||
}, () => test_on_browser(browser));
|
||||
} else {
|
||||
yield test_browser_swapping(tab, browser);
|
||||
|
||||
yield test_click_on_pinned_tab_after_mute();
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,3 +300,7 @@ add_task(function* test_page() {
|
||||
url: PAGE
|
||||
}, test_on_browser);
|
||||
});
|
||||
|
||||
add_task(test_click_on_pinned_tab_after_mute);
|
||||
|
||||
add_task(test_cross_process_load);
|
||||
|
@ -22,7 +22,8 @@ this.ContentWebRTC = {
|
||||
return;
|
||||
|
||||
this._initialized = true;
|
||||
Services.obs.addObserver(handleRequest, "getUserMedia:request", false);
|
||||
Services.obs.addObserver(handleGUMRequest, "getUserMedia:request", false);
|
||||
Services.obs.addObserver(handlePCRequest, "PeerConnection:request", false);
|
||||
Services.obs.addObserver(updateIndicators, "recording-device-events", false);
|
||||
Services.obs.addObserver(removeBrowserSpecificIndicator, "recording-window-ended", false);
|
||||
},
|
||||
@ -31,17 +32,31 @@ this.ContentWebRTC = {
|
||||
handleEvent: function(aEvent) {
|
||||
let contentWindow = aEvent.target.defaultView;
|
||||
let mm = getMessageManagerForWindow(contentWindow);
|
||||
for (let key of contentWindow.pendingGetUserMediaRequests.keys())
|
||||
for (let key of contentWindow.pendingGetUserMediaRequests.keys()) {
|
||||
mm.sendAsyncMessage("webrtc:CancelRequest", key);
|
||||
}
|
||||
for (let key of contentWindow.pendingPeerConnectionRequests.keys()) {
|
||||
mm.sendAsyncMessage("rtcpeer:CancelRequest", key);
|
||||
}
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
switch (aMessage.name) {
|
||||
case "webrtc:Allow":
|
||||
case "rtcpeer:Allow":
|
||||
case "rtcpeer:Deny": {
|
||||
let callID = aMessage.data.callID;
|
||||
let contentWindow = Services.wm.getOuterWindowWithId(aMessage.data.windowID);
|
||||
forgetPCRequest(contentWindow, callID);
|
||||
let topic = (aMessage.name == "rtcpeer:Allow") ? "PeerConnection:response:allow" :
|
||||
"PeerConnection:response:deny";
|
||||
Services.obs.notifyObservers(null, topic, callID);
|
||||
break;
|
||||
}
|
||||
case "webrtc:Allow": {
|
||||
let callID = aMessage.data.callID;
|
||||
let contentWindow = Services.wm.getOuterWindowWithId(aMessage.data.windowID);
|
||||
let devices = contentWindow.pendingGetUserMediaRequests.get(callID);
|
||||
forgetRequest(contentWindow, callID);
|
||||
forgetGUMRequest(contentWindow, callID);
|
||||
|
||||
let allowedDevices = Cc["@mozilla.org/supports-array;1"]
|
||||
.createInstance(Ci.nsISupportsArray);
|
||||
@ -50,8 +65,9 @@ this.ContentWebRTC = {
|
||||
|
||||
Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", callID);
|
||||
break;
|
||||
}
|
||||
case "webrtc:Deny":
|
||||
denyRequest(aMessage.data);
|
||||
denyGUMRequest(aMessage.data);
|
||||
break;
|
||||
case "webrtc:StopSharing":
|
||||
Services.obs.notifyObservers(null, "getUserMedia:revoke", aMessage.data);
|
||||
@ -60,7 +76,28 @@ this.ContentWebRTC = {
|
||||
}
|
||||
};
|
||||
|
||||
function handleRequest(aSubject, aTopic, aData) {
|
||||
function handlePCRequest(aSubject, aTopic, aData) {
|
||||
let { windowID, innerWindowID, callID, isSecure } = aSubject;
|
||||
let contentWindow = Services.wm.getOuterWindowWithId(windowID);
|
||||
|
||||
if (!contentWindow.pendingPeerConnectionRequests) {
|
||||
setupPendingListsInitially(contentWindow);
|
||||
}
|
||||
contentWindow.pendingPeerConnectionRequests.add(callID);
|
||||
|
||||
let request = {
|
||||
windowID: windowID,
|
||||
innerWindowID: innerWindowID,
|
||||
callID: callID,
|
||||
documentURI: contentWindow.document.documentURI,
|
||||
secure: isSecure,
|
||||
};
|
||||
|
||||
let mm = getMessageManagerForWindow(contentWindow);
|
||||
mm.sendAsyncMessage("rtcpeer:Request", request);
|
||||
}
|
||||
|
||||
function handleGUMRequest(aSubject, aTopic, aData) {
|
||||
let constraints = aSubject.getConstraints();
|
||||
let secure = aSubject.isSecure;
|
||||
let contentWindow = Services.wm.getOuterWindowWithId(aSubject.windowID);
|
||||
@ -74,7 +111,7 @@ function handleRequest(aSubject, aTopic, aData) {
|
||||
function (error) {
|
||||
// bug 827146 -- In the future, the UI should catch NotFoundError
|
||||
// and allow the user to plug in a device, instead of immediately failing.
|
||||
denyRequest({callID: aSubject.callID}, error);
|
||||
denyGUMRequest({callID: aSubject.callID}, error);
|
||||
},
|
||||
aSubject.innerWindowID);
|
||||
}
|
||||
@ -123,13 +160,12 @@ function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSec
|
||||
requestTypes.push(sharingAudio ? "AudioCapture" : "Microphone");
|
||||
|
||||
if (!requestTypes.length) {
|
||||
denyRequest({callID: aCallID}, "NotFoundError");
|
||||
denyGUMRequest({callID: aCallID}, "NotFoundError");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aContentWindow.pendingGetUserMediaRequests) {
|
||||
aContentWindow.pendingGetUserMediaRequests = new Map();
|
||||
aContentWindow.addEventListener("unload", ContentWebRTC);
|
||||
setupPendingListsInitially(aContentWindow);
|
||||
}
|
||||
aContentWindow.pendingGetUserMediaRequests.set(aCallID, devices);
|
||||
|
||||
@ -149,7 +185,7 @@ function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSec
|
||||
mm.sendAsyncMessage("webrtc:Request", request);
|
||||
}
|
||||
|
||||
function denyRequest(aData, aError) {
|
||||
function denyGUMRequest(aData, aError) {
|
||||
let msg = null;
|
||||
if (aError) {
|
||||
msg = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
|
||||
@ -161,16 +197,36 @@ function denyRequest(aData, aError) {
|
||||
return;
|
||||
let contentWindow = Services.wm.getOuterWindowWithId(aData.windowID);
|
||||
if (contentWindow.pendingGetUserMediaRequests)
|
||||
forgetRequest(contentWindow, aData.callID);
|
||||
forgetGUMRequest(contentWindow, aData.callID);
|
||||
}
|
||||
|
||||
function forgetRequest(aContentWindow, aCallID) {
|
||||
function forgetGUMRequest(aContentWindow, aCallID) {
|
||||
aContentWindow.pendingGetUserMediaRequests.delete(aCallID);
|
||||
if (aContentWindow.pendingGetUserMediaRequests.size)
|
||||
return;
|
||||
forgetPendingListsEventually(aContentWindow);
|
||||
}
|
||||
|
||||
aContentWindow.removeEventListener("unload", ContentWebRTC);
|
||||
function forgetPCRequest(aContentWindow, aCallID) {
|
||||
aContentWindow.pendingPeerConnectionRequests.delete(aCallID);
|
||||
forgetPendingListsEventually(aContentWindow);
|
||||
}
|
||||
|
||||
function setupPendingListsInitially(aContentWindow) {
|
||||
if (aContentWindow.pendingGetUserMediaRequests) {
|
||||
return;
|
||||
}
|
||||
aContentWindow.pendingGetUserMediaRequests = new Map();
|
||||
aContentWindow.pendingPeerConnectionRequests = new Set();
|
||||
aContentWindow.addEventListener("unload", ContentWebRTC);
|
||||
}
|
||||
|
||||
function forgetPendingListsEventually(aContentWindow) {
|
||||
if (aContentWindow.pendingGetUserMediaRequests.size ||
|
||||
aContentWindow.pendingPeerConnectionRequests.size) {
|
||||
return;
|
||||
}
|
||||
aContentWindow.pendingGetUserMediaRequests = null;
|
||||
aContentWindow.pendingPeerConnectionRequests = null;
|
||||
aContentWindow.removeEventListener("unload", ContentWebRTC);
|
||||
}
|
||||
|
||||
function updateIndicators() {
|
||||
|
@ -29,6 +29,8 @@ this.webrtcUI = {
|
||||
|
||||
let mm = Cc["@mozilla.org/globalmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageListenerManager);
|
||||
mm.addMessageListener("rtcpeer:Request", this);
|
||||
mm.addMessageListener("rtcpeer:CancelRequest", this);
|
||||
mm.addMessageListener("webrtc:Request", this);
|
||||
mm.addMessageListener("webrtc:CancelRequest", this);
|
||||
mm.addMessageListener("webrtc:UpdateBrowserIndicators", this);
|
||||
@ -44,6 +46,8 @@ this.webrtcUI = {
|
||||
|
||||
let mm = Cc["@mozilla.org/globalmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageListenerManager);
|
||||
mm.removeMessageListener("rtcpeer:Request", this);
|
||||
mm.removeMessageListener("rtcpeer:CancelRequest", this);
|
||||
mm.removeMessageListener("webrtc:Request", this);
|
||||
mm.removeMessageListener("webrtc:CancelRequest", this);
|
||||
mm.removeMessageListener("webrtc:UpdateBrowserIndicators", this);
|
||||
@ -124,6 +128,47 @@ this.webrtcUI = {
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
switch (aMessage.name) {
|
||||
|
||||
// Add-ons can override stock permission behavior by doing:
|
||||
//
|
||||
// var stockReceiveMessage = webrtcUI.receiveMessage;
|
||||
//
|
||||
// webrtcUI.receiveMessage = function(aMessage) {
|
||||
// switch (aMessage.name) {
|
||||
// case "rtcpeer:Request": {
|
||||
// // new code.
|
||||
// break;
|
||||
// ...
|
||||
// default:
|
||||
// return stockReceiveMessage.call(this, aMessage);
|
||||
//
|
||||
// Intercepting gUM and peerConnection requests should let an add-on
|
||||
// limit PeerConnection activity with automatic rules and/or prompts
|
||||
// in a sensible manner that avoids double-prompting in typical
|
||||
// gUM+PeerConnection scenarios. For example:
|
||||
//
|
||||
// State Sample Action
|
||||
// --------------------------------------------------------------
|
||||
// No IP leaked yet + No gUM granted Warn user
|
||||
// No IP leaked yet + gUM granted Avoid extra dialog
|
||||
// No IP leaked yet + gUM request pending. Delay until gUM grant
|
||||
// IP already leaked Too late to warn
|
||||
|
||||
case "rtcpeer:Request": {
|
||||
// Always allow. This code-point exists for add-ons to override.
|
||||
let { callID, windowID } = aMessage.data;
|
||||
// Also available: isSecure, innerWindowID. For contentWindow:
|
||||
//
|
||||
// let contentWindow = Services.wm.getOuterWindowWithId(windowID);
|
||||
|
||||
let mm = aMessage.target.messageManager;
|
||||
mm.sendAsyncMessage("rtcpeer:Allow",
|
||||
{ callID: callID, windowID: windowID });
|
||||
break;
|
||||
}
|
||||
case "rtcpeer:CancelRequest":
|
||||
// No data to release. This code-point exists for add-ons to override.
|
||||
break;
|
||||
case "webrtc:Request":
|
||||
prompt(aMessage.target, aMessage.data);
|
||||
break;
|
||||
@ -441,7 +486,7 @@ function prompt(aBrowser, aRequest) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mm = notification.browser.messageManager
|
||||
let mm = notification.browser.messageManager;
|
||||
mm.sendAsyncMessage("webrtc:Allow", {callID: aRequest.callID,
|
||||
windowID: aRequest.windowID,
|
||||
devices: allowedDevices});
|
||||
|
@ -111,7 +111,7 @@ nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAutoCString hostPort;
|
||||
nsAutoCString host;
|
||||
|
||||
// chrome: URLs don't have a meaningful origin, so make
|
||||
// sure we just get the full spec for them.
|
||||
@ -120,10 +120,10 @@ nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin)
|
||||
bool isChrome;
|
||||
nsresult rv = origin->SchemeIs("chrome", &isChrome);
|
||||
if (NS_SUCCEEDED(rv) && !isChrome) {
|
||||
rv = origin->GetAsciiHost(hostPort);
|
||||
rv = origin->GetAsciiHost(host);
|
||||
// Some implementations return an empty string, treat it as no support
|
||||
// for asciiHost by that implementation.
|
||||
if (hostPort.IsEmpty()) {
|
||||
if (host.IsEmpty()) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
@ -159,6 +159,15 @@ nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin)
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv) && !isChrome) {
|
||||
nsAutoCString hostPort;
|
||||
if (host.FindChar(':') != -1) {
|
||||
hostPort.Assign("[");
|
||||
hostPort.Append(host);
|
||||
hostPort.Append("]");
|
||||
} else {
|
||||
hostPort.Assign(host);
|
||||
}
|
||||
|
||||
if (port != -1) {
|
||||
hostPort.Append(':');
|
||||
hostPort.AppendInt(port, 10);
|
||||
|
@ -47,6 +47,12 @@ function run_test() {
|
||||
var nullPrin = Cu.getObjectPrincipal(new Cu.Sandbox(null));
|
||||
do_check_true(/^moz-nullprincipal:\{([0-9]|[a-z]|\-){36}\}$/.test(nullPrin.origin));
|
||||
checkOriginAttributes(nullPrin);
|
||||
var ipv6Prin = ssm.createCodebasePrincipal(makeURI('https://[2001:db8::ff00:42:8329]:123'), {});
|
||||
do_check_eq(ipv6Prin.origin, 'https://[2001:db8::ff00:42:8329]:123');
|
||||
checkOriginAttributes(ipv6Prin);
|
||||
var ipv6NPPrin = ssm.createCodebasePrincipal(makeURI('https://[2001:db8::ff00:42:8329]'), {});
|
||||
do_check_eq(ipv6NPPrin.origin, 'https://[2001:db8::ff00:42:8329]');
|
||||
checkOriginAttributes(ipv6NPPrin);
|
||||
var ep = ssm.createExpandedPrincipal([exampleCom, nullPrin, exampleOrg]);
|
||||
checkOriginAttributes(ep);
|
||||
checkCrossOrigin(exampleCom, exampleOrg);
|
||||
|
@ -463,51 +463,22 @@ void
|
||||
ImportLoader::Open()
|
||||
{
|
||||
AutoError ae(this, false);
|
||||
// Imports should obey to the master documents CSP.
|
||||
nsCOMPtr<nsIDocument> master = mImportParent->MasterDocument();
|
||||
nsIPrincipal* principal = Principal();
|
||||
|
||||
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
|
||||
nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_SUBDOCUMENT,
|
||||
mURI,
|
||||
principal,
|
||||
mImportParent,
|
||||
NS_LITERAL_CSTRING("text/html"),
|
||||
/* extra = */ nullptr,
|
||||
&shouldLoad,
|
||||
nsContentUtils::GetContentPolicy(),
|
||||
nsContentUtils::GetSecurityManager());
|
||||
if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
|
||||
NS_WARN_IF_FALSE(NS_CP_ACCEPTED(shouldLoad), "ImportLoader rejected by CSP");
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsILoadGroup> loadGroup =
|
||||
mImportParent->MasterDocument()->GetDocumentLoadGroup();
|
||||
|
||||
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
||||
rv = secMan->CheckLoadURIWithPrincipal(principal, mURI,
|
||||
nsIScriptSecurityManager::STANDARD);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = master->GetDocumentLoadGroup();
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = NS_NewChannel(getter_AddRefs(channel),
|
||||
mURI,
|
||||
mImportParent,
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_SUBDOCUMENT,
|
||||
loadGroup,
|
||||
nullptr, // aCallbacks
|
||||
nsIRequest::LOAD_BACKGROUND);
|
||||
nsresult rv = NS_NewChannel(getter_AddRefs(channel),
|
||||
mURI,
|
||||
mImportParent,
|
||||
nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS,
|
||||
nsIContentPolicy::TYPE_SUBDOCUMENT,
|
||||
loadGroup,
|
||||
nullptr, // aCallbacks
|
||||
nsIRequest::LOAD_BACKGROUND);
|
||||
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
// Init CORSListenerProxy and omit credentials.
|
||||
nsRefPtr<nsCORSListenerProxy> corsListener =
|
||||
new nsCORSListenerProxy(this, principal,
|
||||
/* aWithCredentials */ false);
|
||||
rv = corsListener->Init(channel, DataURIHandling::Allow);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
rv = channel->AsyncOpen(corsListener, nullptr);
|
||||
rv = channel->AsyncOpen2(this);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
BlockScripts();
|
||||
|
@ -10,4 +10,4 @@
|
||||
* designed to be used as input to the C preprocessor *only*.
|
||||
*/
|
||||
|
||||
DOCUMENT_WARNING(WillChangeOverBudgetIgnored)
|
||||
DOCUMENT_WARNING(IgnoringWillChangeOverBudget)
|
||||
|
@ -4516,8 +4516,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
${mozMapType} &mozMap = ${mozMapRef};
|
||||
|
||||
JS::Rooted<JSObject*> mozMapObj(cx, &$${val}.toObject());
|
||||
JS::AutoIdArray ids(cx, JS_Enumerate(cx, mozMapObj));
|
||||
if (!ids) {
|
||||
JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
|
||||
if (!JS_Enumerate(cx, mozMapObj, &ids)) {
|
||||
$*{exceptionCode}
|
||||
}
|
||||
JS::Rooted<JS::Value> propNameValue(cx);
|
||||
|
@ -79,8 +79,7 @@ static const gl::GLFeature kRequiredFeatures[] = {
|
||||
gl::GLFeature::element_index_uint,
|
||||
gl::GLFeature::frag_color_float,
|
||||
gl::GLFeature::frag_depth,
|
||||
gl::GLFeature::framebuffer_blit,
|
||||
gl::GLFeature::framebuffer_multisample,
|
||||
gl::GLFeature::framebuffer_object,
|
||||
gl::GLFeature::get_integer_indexed,
|
||||
gl::GLFeature::get_integer64_indexed,
|
||||
gl::GLFeature::gpu_shader4,
|
||||
@ -165,6 +164,16 @@ WebGLContext::InitWebGL2()
|
||||
gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
|
||||
&mGLMaxUniformBufferBindings);
|
||||
|
||||
if (MinCapabilityMode()) {
|
||||
mGLMax3DTextureSize = MINVALUE_GL_MAX_3D_TEXTURE_SIZE;
|
||||
mGLMaxArrayTextureLayers = MINVALUE_GL_MAX_ARRAY_TEXTURE_LAYERS;
|
||||
} else {
|
||||
gl->fGetIntegerv(LOCAL_GL_MAX_3D_TEXTURE_SIZE,
|
||||
(GLint*) &mGLMax3DTextureSize);
|
||||
gl->fGetIntegerv(LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS,
|
||||
(GLint*) &mGLMaxArrayTextureLayers);
|
||||
}
|
||||
|
||||
mBoundTransformFeedbackBuffers.SetLength(mGLMaxTransformFeedbackSeparateAttribs);
|
||||
mBoundUniformBuffers.SetLength(mGLMaxUniformBufferBindings);
|
||||
|
||||
|
@ -8,6 +8,12 @@
|
||||
|
||||
#include "WebGLContext.h"
|
||||
|
||||
/*
|
||||
* Minimum value constants define in 6.2 State Tables of OpenGL ES - 3.0.4
|
||||
*/
|
||||
#define MINVALUE_GL_MAX_3D_TEXTURE_SIZE 256
|
||||
#define MINVALUE_GL_MAX_ARRAY_TEXTURE_LAYERS 256
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
@ -55,13 +61,20 @@ public:
|
||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
||||
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||
GLbitfield mask, GLenum filter);
|
||||
void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
|
||||
void GetInternalformatParameter(JSContext*, GLenum target, GLenum internalformat, GLenum pname, JS::MutableHandleValue retval);
|
||||
void FramebufferTextureLayer(GLenum target, GLenum attachment, WebGLTexture* texture, GLint level, GLint layer);
|
||||
void InvalidateFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments,
|
||||
ErrorResult& rv);
|
||||
void InvalidateSubFramebuffer (GLenum target, const dom::Sequence<GLenum>& attachments, GLint x, GLint y,
|
||||
GLsizei width, GLsizei height, ErrorResult& rv);
|
||||
void ReadBuffer(GLenum mode);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Renderbuffer objects - WebGL2ContextRenderbuffers.cpp
|
||||
|
||||
void GetInternalformatParameter(JSContext*, GLenum target, GLenum internalformat,
|
||||
GLenum pname, JS::MutableHandleValue retval,
|
||||
ErrorResult& rv);
|
||||
void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat,
|
||||
GLsizei width, GLsizei height);
|
||||
|
||||
|
@ -330,16 +330,92 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
|
||||
mask, filter);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)
|
||||
static bool
|
||||
ValidateTextureLayerAttachment(GLenum attachment)
|
||||
{
|
||||
GenerateWarning("framebufferTextureLayer: Not Implemented.");
|
||||
if (LOCAL_GL_COLOR_ATTACHMENT0 < attachment &&
|
||||
attachment <= LOCAL_GL_COLOR_ATTACHMENT15)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (attachment) {
|
||||
case LOCAL_GL_DEPTH_ATTACHMENT:
|
||||
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
|
||||
case LOCAL_GL_STENCIL_ATTACHMENT:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::GetInternalformatParameter(JSContext*, GLenum target, GLenum internalformat, GLenum pname, JS::MutableHandleValue retval)
|
||||
WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
|
||||
WebGLTexture* texture, GLint level, GLint layer)
|
||||
{
|
||||
GenerateWarning("getInternalformatParameter: Not Implemented.");
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateFramebufferTarget(target, "framebufferTextureLayer"))
|
||||
return;
|
||||
|
||||
if (!ValidateTextureLayerAttachment(attachment))
|
||||
return ErrorInvalidEnumInfo("framebufferTextureLayer: attachment:", attachment);
|
||||
|
||||
if (texture) {
|
||||
if (texture->IsDeleted()) {
|
||||
return ErrorInvalidValue("framebufferTextureLayer: texture must be a valid "
|
||||
"texture object.");
|
||||
}
|
||||
|
||||
if (level < 0)
|
||||
return ErrorInvalidValue("framebufferTextureLayer: layer must be >= 0.");
|
||||
|
||||
switch (texture->Target()) {
|
||||
case LOCAL_GL_TEXTURE_3D:
|
||||
if ((GLuint) layer >= mGLMax3DTextureSize) {
|
||||
return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
|
||||
"MAX_3D_TEXTURE_SIZE");
|
||||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TEXTURE_2D_ARRAY:
|
||||
if ((GLuint) layer >= mGLMaxArrayTextureLayers) {
|
||||
return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
|
||||
"MAX_ARRAY_TEXTURE_LAYERS");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return ErrorInvalidOperation("framebufferTextureLayer: texture must be an "
|
||||
"existing 3D texture, or a 2D texture array.");
|
||||
}
|
||||
} else {
|
||||
return ErrorInvalidOperation("framebufferTextureLayer: texture must be an "
|
||||
"existing 3D texture, or a 2D texture array.");
|
||||
}
|
||||
|
||||
WebGLFramebuffer* fb;
|
||||
switch (target) {
|
||||
case LOCAL_GL_FRAMEBUFFER:
|
||||
case LOCAL_GL_DRAW_FRAMEBUFFER:
|
||||
fb = mBoundDrawFramebuffer;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_READ_FRAMEBUFFER:
|
||||
fb = mBoundReadFramebuffer;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Bad target.");
|
||||
}
|
||||
|
||||
if (!fb) {
|
||||
return ErrorInvalidOperation("framebufferTextureLayer: cannot modify"
|
||||
" framebuffer 0.");
|
||||
}
|
||||
|
||||
fb->FramebufferTextureLayer(attachment, texture, level, layer);
|
||||
}
|
||||
|
||||
// Map attachments intended for the default buffer, to attachments for a non-
|
||||
@ -536,13 +612,4 @@ WebGL2Context::ReadBuffer(GLenum mode)
|
||||
gl->Screen()->SetReadBuffer(mode);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::RenderbufferStorageMultisample(GLenum target, GLsizei samples,
|
||||
GLenum internalFormat,
|
||||
GLsizei width, GLsizei height)
|
||||
{
|
||||
RenderbufferStorage_base("renderbufferStorageMultisample", target, samples,
|
||||
internalFormat, width, height);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
66
dom/canvas/WebGL2ContextRenderbuffers.cpp
Normal file
66
dom/canvas/WebGL2ContextRenderbuffers.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WebGL2Context.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "WebGLContextUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
void
|
||||
WebGL2Context::GetInternalformatParameter(JSContext* cx, GLenum target,
|
||||
GLenum internalformat, GLenum pname,
|
||||
JS::MutableHandleValue retval,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (target != LOCAL_GL_RENDERBUFFER) {
|
||||
return ErrorInvalidEnumInfo("getInternalfomratParameter: target must be "
|
||||
"RENDERBUFFER. Was:", target);
|
||||
}
|
||||
|
||||
// GL_INVALID_ENUM is generated if internalformat is not color-,
|
||||
// depth-, or stencil-renderable.
|
||||
// TODO: When format table queries lands.
|
||||
|
||||
if (pname != LOCAL_GL_SAMPLES) {
|
||||
return ErrorInvalidEnumInfo("getInternalformatParameter: pname must be SAMPLES. "
|
||||
"Was:", pname);
|
||||
}
|
||||
|
||||
GLint* samples = nullptr;
|
||||
GLint sampleCount = 0;
|
||||
gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalformat,
|
||||
LOCAL_GL_NUM_SAMPLE_COUNTS, 1, &sampleCount);
|
||||
if (sampleCount > 0) {
|
||||
samples = new GLint[sampleCount];
|
||||
gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalformat, LOCAL_GL_SAMPLES,
|
||||
sampleCount, samples);
|
||||
}
|
||||
|
||||
JSObject* obj = dom::Int32Array::Create(cx, this, sampleCount, samples);
|
||||
if (!obj) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
delete[] samples;
|
||||
|
||||
retval.setObjectOrNull(obj);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::RenderbufferStorageMultisample(GLenum target, GLsizei samples,
|
||||
GLenum internalFormat,
|
||||
GLsizei width, GLsizei height)
|
||||
{
|
||||
RenderbufferStorage_base("renderbufferStorageMultisample", target, samples,
|
||||
internalFormat, width, height);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
@ -272,6 +272,8 @@ WebGLContext::WebGLContext()
|
||||
mGLMaxDrawBuffers = 1;
|
||||
mGLMaxTransformFeedbackSeparateAttribs = 0;
|
||||
mGLMaxUniformBufferBindings = 0;
|
||||
mGLMax3DTextureSize = 0;
|
||||
mGLMaxArrayTextureLayers = 0;
|
||||
|
||||
// See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13
|
||||
mPixelStorePackAlignment = 4;
|
||||
|
@ -1077,6 +1077,8 @@ protected:
|
||||
uint32_t mGLMaxTransformFeedbackSeparateAttribs;
|
||||
GLuint mGLMaxUniformBufferBindings;
|
||||
GLsizei mGLMaxSamples;
|
||||
GLuint mGLMax3DTextureSize;
|
||||
GLuint mGLMaxArrayTextureLayers;
|
||||
|
||||
public:
|
||||
GLuint MaxVertexAttribs() const {
|
||||
|
@ -121,8 +121,14 @@ UnmarkAttachment(WebGLFBAttachPoint& attachment)
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFBAttachPoint::SetTexImage(WebGLTexture* tex, TexImageTarget target,
|
||||
GLint level)
|
||||
WebGLFBAttachPoint::SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level)
|
||||
{
|
||||
SetTexImageLayer(tex, target, level, 0);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFBAttachPoint::SetTexImageLayer(WebGLTexture* tex, TexImageTarget target,
|
||||
GLint level, GLint layer)
|
||||
{
|
||||
mFB->InvalidateFramebufferStatus();
|
||||
|
||||
@ -132,6 +138,7 @@ WebGLFBAttachPoint::SetTexImage(WebGLTexture* tex, TexImageTarget target,
|
||||
mRenderbufferPtr = nullptr;
|
||||
mTexImageTarget = target;
|
||||
mTexImageLevel = level;
|
||||
mTexImageLayer = layer;
|
||||
|
||||
if (tex)
|
||||
tex->MarkAttachment(*this);
|
||||
@ -378,18 +385,44 @@ WebGLFBAttachPoint::FinalizeAttachment(gl::GLContext* gl,
|
||||
|
||||
const GLenum imageTarget = ImageTarget().get();
|
||||
const GLint mipLevel = MipLevel();
|
||||
const GLint layer = Layer();
|
||||
const GLuint glName = Texture()->mGLName;
|
||||
|
||||
if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
|
||||
imageTarget, glName, mipLevel);
|
||||
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
|
||||
imageTarget, glName, mipLevel);
|
||||
} else {
|
||||
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(),
|
||||
imageTarget, glName, mipLevel);
|
||||
switch (imageTarget) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
||||
if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
|
||||
imageTarget, glName, mipLevel);
|
||||
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
|
||||
imageTarget, glName, mipLevel);
|
||||
} else {
|
||||
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(),
|
||||
imageTarget, glName, mipLevel);
|
||||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TEXTURE_2D_ARRAY:
|
||||
case LOCAL_GL_TEXTURE_3D:
|
||||
if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_DEPTH_ATTACHMENT,
|
||||
glName, mipLevel, layer);
|
||||
gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_STENCIL_ATTACHMENT,
|
||||
glName, mipLevel, layer);
|
||||
} else {
|
||||
gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(),
|
||||
glName, mipLevel, layer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
return ;
|
||||
}
|
||||
|
||||
if (Renderbuffer()) {
|
||||
@ -487,6 +520,21 @@ WebGLFramebuffer::FramebufferTexture2D(FBAttachment attachPointEnum,
|
||||
InvalidateFramebufferStatus();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFramebuffer::FramebufferTextureLayer(FBAttachment attachment, WebGLTexture* tex,
|
||||
GLint level, GLint layer)
|
||||
{
|
||||
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
|
||||
mContext->mBoundReadFramebuffer == this);
|
||||
MOZ_ASSERT(tex);
|
||||
|
||||
WebGLFBAttachPoint& attachPoint = GetAttachPoint(attachment);
|
||||
TexImageTarget texImageTarget = tex->Target();
|
||||
attachPoint.SetTexImageLayer(tex, texImageTarget, level, layer);
|
||||
|
||||
InvalidateFramebufferStatus();
|
||||
}
|
||||
|
||||
WebGLFBAttachPoint&
|
||||
WebGLFramebuffer::GetAttachPoint(FBAttachment attachPoint)
|
||||
{
|
||||
|
@ -34,6 +34,7 @@ private:
|
||||
WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
|
||||
FBAttachment mAttachmentPoint;
|
||||
TexImageTarget mTexImageTarget;
|
||||
GLint mTexImageLayer;
|
||||
GLint mTexImageLevel;
|
||||
|
||||
public:
|
||||
@ -58,8 +59,10 @@ public:
|
||||
}
|
||||
|
||||
void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level);
|
||||
void SetTexImageLayer(WebGLTexture* tex, TexImageTarget target, GLint level,
|
||||
GLint layer);
|
||||
void SetRenderbuffer(WebGLRenderbuffer* rb);
|
||||
|
||||
|
||||
const WebGLTexture* Texture() const {
|
||||
return mTexturePtr;
|
||||
}
|
||||
@ -75,6 +78,9 @@ public:
|
||||
TexImageTarget ImageTarget() const {
|
||||
return mTexImageTarget;
|
||||
}
|
||||
GLint Layer() const {
|
||||
return mTexImageLayer;
|
||||
}
|
||||
GLint MipLevel() const {
|
||||
return mTexImageLevel;
|
||||
}
|
||||
@ -146,6 +152,9 @@ public:
|
||||
TexImageTarget texImageTarget, WebGLTexture* tex,
|
||||
GLint level);
|
||||
|
||||
void FramebufferTextureLayer(FBAttachment attachment, WebGLTexture* tex, GLint level,
|
||||
GLint layer);
|
||||
|
||||
bool HasDefinedAttachments() const;
|
||||
bool HasIncompleteAttachments() const;
|
||||
bool AllImageRectsMatch() const;
|
||||
|
@ -171,7 +171,7 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
||||
|
||||
// Uniforms
|
||||
|
||||
const bool needsCheckForArrays = true;
|
||||
const bool needsCheckForArrays = gl->WorkAroundDriverBugs();
|
||||
|
||||
GLuint numActiveUniforms = 0;
|
||||
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORMS,
|
||||
|
@ -60,6 +60,7 @@ UNIFIED_SOURCES += [
|
||||
'WebGL2ContextMRTs.cpp',
|
||||
'WebGL2ContextPrograms.cpp',
|
||||
'WebGL2ContextQueries.cpp',
|
||||
'WebGL2ContextRenderbuffers.cpp',
|
||||
'WebGL2ContextSamplers.cpp',
|
||||
'WebGL2ContextState.cpp',
|
||||
'WebGL2ContextSync.cpp',
|
||||
|
@ -134,10 +134,6 @@ const kEventConstructors = {
|
||||
return e;
|
||||
},
|
||||
},
|
||||
CSSFontFaceLoadEvent: { create: function (aName, aProps) {
|
||||
return new CSSFontFaceLoadEvent(aName, aProps);
|
||||
},
|
||||
},
|
||||
CustomEvent: { create: function (aName, aProps) {
|
||||
return new CustomEvent(aName, aProps);
|
||||
},
|
||||
@ -211,6 +207,10 @@ const kEventConstructors = {
|
||||
return new FocusEvent(aName, aProps);
|
||||
},
|
||||
},
|
||||
FontFaceSetLoadEvent: { create: function (aName, aProps) {
|
||||
return new FontFaceSetLoadEvent(aName, aProps);
|
||||
},
|
||||
},
|
||||
GamepadEvent: { create: function (aName, aProps) {
|
||||
return new GamepadEvent(aName, aProps);
|
||||
},
|
||||
|
@ -245,10 +245,10 @@ nsGeolocationSettings::HandleGeolocationPerOriginSettingsChange(const JS::Value&
|
||||
AutoEntryScript aes(global, "geolocation.app_settings enumeration");
|
||||
aes.TakeOwnershipOfErrorReporting();
|
||||
JSContext *cx = aes.cx();
|
||||
JS::AutoIdArray ids(cx, JS_Enumerate(cx, obj));
|
||||
JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
|
||||
|
||||
// if we get no ids then the exception list is empty and we can return here.
|
||||
if (!ids) {
|
||||
if (!JS_Enumerate(cx, obj, &ids)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2081,6 +2081,10 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
||||
SEND_SHUTDOWN_MESSAGE));
|
||||
}
|
||||
cpm->RemoveContentProcess(this->ChildID());
|
||||
|
||||
if (mDriverCrashGuard) {
|
||||
mDriverCrashGuard->NotifyCrashed();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -5178,6 +5182,42 @@ ContentParent::RecvGetGraphicsDeviceInitData(DeviceInitData* aOut)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvBeginDriverCrashGuard(const uint32_t& aGuardType, bool* aOutCrashed)
|
||||
{
|
||||
// Only one driver crash guard should be active at a time, per-process.
|
||||
MOZ_ASSERT(!mDriverCrashGuard);
|
||||
|
||||
UniquePtr<gfx::DriverCrashGuard> guard;
|
||||
switch (gfx::CrashGuardType(aGuardType)) {
|
||||
case gfx::CrashGuardType::D3D11Layers:
|
||||
guard = MakeUnique<gfx::D3D11LayersCrashGuard>(this);
|
||||
break;
|
||||
case gfx::CrashGuardType::D3D9Video:
|
||||
guard = MakeUnique<gfx::D3D9VideoCrashGuard>(this);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("unknown crash guard type");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (guard->Crashed()) {
|
||||
*aOutCrashed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
*aOutCrashed = false;
|
||||
mDriverCrashGuard = Move(guard);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvEndDriverCrashGuard(const uint32_t& aGuardType)
|
||||
{
|
||||
mDriverCrashGuard = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "nsIDOMGeoPositionCallback.h"
|
||||
#include "nsIDOMGeoPositionErrorCallback.h"
|
||||
#include "PermissionMessageUtils.h"
|
||||
#include "DriverCrashGuard.h"
|
||||
|
||||
#define CHILD_PROCESS_SHUTDOWN_MESSAGE NS_LITERAL_STRING("child-process-shutdown")
|
||||
|
||||
@ -814,6 +815,8 @@ private:
|
||||
virtual bool RecvGetGraphicsFeatureStatus(const int32_t& aFeature,
|
||||
int32_t* aStatus,
|
||||
bool* aSuccess) override;
|
||||
virtual bool RecvBeginDriverCrashGuard(const uint32_t& aGuardType, bool* aOutCrashed) override;
|
||||
virtual bool RecvEndDriverCrashGuard(const uint32_t& aGuardType) override;
|
||||
|
||||
virtual bool RecvAddIdleObserver(const uint64_t& observerId,
|
||||
const uint32_t& aIdleTimeInS) override;
|
||||
@ -954,6 +957,8 @@ private:
|
||||
nsRefPtr<mozilla::ProfileGatherer> mGatherer;
|
||||
#endif
|
||||
nsCString mProfile;
|
||||
|
||||
UniquePtr<gfx::DriverCrashGuard> mDriverCrashGuard;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -933,6 +933,10 @@ parent:
|
||||
|
||||
sync GetGraphicsFeatureStatus(int32_t aFeature) returns (int32_t aStatus, bool aSuccess);
|
||||
|
||||
// Driver crash guards. aGuardType must be a member of CrashGuardType.
|
||||
sync BeginDriverCrashGuard(uint32_t aGuardType) returns (bool crashDetected);
|
||||
sync EndDriverCrashGuard(uint32_t aGuardType);
|
||||
|
||||
AddIdleObserver(uint64_t observerId, uint32_t idleTimeInS);
|
||||
RemoveIdleObserver(uint64_t observerId, uint32_t idleTimeInS);
|
||||
|
||||
|
@ -155,8 +155,8 @@ ImportXULIntoContentWarning=Importing XUL nodes into a content document is depre
|
||||
XMLDocumentLoadPrincipalMismatch=Use of document.load forbidden on Documents that come from other Windows. Only the Window in which a Document was created is allowed to call .load on that Document. Preferably, use XMLHttpRequest instead.
|
||||
# LOCALIZATION NOTE: Do not translate "IndexedDB".
|
||||
IndexedDBTransactionAbortNavigation=An IndexedDB transaction that was not yet complete has been aborted due to page navigation.
|
||||
# LOCALIZATION NOTE: Do not translate Will-change, %1$S,%2$S,%3$S are numbers.
|
||||
WillChangeOverBudgetIgnoredWarning=Will-change memory consumption is too high. Surface area covers %1$S px, budget is the document surface area multiplied by %2$S (%3$S px). Occurences of will-change over the budget will be ignored.
|
||||
# LOCALIZATION NOTE: Do not translate Will-change, %1$S,%2$S are numbers.
|
||||
IgnoringWillChangeOverBudgetWarning=Will-change memory consumption is too high. Budget limit is the document surface area multiplied by %1$S (%2$S px). Occurrences of will-change over the budget will be ignored.
|
||||
# LOCALIZATION NOTE: Do not translate "ServiceWorker".
|
||||
HittingMaxWorkersPerDomain=A ServiceWorker could not be started immediately because other documents in the same origin are already using the maximum number of workers. The ServiceWorker is now queued and will be started after some of the other workers have completed.
|
||||
# LOCALIZATION NOTE: Do no translate "setVelocity", "PannerNode", "AudioListener", "speedOfSound" and "dopplerFactor"
|
||||
|
@ -1690,11 +1690,11 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
|
||||
}
|
||||
|
||||
if (vc.mAdvanced.WasPassed() && videoType != dom::MediaSourceEnum::Camera) {
|
||||
// iterate through advanced, forcing mediaSource to match "root"
|
||||
const char *camera = EnumToASCII(dom::MediaSourceEnumValues::strings,
|
||||
dom::MediaSourceEnum::Camera);
|
||||
// iterate through advanced, forcing all unset mediaSources to match "root"
|
||||
const char *unset = EnumToASCII(dom::MediaSourceEnumValues::strings,
|
||||
dom::MediaSourceEnum::Camera);
|
||||
for (MediaTrackConstraintSet& cs : vc.mAdvanced.Value()) {
|
||||
if (cs.mMediaSource.EqualsASCII(camera)) {
|
||||
if (cs.mMediaSource.EqualsASCII(unset)) {
|
||||
cs.mMediaSource = vc.mMediaSource;
|
||||
}
|
||||
}
|
||||
@ -1729,15 +1729,46 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
|
||||
audioType = StringToEnum(dom::MediaSourceEnumValues::strings,
|
||||
ac.mMediaSource,
|
||||
audioType);
|
||||
// Only enable AudioCapture if the pref is enabled. If it's not, we can deny
|
||||
// right away.
|
||||
if (audioType == dom::MediaSourceEnum::AudioCapture &&
|
||||
!Preferences::GetBool("media.getusermedia.audiocapture.enabled")) {
|
||||
nsRefPtr<MediaStreamError> error =
|
||||
new MediaStreamError(aWindow,
|
||||
NS_LITERAL_STRING("PermissionDeniedError"));
|
||||
onFailure->OnError(error);
|
||||
return NS_OK;
|
||||
// Work around WebIDL default since spec uses same dictionary w/audio & video.
|
||||
if (audioType == dom::MediaSourceEnum::Camera) {
|
||||
audioType = dom::MediaSourceEnum::Microphone;
|
||||
ac.mMediaSource.AssignASCII(EnumToASCII(dom::MediaSourceEnumValues::strings,
|
||||
audioType));
|
||||
}
|
||||
|
||||
switch (audioType) {
|
||||
case dom::MediaSourceEnum::Microphone:
|
||||
break;
|
||||
|
||||
case dom::MediaSourceEnum::AudioCapture:
|
||||
// Only enable AudioCapture if the pref is enabled. If it's not, we can
|
||||
// deny right away.
|
||||
if (!Preferences::GetBool("media.getusermedia.audiocapture.enabled")) {
|
||||
nsRefPtr<MediaStreamError> error =
|
||||
new MediaStreamError(aWindow,
|
||||
NS_LITERAL_STRING("PermissionDeniedError"));
|
||||
onFailure->OnError(error);
|
||||
return NS_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case dom::MediaSourceEnum::Other:
|
||||
default: {
|
||||
nsRefPtr<MediaStreamError> error =
|
||||
new MediaStreamError(aWindow, NS_LITERAL_STRING("NotFoundError"));
|
||||
onFailure->OnError(error);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
if (ac.mAdvanced.WasPassed()) {
|
||||
// iterate through advanced, forcing all unset mediaSources to match "root"
|
||||
const char *unset = EnumToASCII(dom::MediaSourceEnumValues::strings,
|
||||
dom::MediaSourceEnum::Camera);
|
||||
for (MediaTrackConstraintSet& cs : ac.mAdvanced.Value()) {
|
||||
if (cs.mMediaSource.EqualsASCII(unset)) {
|
||||
cs.mMediaSource = ac.mMediaSource;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
StreamListeners* listeners = AddWindowID(windowID);
|
||||
|
@ -13,6 +13,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "PeerConnectionIdp",
|
||||
"resource://gre/modules/media/PeerConnectionIdp.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "convertToRTCStatsReport",
|
||||
"resource://gre/modules/media/RTCStatsReport.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
const PC_CONTRACT = "@mozilla.org/dom/peerconnection;1";
|
||||
const PC_OBS_CONTRACT = "@mozilla.org/dom/peerconnectionobserver;1";
|
||||
@ -23,6 +25,7 @@ const PC_STATS_CONTRACT = "@mozilla.org/dom/rtcstatsreport;1";
|
||||
const PC_STATIC_CONTRACT = "@mozilla.org/dom/peerconnectionstatic;1";
|
||||
const PC_SENDER_CONTRACT = "@mozilla.org/dom/rtpsender;1";
|
||||
const PC_RECEIVER_CONTRACT = "@mozilla.org/dom/rtpreceiver;1";
|
||||
const PC_COREQUEST_CONTRACT = "@mozilla.org/dom/createofferrequest;1";
|
||||
|
||||
const PC_CID = Components.ID("{bdc2e533-b308-4708-ac8e-a8bfade6d851}");
|
||||
const PC_OBS_CID = Components.ID("{d1748d4c-7f6a-4dc5-add6-d55b7678537e}");
|
||||
@ -33,6 +36,7 @@ const PC_STATS_CID = Components.ID("{7fe6e18b-0da3-4056-bf3b-440ef3809e06}");
|
||||
const PC_STATIC_CID = Components.ID("{0fb47c47-a205-4583-a9fc-cbadf8c95880}");
|
||||
const PC_SENDER_CID = Components.ID("{4fff5d46-d827-4cd4-a970-8fd53977440e}");
|
||||
const PC_RECEIVER_CID = Components.ID("{d974b814-8fde-411c-8c45-b86791b81030}");
|
||||
const PC_COREQUEST_CID = Components.ID("{74b2122d-65a8-4824-aa9e-3d664cb75dc2}");
|
||||
|
||||
// Global list of PeerConnection objects, so they can be cleaned up when
|
||||
// a page is torn down. (Maps inner window ID to an array of PC objects).
|
||||
@ -40,11 +44,14 @@ function GlobalPCList() {
|
||||
this._list = {};
|
||||
this._networkdown = false; // XXX Need to query current state somehow
|
||||
this._lifecycleobservers = {};
|
||||
this._nextId = 1;
|
||||
Services.obs.addObserver(this, "inner-window-destroyed", true);
|
||||
Services.obs.addObserver(this, "profile-change-net-teardown", true);
|
||||
Services.obs.addObserver(this, "network:offline-about-to-go-offline", true);
|
||||
Services.obs.addObserver(this, "network:offline-status-changed", true);
|
||||
Services.obs.addObserver(this, "gmp-plugin-crash", true);
|
||||
Services.obs.addObserver(this, "PeerConnection:response:allow", true);
|
||||
Services.obs.addObserver(this, "PeerConnection:response:deny", true);
|
||||
if (Cc["@mozilla.org/childprocessmessagemanager;1"]) {
|
||||
let mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
|
||||
mm.addMessageListener("gmp-plugin-crash", this);
|
||||
@ -78,9 +85,23 @@ GlobalPCList.prototype = {
|
||||
} else {
|
||||
this._list[winID] = [Cu.getWeakReference(pc)];
|
||||
}
|
||||
pc._globalPCListId = this._nextId++;
|
||||
this.removeNullRefs(winID);
|
||||
},
|
||||
|
||||
findPC: function(globalPCListId) {
|
||||
for (let winId in this._list) {
|
||||
if (this._list.hasOwnProperty(winId)) {
|
||||
for (let pcref of this._list[winId]) {
|
||||
let pc = pcref.get();
|
||||
if (pc && pc._globalPCListId == globalPCListId) {
|
||||
return pc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
removeNullRefs: function(winID) {
|
||||
if (this._list[winID] === undefined) {
|
||||
return;
|
||||
@ -187,6 +208,18 @@ GlobalPCList.prototype = {
|
||||
let data = { pluginID, pluginName };
|
||||
this.handleGMPCrash(data);
|
||||
}
|
||||
} else if (topic == "PeerConnection:response:allow" ||
|
||||
topic == "PeerConnection:response:deny") {
|
||||
var pc = this.findPC(data);
|
||||
if (pc) {
|
||||
if (topic == "PeerConnection:response:allow") {
|
||||
pc._settlePermission.allow();
|
||||
} else {
|
||||
let err = new pc._win.DOMException("The operation is insecure.",
|
||||
"SecurityError");
|
||||
pc._settlePermission.deny(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -355,6 +388,7 @@ RTCPeerConnection.prototype = {
|
||||
}
|
||||
// Save the appId
|
||||
this._appId = Cu.getWebIDLCallerPrincipal().appId;
|
||||
this._https = this._win.document.documentURIObject.schemeIs("https");
|
||||
|
||||
// Get the offline status for this appId
|
||||
let appOffline = false;
|
||||
@ -690,13 +724,12 @@ RTCPeerConnection.prototype = {
|
||||
|
||||
let origin = Cu.getWebIDLCallerPrincipal().origin;
|
||||
return this._chain(() => {
|
||||
let p = this._certificateReady.then(
|
||||
() => new this._win.Promise((resolve, reject) => {
|
||||
let p = Promise.all([this.getPermission(), this._certificateReady])
|
||||
.then(() => new this._win.Promise((resolve, reject) => {
|
||||
this._onCreateOfferSuccess = resolve;
|
||||
this._onCreateOfferFailure = reject;
|
||||
this._impl.createOffer(options);
|
||||
})
|
||||
);
|
||||
}));
|
||||
p = this._addIdentityAssertion(p, origin);
|
||||
return p.then(
|
||||
sdp => new this._win.mozRTCSessionDescription({ type: "offer", sdp: sdp }));
|
||||
@ -715,8 +748,8 @@ RTCPeerConnection.prototype = {
|
||||
return this._legacyCatch(onSuccess, onError, () => {
|
||||
let origin = Cu.getWebIDLCallerPrincipal().origin;
|
||||
return this._chain(() => {
|
||||
let p = this._certificateReady.then(
|
||||
() => new this._win.Promise((resolve, reject) => {
|
||||
let p = Promise.all([this.getPermission(), this._certificateReady])
|
||||
.then(() => new this._win.Promise((resolve, reject) => {
|
||||
// We give up line-numbers in errors by doing this here, but do all
|
||||
// state-checks inside the chain, to support the legacy feature that
|
||||
// callers don't have to wait for setRemoteDescription to finish.
|
||||
@ -731,8 +764,7 @@ RTCPeerConnection.prototype = {
|
||||
this._onCreateAnswerSuccess = resolve;
|
||||
this._onCreateAnswerFailure = reject;
|
||||
this._impl.createAnswer();
|
||||
})
|
||||
);
|
||||
}));
|
||||
p = this._addIdentityAssertion(p, origin);
|
||||
return p.then(sdp => {
|
||||
return new this._win.mozRTCSessionDescription({ type: "answer", sdp: sdp });
|
||||
@ -741,6 +773,26 @@ RTCPeerConnection.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
getPermission: function() {
|
||||
if (this._havePermission) {
|
||||
return this._havePermission;
|
||||
}
|
||||
if (AppConstants.MOZ_B2G ||
|
||||
Services.prefs.getBoolPref("media.navigator.permission.disabled")) {
|
||||
return this._havePermission = Promise.resolve();
|
||||
}
|
||||
return this._havePermission = new Promise((resolve, reject) => {
|
||||
this._settlePermission = { allow: resolve, deny: reject };
|
||||
let outerId = this._win.QueryInterface(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
|
||||
|
||||
let chrome = new CreateOfferRequest(outerId, this._winID,
|
||||
this._globalPCListId, false);
|
||||
let request = this._win.CreateOfferRequest._create(this._win, chrome);
|
||||
Services.obs.notifyObservers(request, "PeerConnection:request", null);
|
||||
});
|
||||
},
|
||||
|
||||
setLocalDescription: function(desc, onSuccess, onError) {
|
||||
return this._legacyCatch(onSuccess, onError, () => {
|
||||
this._localType = desc.type;
|
||||
@ -771,11 +823,12 @@ RTCPeerConnection.prototype = {
|
||||
"InvalidParameterError");
|
||||
}
|
||||
|
||||
return this._chain(() => new this._win.Promise((resolve, reject) => {
|
||||
return this._chain(() => this.getPermission()
|
||||
.then(() => new this._win.Promise((resolve, reject) => {
|
||||
this._onSetLocalDescriptionSuccess = resolve;
|
||||
this._onSetLocalDescriptionFailure = reject;
|
||||
this._impl.setLocalDescription(type, desc.sdp);
|
||||
}));
|
||||
})));
|
||||
});
|
||||
},
|
||||
|
||||
@ -858,11 +911,12 @@ RTCPeerConnection.prototype = {
|
||||
let origin = Cu.getWebIDLCallerPrincipal().origin;
|
||||
|
||||
return this._chain(() => {
|
||||
let setRem = new this._win.Promise((resolve, reject) => {
|
||||
this._onSetRemoteDescriptionSuccess = resolve;
|
||||
this._onSetRemoteDescriptionFailure = reject;
|
||||
this._impl.setRemoteDescription(type, desc.sdp);
|
||||
});
|
||||
let setRem = this.getPermission()
|
||||
.then(() => new this._win.Promise((resolve, reject) => {
|
||||
this._onSetRemoteDescriptionSuccess = resolve;
|
||||
this._onSetRemoteDescriptionFailure = reject;
|
||||
this._impl.setRemoteDescription(type, desc.sdp);
|
||||
}));
|
||||
|
||||
if (desc.type === "rollback") {
|
||||
return setRem;
|
||||
@ -1436,6 +1490,19 @@ RTCRtpReceiver.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
|
||||
};
|
||||
|
||||
function CreateOfferRequest(windowID, innerWindowID, callID, isSecure) {
|
||||
this.windowID = windowID;
|
||||
this.innerWindowID = innerWindowID;
|
||||
this.callID = callID;
|
||||
this.isSecure = isSecure;
|
||||
}
|
||||
CreateOfferRequest.prototype = {
|
||||
classDescription: "CreateOfferRequest",
|
||||
classID: PC_COREQUEST_CID,
|
||||
contractID: PC_COREQUEST_CONTRACT,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
|
||||
[GlobalPCList,
|
||||
RTCIceCandidate,
|
||||
@ -1445,5 +1512,6 @@ this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
|
||||
RTCRtpReceiver,
|
||||
RTCRtpSender,
|
||||
RTCStatsReport,
|
||||
PeerConnectionObserver]
|
||||
PeerConnectionObserver,
|
||||
CreateOfferRequest]
|
||||
);
|
||||
|
@ -7,6 +7,7 @@ component {7fe6e18b-0da3-4056-bf3b-440ef3809e06} PeerConnection.js
|
||||
component {0fb47c47-a205-4583-a9fc-cbadf8c95880} PeerConnection.js
|
||||
component {4fff5d46-d827-4cd4-a970-8fd53977440e} PeerConnection.js
|
||||
component {d974b814-8fde-411c-8c45-b86791b81030} PeerConnection.js
|
||||
component {74b2122d-65a8-4824-aa9e-3d664cb75dc2} PeerConnection.js
|
||||
|
||||
contract @mozilla.org/dom/peerconnection;1 {bdc2e533-b308-4708-ac8e-a8bfade6d851}
|
||||
contract @mozilla.org/dom/peerconnectionobserver;1 {d1748d4c-7f6a-4dc5-add6-d55b7678537e}
|
||||
@ -17,3 +18,4 @@ contract @mozilla.org/dom/rtcstatsreport;1 {7fe6e18b-0da3-4056-bf3b-440ef3809e06
|
||||
contract @mozilla.org/dom/peerconnectionstatic;1 {0fb47c47-a205-4583-a9fc-cbadf8c95880}
|
||||
contract @mozilla.org/dom/rtpsender;1 {4fff5d46-d827-4cd4-a970-8fd53977440e}
|
||||
contract @mozilla.org/dom/rtpreceiver;1 {d974b814-8fde-411c-8c45-b86791b81030}
|
||||
contract @mozilla.org/dom/createofferrequest;1 {74b2122d-65a8-4824-aa9e-3d664cb75dc2}
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mfapi.h"
|
||||
#include "MFTDecoder.h"
|
||||
#include "DriverCrashGuard.h"
|
||||
|
||||
const CLSID CLSID_VideoProcessorMFT =
|
||||
{
|
||||
@ -90,6 +91,12 @@ D3D9DXVA2Manager::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
gfx::D3D9VideoCrashGuard crashGuard;
|
||||
if (crashGuard.Crashed()) {
|
||||
NS_WARNING("DXVA2D3D9 crash detected");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Create D3D9Ex.
|
||||
HMODULE d3d9lib = LoadLibraryW(L"d3d9.dll");
|
||||
NS_ENSURE_TRUE(d3d9lib, E_FAIL);
|
||||
|
@ -2088,11 +2088,13 @@ class CloseNotificationRunnable final
|
||||
: public WorkerMainThreadRunnable
|
||||
{
|
||||
Notification* mNotification;
|
||||
bool mHadObserver;
|
||||
|
||||
public:
|
||||
explicit CloseNotificationRunnable(Notification* aNotification)
|
||||
: WorkerMainThreadRunnable(aNotification->mWorkerPrivate)
|
||||
, mNotification(aNotification)
|
||||
, mHadObserver(false)
|
||||
{}
|
||||
|
||||
bool
|
||||
@ -2102,26 +2104,54 @@ class CloseNotificationRunnable final
|
||||
// The Notify() take's responsibility of releasing the Notification.
|
||||
mNotification->mObserver->ForgetNotification();
|
||||
mNotification->mObserver = nullptr;
|
||||
mHadObserver = true;
|
||||
}
|
||||
mNotification->CloseInternal();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HadObserver()
|
||||
{
|
||||
return mHadObserver;
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
NotificationFeature::Notify(JSContext* aCx, Status aStatus)
|
||||
{
|
||||
MOZ_ASSERT(aStatus >= Canceling);
|
||||
if (aStatus >= Canceling) {
|
||||
// CloseNotificationRunnable blocks the worker by pushing a sync event loop
|
||||
// on the stack. Meanwhile, WorkerControlRunnables dispatched to the worker
|
||||
// can still continue running. One of these is
|
||||
// ReleaseNotificationControlRunnable that releases the notification,
|
||||
// invalidating the notification and this feature. We hold this reference to
|
||||
// keep the notification valid until we are done with it.
|
||||
//
|
||||
// An example of when the control runnable could get dispatched to the
|
||||
// worker is if a Notification is created and the worker is immediately
|
||||
// closed, but there is no permission to show it so that the main thread
|
||||
// immediately drops the NotificationRef. In this case, this function blocks
|
||||
// on the main thread, but the main thread dispatches the control runnable,
|
||||
// invalidating mNotification.
|
||||
nsRefPtr<Notification> kungFuDeathGrip = mNotification;
|
||||
|
||||
// Dispatched to main thread, blocks on closing the Notification.
|
||||
nsRefPtr<CloseNotificationRunnable> r =
|
||||
new CloseNotificationRunnable(mNotification);
|
||||
r->Dispatch(aCx);
|
||||
// Dispatched to main thread, blocks on closing the Notification.
|
||||
nsRefPtr<CloseNotificationRunnable> r =
|
||||
new CloseNotificationRunnable(mNotification);
|
||||
r->Dispatch(aCx);
|
||||
|
||||
mNotification->ReleaseObject();
|
||||
// From this point we cannot touch properties of this feature because
|
||||
// ReleaseObject() may have led to the notification going away and the
|
||||
// notification owns this feature!
|
||||
// Only call ReleaseObject() to match the observer's NotificationRef
|
||||
// ownership (since CloseNotificationRunnable asked the observer to drop the
|
||||
// reference to the notification).
|
||||
if (r->HadObserver()) {
|
||||
mNotification->ReleaseObject();
|
||||
}
|
||||
|
||||
// From this point we cannot touch properties of this feature because
|
||||
// ReleaseObject() may have led to the notification going away and the
|
||||
// notification owns this feature!
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2132,8 +2162,13 @@ Notification::RegisterFeature()
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(!mFeature);
|
||||
mFeature = MakeUnique<NotificationFeature>(this);
|
||||
return mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(),
|
||||
mFeature.get());
|
||||
bool added = mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(),
|
||||
mFeature.get());
|
||||
if (!added) {
|
||||
mFeature = nullptr;
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
void
|
||||
@ -2305,14 +2340,14 @@ Notification::CreateAndShow(nsIGlobalObject* aGlobal,
|
||||
// Make a structured clone of the aOptions.mData object
|
||||
JS::Rooted<JS::Value> data(cx, aOptions.mData);
|
||||
notification->InitFromJSVal(cx, data, aRv);
|
||||
if (aRv.Failed()) {
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
notification->SetScope(aScope);
|
||||
|
||||
auto ref = MakeUnique<NotificationRef>(notification);
|
||||
if (!ref->Initialized()) {
|
||||
if (NS_WARN_IF(!ref->Initialized())) {
|
||||
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1032,8 +1032,8 @@ nsJSObjWrapper::NP_Enumerate(NPObject *npobj, NPIdentifier **idarray,
|
||||
JS::Rooted<JSObject*> jsobj(cx, npjsobj->mJSObj);
|
||||
JSAutoCompartment ac(cx, jsobj);
|
||||
|
||||
JS::AutoIdArray ida(cx, JS_Enumerate(cx, jsobj));
|
||||
if (!ida) {
|
||||
JS::Rooted<JS::IdVector> ida(cx, JS::IdVector(cx));
|
||||
if (!JS_Enumerate(cx, jsobj, &ida)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -47,33 +47,33 @@ Atomic<uintptr_t> gIDGenerator(0);
|
||||
using namespace workers;
|
||||
|
||||
// This class processes the promise's callbacks with promise's result.
|
||||
class PromiseCallbackTask final : public nsRunnable
|
||||
class PromiseReactionJob final : public nsRunnable
|
||||
{
|
||||
public:
|
||||
PromiseCallbackTask(Promise* aPromise,
|
||||
PromiseCallback* aCallback,
|
||||
const JS::Value& aValue)
|
||||
PromiseReactionJob(Promise* aPromise,
|
||||
PromiseCallback* aCallback,
|
||||
const JS::Value& aValue)
|
||||
: mPromise(aPromise)
|
||||
, mCallback(aCallback)
|
||||
, mValue(CycleCollectedJSRuntime::Get()->Runtime(), aValue)
|
||||
{
|
||||
MOZ_ASSERT(aPromise);
|
||||
MOZ_ASSERT(aCallback);
|
||||
MOZ_COUNT_CTOR(PromiseCallbackTask);
|
||||
MOZ_COUNT_CTOR(PromiseReactionJob);
|
||||
}
|
||||
|
||||
virtual
|
||||
~PromiseCallbackTask()
|
||||
~PromiseReactionJob()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(PromiseCallbackTask);
|
||||
MOZ_COUNT_DTOR(PromiseCallbackTask);
|
||||
NS_ASSERT_OWNINGTHREAD(PromiseReactionJob);
|
||||
MOZ_COUNT_DTOR(PromiseReactionJob);
|
||||
}
|
||||
|
||||
protected:
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(PromiseCallbackTask);
|
||||
NS_ASSERT_OWNINGTHREAD(PromiseReactionJob);
|
||||
ThreadsafeAutoJSContext cx;
|
||||
JS::Rooted<JSObject*> wrapper(cx, mPromise->GetWrapper());
|
||||
MOZ_ASSERT(wrapper); // It was preserved!
|
||||
@ -174,32 +174,32 @@ GetPromise(JSContext* aCx, JS::Handle<JSObject*> aFunc)
|
||||
|
||||
// Runnable to resolve thenables.
|
||||
// Equivalent to the specification's ResolvePromiseViaThenableTask.
|
||||
class ThenableResolverTask final : public nsRunnable
|
||||
class PromiseResolveThenableJob final : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ThenableResolverTask(Promise* aPromise,
|
||||
JS::Handle<JSObject*> aThenable,
|
||||
PromiseInit* aThen)
|
||||
PromiseResolveThenableJob(Promise* aPromise,
|
||||
JS::Handle<JSObject*> aThenable,
|
||||
PromiseInit* aThen)
|
||||
: mPromise(aPromise)
|
||||
, mThenable(CycleCollectedJSRuntime::Get()->Runtime(), aThenable)
|
||||
, mThen(aThen)
|
||||
{
|
||||
MOZ_ASSERT(aPromise);
|
||||
MOZ_COUNT_CTOR(ThenableResolverTask);
|
||||
MOZ_COUNT_CTOR(PromiseResolveThenableJob);
|
||||
}
|
||||
|
||||
virtual
|
||||
~ThenableResolverTask()
|
||||
~PromiseResolveThenableJob()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(ThenableResolverTask);
|
||||
MOZ_COUNT_DTOR(ThenableResolverTask);
|
||||
NS_ASSERT_OWNINGTHREAD(PromiseResolveThenableJob);
|
||||
MOZ_COUNT_DTOR(PromiseResolveThenableJob);
|
||||
}
|
||||
|
||||
protected:
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(ThenableResolverTask);
|
||||
NS_ASSERT_OWNINGTHREAD(PromiseResolveThenableJob);
|
||||
ThreadsafeAutoJSContext cx;
|
||||
JS::Rooted<JSObject*> wrapper(cx, mPromise->GetWrapper());
|
||||
MOZ_ASSERT(wrapper); // It was preserved!
|
||||
@ -275,16 +275,16 @@ private:
|
||||
NS_DECL_OWNINGTHREAD;
|
||||
};
|
||||
|
||||
// Fast version of ThenableResolverTask for use in the cases when we know we're
|
||||
// Fast version of PromiseResolveThenableJob for use in the cases when we know we're
|
||||
// calling the canonical Promise.prototype.then on an actual DOM Promise. In
|
||||
// that case we can just bypass the jumping into and out of JS and call
|
||||
// AppendCallbacks on that promise directly.
|
||||
class FastThenableResolverTask final : public nsRunnable
|
||||
class FastPromiseResolveThenableJob final : public nsRunnable
|
||||
{
|
||||
public:
|
||||
FastThenableResolverTask(PromiseCallback* aResolveCallback,
|
||||
PromiseCallback* aRejectCallback,
|
||||
Promise* aNextPromise)
|
||||
FastPromiseResolveThenableJob(PromiseCallback* aResolveCallback,
|
||||
PromiseCallback* aRejectCallback,
|
||||
Promise* aNextPromise)
|
||||
: mResolveCallback(aResolveCallback)
|
||||
, mRejectCallback(aRejectCallback)
|
||||
, mNextPromise(aNextPromise)
|
||||
@ -292,21 +292,21 @@ public:
|
||||
MOZ_ASSERT(aResolveCallback);
|
||||
MOZ_ASSERT(aRejectCallback);
|
||||
MOZ_ASSERT(aNextPromise);
|
||||
MOZ_COUNT_CTOR(FastThenableResolverTask);
|
||||
MOZ_COUNT_CTOR(FastPromiseResolveThenableJob);
|
||||
}
|
||||
|
||||
virtual
|
||||
~FastThenableResolverTask()
|
||||
~FastPromiseResolveThenableJob()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(FastThenableResolverTask);
|
||||
MOZ_COUNT_DTOR(FastThenableResolverTask);
|
||||
NS_ASSERT_OWNINGTHREAD(FastPromiseResolveThenableJob);
|
||||
MOZ_COUNT_DTOR(FastPromiseResolveThenableJob);
|
||||
}
|
||||
|
||||
protected:
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(FastThenableResolverTask);
|
||||
NS_ASSERT_OWNINGTHREAD(FastPromiseResolveThenableJob);
|
||||
mNextPromise->AppendCallbacks(mResolveCallback, mRejectCallback);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -822,7 +822,7 @@ Promise::Catch(JSContext* aCx, AnyCallback* aRejectCallback, ErrorResult& aRv)
|
||||
/**
|
||||
* The CountdownHolder class encapsulates Promise.all countdown functions and
|
||||
* the countdown holder parts of the Promises spec. It maintains the result
|
||||
* array and AllResolveHandlers use SetValue() to set the array indices.
|
||||
* array and AllResolveElementFunctions use SetValue() to set the array indices.
|
||||
*/
|
||||
class CountdownHolder final : public nsISupports
|
||||
{
|
||||
@ -910,17 +910,18 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CountdownHolder)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
/**
|
||||
* An AllResolveHandler is the per-promise part of the Promise.all() algorithm.
|
||||
* An AllResolveElementFunction is the per-promise
|
||||
* part of the Promise.all() algorithm.
|
||||
* Every Promise in the handler is handed an instance of this as a resolution
|
||||
* handler and it sets the relevant index in the CountdownHolder.
|
||||
*/
|
||||
class AllResolveHandler final : public PromiseNativeHandler
|
||||
class AllResolveElementFunction final : public PromiseNativeHandler
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(AllResolveHandler)
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(AllResolveElementFunction)
|
||||
|
||||
AllResolveHandler(CountdownHolder* aHolder, uint32_t aIndex)
|
||||
AllResolveElementFunction(CountdownHolder* aHolder, uint32_t aIndex)
|
||||
: mCountdownHolder(aHolder), mIndex(aIndex)
|
||||
{
|
||||
MOZ_ASSERT(aHolder);
|
||||
@ -936,11 +937,11 @@ public:
|
||||
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||
{
|
||||
// Should never be attached to Promise as a reject handler.
|
||||
MOZ_ASSERT(false, "AllResolveHandler should never be attached to a Promise's reject handler!");
|
||||
MOZ_CRASH("AllResolveElementFunction should never be attached to a Promise's reject handler!");
|
||||
}
|
||||
|
||||
private:
|
||||
~AllResolveHandler()
|
||||
~AllResolveElementFunction()
|
||||
{
|
||||
}
|
||||
|
||||
@ -948,14 +949,14 @@ private:
|
||||
uint32_t mIndex;
|
||||
};
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(AllResolveHandler)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(AllResolveHandler)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(AllResolveElementFunction)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(AllResolveElementFunction)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AllResolveHandler)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AllResolveElementFunction)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(AllResolveHandler, mCountdownHolder)
|
||||
NS_IMPL_CYCLE_COLLECTION(AllResolveElementFunction, mCountdownHolder)
|
||||
|
||||
/* static */ already_AddRefed<Promise>
|
||||
Promise::All(const GlobalObject& aGlobal,
|
||||
@ -1019,7 +1020,7 @@ Promise::All(const GlobalObject& aGlobal,
|
||||
|
||||
for (uint32_t i = 0; i < aPromiseList.Length(); ++i) {
|
||||
nsRefPtr<PromiseNativeHandler> resolveHandler =
|
||||
new AllResolveHandler(holder, i);
|
||||
new AllResolveElementFunction(holder, i);
|
||||
|
||||
nsRefPtr<PromiseCallback> resolveCb =
|
||||
new NativePromiseCallback(resolveHandler, Resolved);
|
||||
@ -1132,7 +1133,7 @@ Promise::AppendCallbacks(PromiseCallback* aResolveCallback,
|
||||
// callbacks with promise's result. If promise's state is rejected, queue a
|
||||
// task to process our reject callbacks with promise's result.
|
||||
if (mState != Pending) {
|
||||
EnqueueCallbackTasks();
|
||||
TriggerPromiseReactions();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1299,8 +1300,8 @@ Promise::ResolveInternal(JSContext* aCx,
|
||||
Promise* nextPromise;
|
||||
if (PromiseBinding::IsThenMethod(thenObj) &&
|
||||
NS_SUCCEEDED(UNWRAP_OBJECT(Promise, valueObj, nextPromise))) {
|
||||
// If we were taking the codepath that involves ThenableResolverTask and
|
||||
// PromiseInit below, then eventually, in ThenableResolverTask::Run, we
|
||||
// If we were taking the codepath that involves PromiseResolveThenableJob and
|
||||
// PromiseInit below, then eventually, in PromiseResolveThenableJob::Run, we
|
||||
// would create some JSFunctions in the compartment of
|
||||
// this->GetWrapper() and pass them to the PromiseInit. So by the time
|
||||
// we'd see the resolution value it would be wrapped into the
|
||||
@ -1310,16 +1311,16 @@ Promise::ResolveInternal(JSContext* aCx,
|
||||
JS::Rooted<JSObject*> glob(aCx, GlobalJSObject());
|
||||
nsRefPtr<PromiseCallback> resolveCb = new ResolvePromiseCallback(this, glob);
|
||||
nsRefPtr<PromiseCallback> rejectCb = new RejectPromiseCallback(this, glob);
|
||||
nsRefPtr<FastThenableResolverTask> task =
|
||||
new FastThenableResolverTask(resolveCb, rejectCb, nextPromise);
|
||||
nsRefPtr<FastPromiseResolveThenableJob> task =
|
||||
new FastPromiseResolveThenableJob(resolveCb, rejectCb, nextPromise);
|
||||
DispatchToMicroTask(task);
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<PromiseInit> thenCallback =
|
||||
new PromiseInit(nullptr, thenObj, mozilla::dom::GetIncumbentGlobal());
|
||||
nsRefPtr<ThenableResolverTask> task =
|
||||
new ThenableResolverTask(this, valueObj, thenCallback);
|
||||
nsRefPtr<PromiseResolveThenableJob> task =
|
||||
new PromiseResolveThenableJob(this, valueObj, thenCallback);
|
||||
DispatchToMicroTask(task);
|
||||
return;
|
||||
}
|
||||
@ -1387,7 +1388,7 @@ Promise::Settle(JS::Handle<JS::Value> aValue, PromiseState aState)
|
||||
}
|
||||
#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
|
||||
|
||||
EnqueueCallbackTasks();
|
||||
TriggerPromiseReactions();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1405,7 +1406,7 @@ Promise::MaybeSettle(JS::Handle<JS::Value> aValue,
|
||||
}
|
||||
|
||||
void
|
||||
Promise::EnqueueCallbackTasks()
|
||||
Promise::TriggerPromiseReactions()
|
||||
{
|
||||
nsTArray<nsRefPtr<PromiseCallback>> callbacks;
|
||||
callbacks.SwapElements(mState == Resolved ? mResolveCallbacks
|
||||
@ -1414,8 +1415,8 @@ Promise::EnqueueCallbackTasks()
|
||||
mRejectCallbacks.Clear();
|
||||
|
||||
for (uint32_t i = 0; i < callbacks.Length(); ++i) {
|
||||
nsRefPtr<PromiseCallbackTask> task =
|
||||
new PromiseCallbackTask(this, callbacks[i], mResult);
|
||||
nsRefPtr<PromiseReactionJob> task =
|
||||
new PromiseReactionJob(this, callbacks[i], mResult);
|
||||
DispatchToMicroTask(task);
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ class Promise : public nsISupports,
|
||||
public SupportsWeakPtr<Promise>
|
||||
{
|
||||
friend class NativePromiseCallback;
|
||||
friend class PromiseCallbackTask;
|
||||
friend class PromiseReactionJob;
|
||||
friend class PromiseResolverTask;
|
||||
friend class PromiseTask;
|
||||
#if defined(DOM_PROMISE_DEPRECATED_REPORTING)
|
||||
@ -85,8 +85,8 @@ class Promise : public nsISupports,
|
||||
friend class PromiseWorkerProxyRunnable;
|
||||
friend class RejectPromiseCallback;
|
||||
friend class ResolvePromiseCallback;
|
||||
friend class ThenableResolverTask;
|
||||
friend class FastThenableResolverTask;
|
||||
friend class PromiseResolveThenableJob;
|
||||
friend class FastPromiseResolveThenableJob;
|
||||
friend class WrapperPromiseCallback;
|
||||
|
||||
public:
|
||||
@ -274,8 +274,8 @@ private:
|
||||
// This method enqueues promise's resolve/reject callbacks with promise's
|
||||
// result. It's executed when the resolver.resolve() or resolver.reject() is
|
||||
// called or when the promise already has a result and new callbacks are
|
||||
// appended by then(), catch() or done().
|
||||
void EnqueueCallbackTasks();
|
||||
// appended by then() or catch().
|
||||
void TriggerPromiseReactions();
|
||||
|
||||
void Settle(JS::Handle<JS::Value> aValue, Promise::PromiseState aState);
|
||||
void MaybeSettle(JS::Handle<JS::Value> aValue, Promise::PromiseState aState);
|
||||
|
@ -5,7 +5,7 @@
|
||||
"use strict";
|
||||
|
||||
// Don't modify this, instead set dom.push.debug.
|
||||
let gDebuggingEnabled = true;
|
||||
let gDebuggingEnabled = false;
|
||||
|
||||
function debug(s) {
|
||||
if (gDebuggingEnabled)
|
||||
|
@ -5,7 +5,7 @@
|
||||
"use strict";
|
||||
|
||||
// Don't modify this, instead set dom.push.debug.
|
||||
let gDebuggingEnabled = true;
|
||||
let gDebuggingEnabled = false;
|
||||
|
||||
function debug(s) {
|
||||
if (gDebuggingEnabled)
|
||||
@ -20,6 +20,8 @@ const Cr = Components.results;
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
gDebuggingEnabled = Services.prefs.getBoolPref("dom.push.debug");
|
||||
|
||||
const kMessages = [
|
||||
"PushService:Register:OK",
|
||||
"PushService:Register:KO",
|
||||
|
@ -116,6 +116,8 @@ DoContentSecurityChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo)
|
||||
nsContentPolicyType contentPolicyType = aLoadInfo->GetContentPolicyType();
|
||||
nsCString mimeTypeGuess;
|
||||
nsCOMPtr<nsINode> requestingContext = nullptr;
|
||||
nsContentPolicyType internalContentPolicyType =
|
||||
aLoadInfo->InternalContentPolicyType();
|
||||
|
||||
switch(contentPolicyType) {
|
||||
case nsIContentPolicy::TYPE_OTHER: {
|
||||
@ -128,8 +130,20 @@ DoContentSecurityChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo)
|
||||
case nsIContentPolicy::TYPE_IMAGE:
|
||||
case nsIContentPolicy::TYPE_STYLESHEET:
|
||||
case nsIContentPolicy::TYPE_OBJECT:
|
||||
case nsIContentPolicy::TYPE_DOCUMENT:
|
||||
case nsIContentPolicy::TYPE_SUBDOCUMENT:
|
||||
case nsIContentPolicy::TYPE_DOCUMENT: {
|
||||
MOZ_ASSERT(false, "contentPolicyType not supported yet");
|
||||
break;
|
||||
}
|
||||
|
||||
case nsIContentPolicy::TYPE_SUBDOCUMENT: {
|
||||
mimeTypeGuess = NS_LITERAL_CSTRING("text/html");
|
||||
requestingContext = aLoadInfo->LoadingNode();
|
||||
MOZ_ASSERT(!requestingContext ||
|
||||
requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
|
||||
"type_subdocument requires requestingContext of type Document");
|
||||
break;
|
||||
}
|
||||
|
||||
case nsIContentPolicy::TYPE_REFRESH:
|
||||
case nsIContentPolicy::TYPE_XBL:
|
||||
case nsIContentPolicy::TYPE_PING: {
|
||||
@ -139,12 +153,24 @@ DoContentSecurityChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo)
|
||||
|
||||
case nsIContentPolicy::TYPE_XMLHTTPREQUEST: {
|
||||
// alias nsIContentPolicy::TYPE_DATAREQUEST:
|
||||
mimeTypeGuess = NS_LITERAL_CSTRING(TEXT_EVENT_STREAM);
|
||||
requestingContext = aLoadInfo->LoadingNode();
|
||||
MOZ_ASSERT(!requestingContext ||
|
||||
requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
|
||||
"type_xml requires requestingContext of type Document");
|
||||
|
||||
if (internalContentPolicyType ==
|
||||
nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST) {
|
||||
mimeTypeGuess = NS_LITERAL_CSTRING("application/xml");
|
||||
}
|
||||
else {
|
||||
MOZ_ASSERT(internalContentPolicyType ==
|
||||
nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE,
|
||||
"can not set mime type guess for unexpected internal type");
|
||||
mimeTypeGuess = NS_LITERAL_CSTRING(TEXT_EVENT_STREAM);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case nsIContentPolicy::TYPE_OBJECT_SUBREQUEST: {
|
||||
mimeTypeGuess = EmptyCString();
|
||||
requestingContext = aLoadInfo->LoadingNode();
|
||||
@ -161,9 +187,6 @@ DoContentSecurityChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo)
|
||||
}
|
||||
|
||||
case nsIContentPolicy::TYPE_MEDIA: {
|
||||
nsContentPolicyType internalContentPolicyType =
|
||||
aLoadInfo->InternalContentPolicyType();
|
||||
|
||||
if (internalContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_TRACK) {
|
||||
mimeTypeGuess = NS_LITERAL_CSTRING("text/vtt");
|
||||
}
|
||||
|
@ -311,8 +311,6 @@ var interfaceNamesInGlobalScope =
|
||||
"CSSConditionRule",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"CSSCounterStyleRule",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"CSSFontFaceLoadEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"CSSFontFaceRule",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
@ -471,6 +469,8 @@ var interfaceNamesInGlobalScope =
|
||||
"FontFace",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"FontFaceSet",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"FontFaceSetLoadEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"GainNode",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
16
dom/webidl/CreateOfferRequest.webidl
Normal file
16
dom/webidl/CreateOfferRequest.webidl
Normal file
@ -0,0 +1,16 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* This is an internal IDL file
|
||||
*/
|
||||
|
||||
[ChromeOnly,
|
||||
JSImplementation="@mozilla.org/dom/createofferrequest;1"]
|
||||
interface CreateOfferRequest {
|
||||
readonly attribute unsigned long long windowID;
|
||||
readonly attribute unsigned long long innerWindowID;
|
||||
readonly attribute DOMString callID;
|
||||
readonly attribute boolean isSecure;
|
||||
};
|
@ -10,12 +10,12 @@
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
dictionary CSSFontFaceLoadEventInit : EventInit {
|
||||
dictionary FontFaceSetLoadEventInit : EventInit {
|
||||
sequence<FontFace> fontfaces = [];
|
||||
};
|
||||
|
||||
[Constructor(DOMString type, optional CSSFontFaceLoadEventInit eventInitDict),
|
||||
[Constructor(DOMString type, optional FontFaceSetLoadEventInit eventInitDict),
|
||||
Pref="layout.css.font-loading-api.enabled"]
|
||||
interface CSSFontFaceLoadEvent : Event {
|
||||
interface FontFaceSetLoadEvent : Event {
|
||||
[Cached, Constant] readonly attribute sequence<FontFace> fontfaces;
|
||||
};
|
@ -20,8 +20,6 @@ callback AnyCallback = any (any value);
|
||||
Exposed=(Window,Worker,System)]
|
||||
// Need to escape "Promise" so it's treated as an identifier.
|
||||
interface _Promise {
|
||||
// TODO bug 875289 - static Promise fulfill(any value);
|
||||
|
||||
// Disable the static methods when the interface object is supposed to be
|
||||
// disabled, just in case some code decides to walk over to .constructor from
|
||||
// the proto of a promise object or someone screws up and manages to create a
|
||||
|
@ -323,8 +323,7 @@ interface WebGL2RenderingContext : WebGLRenderingContext
|
||||
/* Framebuffer objects */
|
||||
void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
|
||||
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
void framebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
|
||||
any getInternalformatParameter(GLenum target, GLenum internalformat, GLenum pname);
|
||||
void framebufferTextureLayer(GLenum target, GLenum attachment, WebGLTexture? texture, GLint level, GLint layer);
|
||||
|
||||
[Throws]
|
||||
void invalidateFramebuffer(GLenum target, sequence<GLenum> attachments);
|
||||
@ -336,6 +335,8 @@ interface WebGL2RenderingContext : WebGLRenderingContext
|
||||
void readBuffer(GLenum src);
|
||||
|
||||
/* Renderbuffer objects */
|
||||
[Throws]
|
||||
any getInternalformatParameter(GLenum target, GLenum internalformat, GLenum pname);
|
||||
void renderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
|
||||
|
||||
/* Texture objects */
|
||||
|
@ -88,6 +88,7 @@ WEBIDL_FILES = [
|
||||
'ContainerBoxObject.webidl',
|
||||
'ConvolverNode.webidl',
|
||||
'Coordinates.webidl',
|
||||
'CreateOfferRequest.webidl',
|
||||
'Crypto.webidl',
|
||||
'CSPDictionaries.webidl',
|
||||
'CSPReport.webidl',
|
||||
@ -750,7 +751,6 @@ GENERATED_EVENTS_WEBIDL_FILES = [
|
||||
'CaretStateChangedEvent.webidl',
|
||||
'CFStateChangeEvent.webidl',
|
||||
'CloseEvent.webidl',
|
||||
'CSSFontFaceLoadEvent.webidl',
|
||||
'DataErrorEvent.webidl',
|
||||
'DataStoreChangeEvent.webidl',
|
||||
'DeviceLightEvent.webidl',
|
||||
@ -762,6 +762,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
|
||||
'DownloadEvent.webidl',
|
||||
'ErrorEvent.webidl',
|
||||
'ExternalAppEvent.webidl',
|
||||
'FontFaceSetLoadEvent.webidl',
|
||||
'HashChangeEvent.webidl',
|
||||
'IccChangeEvent.webidl',
|
||||
'ImageCaptureErrorEvent.webidl',
|
||||
|
@ -97,12 +97,20 @@ onfetch = function(ev) {
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes("nonexistent_image.gif")) {
|
||||
var imageAsBinaryString = atob("R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs");
|
||||
var imageLength = imageAsBinaryString.length;
|
||||
|
||||
// If we just pass |imageAsBinaryString| to the Response constructor, an
|
||||
// encoding conversion occurs that corrupts the image. Instead, we need to
|
||||
// convert it to a typed array.
|
||||
// typed array.
|
||||
var imageAsArray = new Uint8Array(imageLength);
|
||||
for (var i = 0; i < imageLength; ++i) {
|
||||
imageAsArray[i] = imageAsBinaryString.charCodeAt(i);
|
||||
}
|
||||
|
||||
ev.respondWith(Promise.resolve(
|
||||
new Response(atob("R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs"), {
|
||||
headers: {
|
||||
"Content-Type": "image/gif"
|
||||
}
|
||||
})
|
||||
new Response(imageAsArray, { headers: { "Content-Type": "image/gif" } })
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -332,41 +332,7 @@ XMLDocument::Load(const nsAString& aUrl, ErrorResult& aRv)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to see whether the current document is allowed to load this URI.
|
||||
// It's important to use the current document's principal for this check so
|
||||
// that we don't end up in a case where code with elevated privileges is
|
||||
// calling us and changing the principal of this document.
|
||||
|
||||
// Enforce same-origin even for chrome loaders to avoid someone accidentally
|
||||
// using a document that content has a reference to and turn that into a
|
||||
// chrome document.
|
||||
if (!nsContentUtils::IsSystemPrincipal(principal)) {
|
||||
rv = principal->CheckMayLoad(uri, false, false);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return false;
|
||||
}
|
||||
|
||||
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
|
||||
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST,
|
||||
uri,
|
||||
principal,
|
||||
callingDoc ? callingDoc.get() :
|
||||
static_cast<nsIDocument*>(this),
|
||||
NS_LITERAL_CSTRING("application/xml"),
|
||||
nullptr,
|
||||
&shouldLoad,
|
||||
nsContentUtils::GetContentPolicy(),
|
||||
nsContentUtils::GetSecurityManager());
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return false;
|
||||
}
|
||||
if (NS_CP_REJECTED(shouldLoad)) {
|
||||
aRv.Throw(NS_ERROR_CONTENT_BLOCKED);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (nsContentUtils::IsSystemPrincipal(principal)) {
|
||||
// We're called from chrome, check to make sure the URI we're
|
||||
// about to load is also chrome.
|
||||
|
||||
@ -444,7 +410,7 @@ XMLDocument::Load(const nsAString& aUrl, ErrorResult& aRv)
|
||||
uri,
|
||||
callingDoc ? callingDoc.get() :
|
||||
static_cast<nsIDocument*>(this),
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
|
||||
nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST,
|
||||
loadGroup,
|
||||
req,
|
||||
@ -478,7 +444,7 @@ XMLDocument::Load(const nsAString& aUrl, ErrorResult& aRv)
|
||||
// mChannelIsPending.
|
||||
|
||||
// Start an asynchronous read of the XML document
|
||||
rv = channel->AsyncOpen(listener, nullptr);
|
||||
rv = channel->AsyncOpen2(listener);
|
||||
if (NS_FAILED(rv)) {
|
||||
mChannelIsPending = false;
|
||||
aRv.Throw(rv);
|
||||
|
@ -204,7 +204,7 @@ public:
|
||||
int64_t aModificationTime) = 0;
|
||||
};
|
||||
|
||||
class UpgradeHostToOriginDBMigration final : public UpgradeHostToOriginHelper {
|
||||
class MOZ_STACK_CLASS UpgradeHostToOriginDBMigration final : public UpgradeHostToOriginHelper {
|
||||
public:
|
||||
UpgradeHostToOriginDBMigration(mozIStorageConnection* aDBConn, int64_t* aID) : mDBConn(aDBConn)
|
||||
, mID(aID)
|
||||
@ -256,7 +256,7 @@ private:
|
||||
int64_t* mID;
|
||||
};
|
||||
|
||||
class UpgradeHostToOriginHostfileImport final : public UpgradeHostToOriginHelper {
|
||||
class MOZ_STACK_CLASS UpgradeHostToOriginHostfileImport final : public UpgradeHostToOriginHelper {
|
||||
public:
|
||||
UpgradeHostToOriginHostfileImport(nsPermissionManager* aPm,
|
||||
nsPermissionManager::DBOperationType aOperation,
|
||||
@ -285,6 +285,93 @@ private:
|
||||
int64_t mID;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS UpgradeIPHostToOriginDB final : public UpgradeHostToOriginHelper {
|
||||
public:
|
||||
UpgradeIPHostToOriginDB(mozIStorageConnection* aDBConn, int64_t* aID) : mDBConn(aDBConn)
|
||||
, mID(aID)
|
||||
{
|
||||
mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"INSERT INTO moz_perms"
|
||||
"(id, origin, type, permission, expireType, expireTime, modificationTime) "
|
||||
"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"), getter_AddRefs(mStmt));
|
||||
|
||||
mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT id FROM moz_perms WHERE origin = ?1 AND type = ?2"),
|
||||
getter_AddRefs(mLookupStmt));
|
||||
}
|
||||
|
||||
nsresult
|
||||
Insert(const nsACString& aOrigin, const nsAFlatCString& aType,
|
||||
uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime,
|
||||
int64_t aModificationTime) final
|
||||
{
|
||||
// Every time the migration code wants to insert an origin into
|
||||
// the database we need to check to see if someone has already
|
||||
// created a permissions entry for that permission. If they have,
|
||||
// we don't want to insert a duplicate row.
|
||||
//
|
||||
// We can afford to do this lookup unconditionally and not perform
|
||||
// caching, as a origin type pair should only be attempted to be
|
||||
// inserted once.
|
||||
|
||||
nsresult rv = mLookupStmt->Reset();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mLookupStmt->BindUTF8StringByIndex(0, aOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mLookupStmt->BindUTF8StringByIndex(1, aType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Check if we already have the row in the database, if we do, then
|
||||
// we don't want to be inserting it again.
|
||||
bool moreStmts = false;
|
||||
if (NS_FAILED(mLookupStmt->ExecuteStep(&moreStmts)) || moreStmts) {
|
||||
mLookupStmt->Reset();
|
||||
NS_WARNING("A permissions entry was going to be re-migrated, "
|
||||
"but was already found in the permissions database.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Actually insert the statement into the database.
|
||||
rv = mStmt->BindInt64ByIndex(0, *mID);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mStmt->BindUTF8StringByIndex(1, aOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mStmt->BindUTF8StringByIndex(2, aType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mStmt->BindInt32ByIndex(3, aPermission);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mStmt->BindInt32ByIndex(4, aExpireType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mStmt->BindInt64ByIndex(5, aExpireTime);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mStmt->BindInt64ByIndex(6, aModificationTime);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Increment the working identifier, as we are about to use this one
|
||||
(*mID)++;
|
||||
|
||||
rv = mStmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<mozIStorageStatement> mStmt;
|
||||
nsCOMPtr<mozIStorageStatement> mLookupStmt;
|
||||
nsCOMPtr<mozIStorageConnection> mDBConn;
|
||||
int64_t* mID;
|
||||
};
|
||||
|
||||
|
||||
nsresult
|
||||
UpgradeHostToOriginAndInsert(const nsACString& aHost, const nsAFlatCString& aType,
|
||||
uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime,
|
||||
@ -344,10 +431,12 @@ UpgradeHostToOriginAndInsert(const nsACString& aHost, const nsAFlatCString& aTyp
|
||||
MOZ_ASSERT(tldService); // We should always have a tldService
|
||||
if (tldService) {
|
||||
rv = tldService->GetBaseDomainFromHost(aHost, 0, eTLD1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
// We should never hit this branch, but we produce a fake eTLD1
|
||||
// to avoid crashing in a release build in case we hit this branch
|
||||
}
|
||||
|
||||
if (!tldService || NS_FAILED(rv)) {
|
||||
// If the lookup on the tldService for the base domain for the host failed,
|
||||
// that means that we just want to directly use the host as the host name
|
||||
// for the lookup.
|
||||
eTLD1 = aHost;
|
||||
}
|
||||
|
||||
@ -446,32 +535,45 @@ UpgradeHostToOriginAndInsert(const nsACString& aHost, const nsAFlatCString& aTyp
|
||||
// This has a relatively high liklihood of applying the permission to the correct
|
||||
// origin.
|
||||
if (!foundHistory) {
|
||||
rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + aHost);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsAutoCString hostSegment;
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsAutoCString origin;
|
||||
|
||||
nsAutoCString origin;
|
||||
rv = principal->GetOrigin(origin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aHelper->Insert(origin, aType, aPermission,
|
||||
aExpireType, aExpireTime, aModificationTime);
|
||||
// If this is an ipv6 URI, we need to surround it in '[', ']' before trying to
|
||||
// parse it as a URI.
|
||||
if (aHost.FindChar(':') != -1) {
|
||||
hostSegment.Assign("[");
|
||||
hostSegment.Append(aHost);
|
||||
hostSegment.Append("]");
|
||||
} else {
|
||||
hostSegment.Assign(aHost);
|
||||
}
|
||||
rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("https://") + aHost);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString origin;
|
||||
rv = principal->GetOrigin(origin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// http:// URI default
|
||||
rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + hostSegment);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aHelper->Insert(origin, aType, aPermission,
|
||||
aExpireType, aExpireTime, aModificationTime);
|
||||
}
|
||||
rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = principal->GetOrigin(origin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aHelper->Insert(origin, aType, aPermission,
|
||||
aExpireType, aExpireTime, aModificationTime);
|
||||
|
||||
// https:// URI default
|
||||
rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("https://") + hostSegment);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = principal->GetOrigin(origin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aHelper->Insert(origin, aType, aPermission,
|
||||
aExpireType, aExpireTime, aModificationTime);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -614,7 +716,7 @@ nsPermissionManager::AppClearDataObserverInit()
|
||||
// nsPermissionManager Implementation
|
||||
|
||||
#define PERMISSIONS_FILE_NAME "permissions.sqlite"
|
||||
#define HOSTS_SCHEMA_VERSION 7
|
||||
#define HOSTS_SCHEMA_VERSION 8
|
||||
|
||||
#define HOSTPERM_FILE_NAME "hostperm.1"
|
||||
|
||||
@ -1059,8 +1161,8 @@ nsPermissionManager::InitDB(bool aRemoveFile)
|
||||
// and then back up their old database as moz_perms_v6
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> countStmt;
|
||||
mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT COUNT(*) FROM moz_perms"),
|
||||
getter_AddRefs(countStmt));
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT COUNT(*) FROM moz_perms"),
|
||||
getter_AddRefs(countStmt));
|
||||
bool hasResult = false;
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
NS_SUCCEEDED(countStmt->ExecuteStep(&hasResult)) &&
|
||||
@ -1139,6 +1241,107 @@ nsPermissionManager::InitDB(bool aRemoveFile)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// fall through to the next upgrade
|
||||
|
||||
// The version 7-8 migration is the re-migration of localhost and ip-address
|
||||
// entries due to errors in the previous version 7 migration which caused
|
||||
// localhost and ip-address entries to be incorrectly discarded.
|
||||
// The version 7 migration logic has been corrected, and thus this logic only
|
||||
// needs to execute if the user is currently on version 7.
|
||||
case 7:
|
||||
{
|
||||
// This migration will be relatively expensive as we need to perform
|
||||
// database lookups for each origin which we want to insert. Fortunately,
|
||||
// it shouldn't be too expensive as we only want to insert a small number
|
||||
// of entries created for localhost or IP addresses.
|
||||
|
||||
// We only want to perform the re-migration if moz_hosts is a backup
|
||||
bool hostsIsBackupExists = false;
|
||||
mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts_is_backup"),
|
||||
&hostsIsBackupExists);
|
||||
|
||||
// Only perform this migration if the original schema version was 7, and
|
||||
// the moz_hosts table is a backup.
|
||||
if (dbSchemaVersion == 7 && hostsIsBackupExists) {
|
||||
nsCOMPtr<nsIEffectiveTLDService> tldService =
|
||||
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
||||
MOZ_ASSERT(tldService); // We should always have a tldService
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT host, type, permission, expireType, expireTime, "
|
||||
"modificationTime, appId, isInBrowserElement FROM moz_hosts"),
|
||||
getter_AddRefs(stmt));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> idStmt;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT MAX(id) FROM moz_hosts"), getter_AddRefs(idStmt));
|
||||
int64_t id = 0;
|
||||
bool hasResult = false;
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
NS_SUCCEEDED(idStmt->ExecuteStep(&hasResult)) &&
|
||||
hasResult) {
|
||||
id = idStmt->AsInt32(0) + 1;
|
||||
}
|
||||
|
||||
nsAutoCString host, type;
|
||||
uint32_t permission;
|
||||
uint32_t expireType;
|
||||
int64_t expireTime;
|
||||
int64_t modificationTime;
|
||||
uint32_t appId;
|
||||
bool isInBrowserElement;
|
||||
|
||||
while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
|
||||
// Read in the old row
|
||||
rv = stmt->GetUTF8String(0, host);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoCString eTLD1;
|
||||
rv = tldService->GetBaseDomainFromHost(host, 0, eTLD1);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// We only care about entries which the tldService can't handle
|
||||
continue;
|
||||
}
|
||||
|
||||
rv = stmt->GetUTF8String(1, type);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
permission = stmt->AsInt32(2);
|
||||
expireType = stmt->AsInt32(3);
|
||||
expireTime = stmt->AsInt64(4);
|
||||
modificationTime = stmt->AsInt64(5);
|
||||
if (NS_WARN_IF(stmt->AsInt64(6) < 0)) {
|
||||
continue;
|
||||
}
|
||||
appId = static_cast<uint32_t>(stmt->AsInt64(6));
|
||||
isInBrowserElement = static_cast<bool>(stmt->AsInt32(7));
|
||||
|
||||
// Perform the meat of the migration by deferring to the
|
||||
// UpgradeHostToOriginAndInsert function.
|
||||
UpgradeIPHostToOriginDB upHelper(mDBConn, &id);
|
||||
rv = UpgradeHostToOriginAndInsert(host, type, permission,
|
||||
expireType, expireTime,
|
||||
modificationTime, appId,
|
||||
isInBrowserElement,
|
||||
&upHelper);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Unexpected failure when upgrading migrating permission "
|
||||
"from host to origin");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Even if we didn't perform the migration, we want to bump the schema
|
||||
// version to 8.
|
||||
rv = mDBConn->SetSchemaVersion(8);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// current version.
|
||||
case HOSTS_SCHEMA_VERSION:
|
||||
break;
|
||||
|
@ -121,7 +121,7 @@ function run_test() {
|
||||
|
||||
// The schema should be upgraded to 6, and a 'modificationTime' column should
|
||||
// exist with all records having a value of 0.
|
||||
do_check_eq(connection.schemaVersion, 7);
|
||||
do_check_eq(connection.schemaVersion, 8);
|
||||
|
||||
let select = connection.createStatement("SELECT modificationTime FROM moz_perms")
|
||||
let numMigrated = 0;
|
||||
|
@ -85,6 +85,9 @@ add_task(function test() {
|
||||
insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false),
|
||||
insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false),
|
||||
insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true),
|
||||
insertHost("localhost", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", "A", 1, 0, 0, 0, 0, false),
|
||||
@ -139,6 +142,14 @@ add_task(function test() {
|
||||
// following entries
|
||||
["ftp://sub.foo.com:8000", "B", 1, 0, 0],
|
||||
["ftp://subber.sub.foo.com:8000", "B", 1, 0, 0],
|
||||
|
||||
// Make sure that we also support localhost, and IP addresses
|
||||
["http://localhost", "A", 1, 0, 0],
|
||||
["https://localhost", "A", 1, 0, 0],
|
||||
["http://127.0.0.1", "A", 1, 0, 0],
|
||||
["https://127.0.0.1", "A", 1, 0, 0],
|
||||
["http://192.0.2.235", "A", 1, 0, 0],
|
||||
["https://192.0.2.235", "A", 1, 0, 0],
|
||||
];
|
||||
|
||||
let found = expected.map((it) => 0);
|
||||
|
@ -122,6 +122,9 @@ add_task(function test() {
|
||||
insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false),
|
||||
insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false),
|
||||
insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true),
|
||||
insertHost("localhost", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("263.123.555.676", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", "A", 1, 0, 0, 0, 0, false),
|
||||
@ -160,6 +163,14 @@ add_task(function test() {
|
||||
["https://bar.ca^appId=1000&inBrowser=1", "A", 1, 0, 0],
|
||||
["file:///some/path/to/file.html", "A", 1, 0, 0],
|
||||
["file:///another/file.html", "A", 1, 0, 0],
|
||||
|
||||
// Make sure that we also support localhost, and IP addresses
|
||||
["http://localhost", "A", 1, 0, 0],
|
||||
["https://localhost", "A", 1, 0, 0],
|
||||
["http://127.0.0.1", "A", 1, 0, 0],
|
||||
["https://127.0.0.1", "A", 1, 0, 0],
|
||||
["http://263.123.555.676", "A", 1, 0, 0],
|
||||
["https://263.123.555.676", "A", 1, 0, 0],
|
||||
];
|
||||
|
||||
let found = expected.map((it) => 0);
|
||||
|
@ -139,6 +139,9 @@ add_task(function test() {
|
||||
insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false),
|
||||
insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false),
|
||||
insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true),
|
||||
insertHost("localhost", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", "A", 1, 0, 0, 0, 0, false),
|
||||
@ -193,6 +196,14 @@ add_task(function test() {
|
||||
// following entries
|
||||
["ftp://sub.foo.com:8000", "B", 1, 0, 0],
|
||||
["ftp://subber.sub.foo.com:8000", "B", 1, 0, 0],
|
||||
|
||||
// Make sure that we also support localhost, and IP addresses
|
||||
["http://localhost", "A", 1, 0, 0],
|
||||
["https://localhost", "A", 1, 0, 0],
|
||||
["http://127.0.0.1", "A", 1, 0, 0],
|
||||
["https://127.0.0.1", "A", 1, 0, 0],
|
||||
["http://192.0.2.235", "A", 1, 0, 0],
|
||||
["https://192.0.2.235", "A", 1, 0, 0],
|
||||
];
|
||||
|
||||
let found = expected.map((it) => 0);
|
||||
|
@ -75,6 +75,9 @@ add_task(function test() {
|
||||
insertOrigin("https://foo.com", "A", 2, 0, 0, 0),
|
||||
insertOrigin("http://foo.com", "A", 2, 0, 0, 0),
|
||||
insertOrigin("http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0),
|
||||
|
||||
insertOrigin("http://127.0.0.1", "B", 2, 0, 0, 0),
|
||||
insertOrigin("http://localhost", "B", 2, 0, 0, 0),
|
||||
];
|
||||
|
||||
let created4 = []; // Didn't create any v4 entries, so the DB should be empty
|
||||
@ -88,7 +91,10 @@ add_task(function test() {
|
||||
let expected = [
|
||||
["https://foo.com", "A", 2, 0, 0, 0],
|
||||
["http://foo.com", "A", 2, 0, 0, 0],
|
||||
["http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0]
|
||||
["http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0],
|
||||
|
||||
["http://127.0.0.1", "B", 2, 0, 0, 0],
|
||||
["http://localhost", "B", 2, 0, 0, 0],
|
||||
];
|
||||
|
||||
let found = expected.map((it) => 0);
|
||||
|
@ -139,6 +139,9 @@ add_task(function test() {
|
||||
insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false),
|
||||
insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false),
|
||||
insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true),
|
||||
insertHost("localhost", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", "A", 1, 0, 0, 0, 0, false),
|
||||
@ -193,6 +196,14 @@ add_task(function test() {
|
||||
// following entries
|
||||
["ftp://sub.foo.com:8000", "B", 1, 0, 0],
|
||||
["ftp://subber.sub.foo.com:8000", "B", 1, 0, 0],
|
||||
|
||||
// Make sure that we also support localhost, and IP addresses
|
||||
["http://localhost", "A", 1, 0, 0],
|
||||
["https://localhost", "A", 1, 0, 0],
|
||||
["http://127.0.0.1", "A", 1, 0, 0],
|
||||
["https://127.0.0.1", "A", 1, 0, 0],
|
||||
["http://192.0.2.235", "A", 1, 0, 0],
|
||||
["https://192.0.2.235", "A", 1, 0, 0],
|
||||
];
|
||||
|
||||
let found = expected.map((it) => 0);
|
||||
|
266
extensions/cookie/test/unit/test_permmanager_migrate_7-8.js
Normal file
266
extensions/cookie/test/unit/test_permmanager_migrate_7-8.js
Normal file
@ -0,0 +1,266 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
|
||||
"resource://testing-common/PlacesTestUtils.jsm");
|
||||
|
||||
let PERMISSIONS_FILE_NAME = "permissions.sqlite";
|
||||
|
||||
function GetPermissionsFile(profile)
|
||||
{
|
||||
let file = profile.clone();
|
||||
file.append(PERMISSIONS_FILE_NAME);
|
||||
return file;
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function test() {
|
||||
/* Create and set up the permissions database */
|
||||
let profile = do_get_profile();
|
||||
|
||||
let db = Services.storage.openDatabase(GetPermissionsFile(profile));
|
||||
db.schemaVersion = 7;
|
||||
|
||||
/*
|
||||
* V5 table
|
||||
*/
|
||||
db.executeSimpleSQL(
|
||||
"CREATE TABLE moz_perms (" +
|
||||
" id INTEGER PRIMARY KEY" +
|
||||
",origin TEXT" +
|
||||
",type TEXT" +
|
||||
",permission INTEGER" +
|
||||
",expireType INTEGER" +
|
||||
",expireTime INTEGER" +
|
||||
",modificationTime INTEGER" +
|
||||
")");
|
||||
|
||||
let stmt6Insert = db.createStatement(
|
||||
"INSERT INTO moz_perms (" +
|
||||
"id, origin, type, permission, expireType, expireTime, modificationTime" +
|
||||
") VALUES (" +
|
||||
":id, :origin, :type, :permission, :expireType, :expireTime, :modificationTime" +
|
||||
")");
|
||||
|
||||
/*
|
||||
* V4 table
|
||||
*/
|
||||
db.executeSimpleSQL(
|
||||
"CREATE TABLE moz_hosts (" +
|
||||
" id INTEGER PRIMARY KEY" +
|
||||
",host TEXT" +
|
||||
",type TEXT" +
|
||||
",permission INTEGER" +
|
||||
",expireType INTEGER" +
|
||||
",expireTime INTEGER" +
|
||||
",modificationTime INTEGER" +
|
||||
",appId INTEGER" +
|
||||
",isInBrowserElement INTEGER" +
|
||||
")");
|
||||
|
||||
let stmtInsert = db.createStatement(
|
||||
"INSERT INTO moz_hosts (" +
|
||||
"id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement" +
|
||||
") VALUES (" +
|
||||
":id, :host, :type, :permission, :expireType, :expireTime, :modificationTime, :appId, :isInBrowserElement" +
|
||||
")");
|
||||
|
||||
/*
|
||||
* The v4 table is a backup
|
||||
*/
|
||||
db.executeSimpleSQL("CREATE TABLE moz_hosts_is_backup (dummy INTEGER PRIMARY KEY)");
|
||||
|
||||
let id = 0;
|
||||
|
||||
function insertOrigin(origin, type, permission, expireType, expireTime, modificationTime) {
|
||||
let thisId = id++;
|
||||
|
||||
stmt6Insert.bindByName("id", thisId);
|
||||
stmt6Insert.bindByName("origin", origin);
|
||||
stmt6Insert.bindByName("type", type);
|
||||
stmt6Insert.bindByName("permission", permission);
|
||||
stmt6Insert.bindByName("expireType", expireType);
|
||||
stmt6Insert.bindByName("expireTime", expireTime);
|
||||
stmt6Insert.bindByName("modificationTime", modificationTime);
|
||||
|
||||
stmt6Insert.execute();
|
||||
|
||||
return {
|
||||
id: thisId,
|
||||
origin: origin,
|
||||
type: type,
|
||||
permission: permission,
|
||||
expireType: expireType,
|
||||
expireTime: expireTime,
|
||||
modificationTime: modificationTime
|
||||
};
|
||||
}
|
||||
|
||||
function insertHost(host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement) {
|
||||
let thisId = id++;
|
||||
|
||||
stmtInsert.bindByName("id", thisId);
|
||||
stmtInsert.bindByName("host", host);
|
||||
stmtInsert.bindByName("type", type);
|
||||
stmtInsert.bindByName("permission", permission);
|
||||
stmtInsert.bindByName("expireType", expireType);
|
||||
stmtInsert.bindByName("expireTime", expireTime);
|
||||
stmtInsert.bindByName("modificationTime", modificationTime);
|
||||
stmtInsert.bindByName("appId", appId);
|
||||
stmtInsert.bindByName("isInBrowserElement", isInBrowserElement);
|
||||
|
||||
stmtInsert.execute();
|
||||
|
||||
return {
|
||||
id: thisId,
|
||||
host: host,
|
||||
type: type,
|
||||
permission: permission,
|
||||
expireType: expireType,
|
||||
expireTime: expireTime,
|
||||
modificationTime: modificationTime,
|
||||
appId: appId,
|
||||
isInBrowserElement: isInBrowserElement
|
||||
};
|
||||
}
|
||||
|
||||
let created7 = [
|
||||
insertOrigin("https://foo.com", "A", 2, 0, 0, 0),
|
||||
insertOrigin("http://foo.com", "A", 2, 0, 0, 0),
|
||||
insertOrigin("http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0),
|
||||
insertOrigin("https://192.0.2.235", "A", 2, 0, 0),
|
||||
];
|
||||
|
||||
// Add some rows to the database
|
||||
let created = [
|
||||
insertHost("foo.com", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("foo.com", "C", 1, 0, 0, 0, 0, false),
|
||||
insertHost("foo.com", "A", 1, 0, 0, 0, 1000, false),
|
||||
insertHost("foo.com", "A", 1, 0, 0, 0, 2000, true),
|
||||
insertHost("sub.foo.com", "B", 1, 0, 0, 0, 0, false),
|
||||
insertHost("subber.sub.foo.com", "B", 1, 0, 0, 0, 0, false),
|
||||
insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false),
|
||||
insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false),
|
||||
insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true),
|
||||
insertHost("localhost", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false),
|
||||
// Although ipv6 addresses are written with [] around the IP address,
|
||||
// the .host property doesn't contain these []s, which means that we
|
||||
// write it like this
|
||||
insertHost("2001:db8::ff00:42:8329", "C", 1, 0, 0, 0, 0, false),
|
||||
insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("moz-nullprincipal:{12ahjksd-akjs-asd3-8393-asdu2189asdu}", "B", 1, 0, 0, 0, 0, false),
|
||||
insertHost("<file>", "A", 1, 0, 0, 0, 0, false),
|
||||
insertHost("<file>", "B", 1, 0, 0, 0, 0, false),
|
||||
];
|
||||
|
||||
// CLose the db connection
|
||||
stmtInsert.finalize();
|
||||
db.close();
|
||||
stmtInsert = null;
|
||||
db = null;
|
||||
|
||||
let expected = [
|
||||
// We should have kept the previously migrated entries
|
||||
["https://foo.com", "A", 2, 0, 0, 0],
|
||||
["http://foo.com", "A", 2, 0, 0, 0],
|
||||
["http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0],
|
||||
|
||||
// Make sure that we also support localhost, and IP addresses
|
||||
["https://localhost:8080", "A", 1, 0, 0],
|
||||
["ftp://127.0.0.1:8080", "A", 1, 0, 0],
|
||||
|
||||
["http://[2001:db8::ff00:42:8329]", "C", 1, 0, 0],
|
||||
["https://[2001:db8::ff00:42:8329]", "C", 1, 0, 0],
|
||||
["http://192.0.2.235", "A", 1, 0, 0],
|
||||
|
||||
// There should only be one entry of this type in the database
|
||||
["https://192.0.2.235", "A", 2, 0, 0],
|
||||
];
|
||||
|
||||
let found = expected.map((it) => 0);
|
||||
|
||||
// Add some places to the places database
|
||||
yield PlacesTestUtils.addVisits(Services.io.newURI("https://foo.com/some/other/subdirectory", null, null));
|
||||
yield PlacesTestUtils.addVisits(Services.io.newURI("ftp://some.subdomain.of.foo.com:8000/some/subdirectory", null, null));
|
||||
yield PlacesTestUtils.addVisits(Services.io.newURI("ftp://127.0.0.1:8080", null, null));
|
||||
yield PlacesTestUtils.addVisits(Services.io.newURI("https://localhost:8080", null, null));
|
||||
|
||||
// Force initialization of the nsPermissionManager
|
||||
let enumerator = Services.perms.enumerator;
|
||||
while (enumerator.hasMoreElements()) {
|
||||
let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission);
|
||||
let isExpected = false;
|
||||
|
||||
expected.forEach((it, i) => {
|
||||
if (permission.principal.origin == it[0] &&
|
||||
permission.type == it[1] &&
|
||||
permission.capability == it[2] &&
|
||||
permission.expireType == it[3] &&
|
||||
permission.expireTime == it[4]) {
|
||||
isExpected = true;
|
||||
found[i]++;
|
||||
}
|
||||
});
|
||||
|
||||
do_check_true(isExpected,
|
||||
"Permission " + (isExpected ? "should" : "shouldn't") +
|
||||
" be in permission database: " +
|
||||
permission.principal.origin + ", " +
|
||||
permission.type + ", " +
|
||||
permission.capability + ", " +
|
||||
permission.expireType + ", " +
|
||||
permission.expireTime);
|
||||
}
|
||||
|
||||
found.forEach((count, i) => {
|
||||
do_check_true(count == 1, "Expected count = 1, got count = " + count + " for permission " + expected[i]);
|
||||
});
|
||||
|
||||
// Check to make sure that all of the tables which we care about are present
|
||||
{
|
||||
let db = Services.storage.openDatabase(GetPermissionsFile(profile));
|
||||
do_check_true(db.tableExists("moz_perms"));
|
||||
do_check_true(db.tableExists("moz_hosts"));
|
||||
do_check_true(db.tableExists("moz_hosts_is_backup"));
|
||||
do_check_false(db.tableExists("moz_perms_v6"));
|
||||
|
||||
let mozHostsStmt = db.createStatement("SELECT " +
|
||||
"host, type, permission, expireType, expireTime, " +
|
||||
"modificationTime, appId, isInBrowserElement " +
|
||||
"FROM moz_hosts WHERE id = :id");
|
||||
|
||||
// Check that the moz_hosts table still contains the correct values.
|
||||
created.forEach((it) => {
|
||||
mozHostsStmt.reset();
|
||||
mozHostsStmt.bindByName("id", it.id);
|
||||
mozHostsStmt.executeStep();
|
||||
do_check_eq(mozHostsStmt.getUTF8String(0), it.host);
|
||||
do_check_eq(mozHostsStmt.getUTF8String(1), it.type);
|
||||
do_check_eq(mozHostsStmt.getInt64(2), it.permission);
|
||||
do_check_eq(mozHostsStmt.getInt64(3), it.expireType);
|
||||
do_check_eq(mozHostsStmt.getInt64(4), it.expireTime);
|
||||
do_check_eq(mozHostsStmt.getInt64(5), it.modificationTime);
|
||||
do_check_eq(mozHostsStmt.getInt64(6), it.appId);
|
||||
do_check_eq(mozHostsStmt.getInt64(7), it.isInBrowserElement);
|
||||
});
|
||||
|
||||
// Check that there are the right number of values
|
||||
let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts");
|
||||
mozHostsCount.executeStep();
|
||||
do_check_eq(mozHostsCount.getInt64(0), created.length);
|
||||
|
||||
// Check that there are the right number of values in the permissions database
|
||||
let mozPermsCount = db.createStatement("SELECT count(*) FROM moz_perms");
|
||||
mozPermsCount.executeStep();
|
||||
do_check_eq(mozPermsCount.getInt64(0), expected.length);
|
||||
|
||||
db.close();
|
||||
}
|
||||
});
|
@ -43,3 +43,4 @@ skip-if = debug == true
|
||||
[test_permmanager_migrate_6-7a.js]
|
||||
[test_permmanager_migrate_6-7b.js]
|
||||
[test_permmanager_migrate_4-7_no_history.js]
|
||||
[test_permmanager_migrate_7-8.js]
|
||||
|
@ -1116,9 +1116,7 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
|
||||
HRESULT hr = mDC->CreateBitmap(D2DIntSize(mSize), D2D1::BitmapProperties(D2DPixelFormat(mFormat)), byRef(tmpBitmap));
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(mSize))) << "[D2D1.1] 5CreateBitmap failure " << mSize << " Code: " << hexa(hr) << " format " << (int)mFormat;
|
||||
// For now, crash in this scenario; this should happen because tmpBitmap is
|
||||
// null and CopyFromBitmap call below dereferences it.
|
||||
// return;
|
||||
return;
|
||||
}
|
||||
|
||||
// This flush is important since the copy method will not know about the context drawing to the surface.
|
||||
|
@ -15,6 +15,7 @@
|
||||
#endif
|
||||
#include "mozilla/Assertions.h"
|
||||
#include <vector>
|
||||
#include "RefPtrSkia.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
@ -147,7 +148,7 @@ StrokeOptionsToPaint(SkPaint& aPaint, const StrokeOptions &aOptions)
|
||||
}
|
||||
|
||||
SkDashPathEffect* dash = SkDashPathEffect::Create(&pattern.front(),
|
||||
dashCount,
|
||||
dashCount,
|
||||
SkFloatToScalar(aOptions.mDashOffset));
|
||||
SkSafeUnref(aPaint.setPathEffect(dash));
|
||||
}
|
||||
@ -237,14 +238,14 @@ static inline SkColor ColorToSkColor(const Color &color, Float aAlpha)
|
||||
static inline SkRect
|
||||
RectToSkRect(const Rect& aRect)
|
||||
{
|
||||
return SkRect::MakeXYWH(SkFloatToScalar(aRect.x), SkFloatToScalar(aRect.y),
|
||||
return SkRect::MakeXYWH(SkFloatToScalar(aRect.x), SkFloatToScalar(aRect.y),
|
||||
SkFloatToScalar(aRect.width), SkFloatToScalar(aRect.height));
|
||||
}
|
||||
|
||||
static inline SkRect
|
||||
IntRectToSkRect(const IntRect& aRect)
|
||||
{
|
||||
return SkRect::MakeXYWH(SkIntToScalar(aRect.x), SkIntToScalar(aRect.y),
|
||||
return SkRect::MakeXYWH(SkIntToScalar(aRect.x), SkIntToScalar(aRect.y),
|
||||
SkIntToScalar(aRect.width), SkIntToScalar(aRect.height));
|
||||
}
|
||||
|
||||
@ -289,74 +290,6 @@ ExtendModeToTileMode(ExtendMode aMode)
|
||||
return SkShader::kClamp_TileMode;
|
||||
}
|
||||
|
||||
// The following class was imported from Skia, which is under the
|
||||
// following licence:
|
||||
//
|
||||
// Copyright (c) 2011 Google Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
template <typename T> class RefPtrSkia {
|
||||
public:
|
||||
RefPtrSkia() : fObj(NULL) {}
|
||||
explicit RefPtrSkia(T* obj) : fObj(obj) { SkSafeRef(fObj); }
|
||||
RefPtrSkia(const RefPtrSkia& o) : fObj(o.fObj) { SkSafeRef(fObj); }
|
||||
~RefPtrSkia() { SkSafeUnref(fObj); }
|
||||
|
||||
RefPtrSkia& operator=(const RefPtrSkia& rp) {
|
||||
SkRefCnt_SafeAssign(fObj, rp.fObj);
|
||||
return *this;
|
||||
}
|
||||
RefPtrSkia& operator=(T* obj) {
|
||||
SkRefCnt_SafeAssign(fObj, obj);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T* get() const { return fObj; }
|
||||
T& operator*() const { return *fObj; }
|
||||
T* operator->() const { return fObj; }
|
||||
|
||||
RefPtrSkia& adopt(T* obj) {
|
||||
SkSafeUnref(fObj);
|
||||
fObj = obj;
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef T* RefPtrSkia::*unspecified_bool_type;
|
||||
operator unspecified_bool_type() const {
|
||||
return fObj ? &RefPtrSkia::fObj : NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
T* fObj;
|
||||
};
|
||||
|
||||
// End of code imported from Skia.
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
|
83
gfx/2d/RefPtrSkia.h
Normal file
83
gfx/2d/RefPtrSkia.h
Normal file
@ -0,0 +1,83 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_REFPTRSKIA_H_
|
||||
#define MOZILLA_GFX_REFPTRSKIA_H_
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
// The following class was imported from Skia, which is under the
|
||||
// following licence:
|
||||
//
|
||||
// Copyright (c) 2011 Google Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
template <typename T> class RefPtrSkia {
|
||||
public:
|
||||
RefPtrSkia() : fObj(NULL) {}
|
||||
explicit RefPtrSkia(T* obj) : fObj(obj) { SkSafeRef(fObj); }
|
||||
RefPtrSkia(const RefPtrSkia& o) : fObj(o.fObj) { SkSafeRef(fObj); }
|
||||
~RefPtrSkia() { SkSafeUnref(fObj); }
|
||||
|
||||
RefPtrSkia& operator=(const RefPtrSkia& rp) {
|
||||
SkRefCnt_SafeAssign(fObj, rp.fObj);
|
||||
return *this;
|
||||
}
|
||||
RefPtrSkia& operator=(T* obj) {
|
||||
SkRefCnt_SafeAssign(fObj, obj);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T* get() const { return fObj; }
|
||||
T& operator*() const { return *fObj; }
|
||||
T* operator->() const { return fObj; }
|
||||
|
||||
RefPtrSkia& adopt(T* obj) {
|
||||
SkSafeUnref(fObj);
|
||||
fObj = obj;
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef T* RefPtrSkia::*unspecified_bool_type;
|
||||
operator unspecified_bool_type() const {
|
||||
return fObj ? &RefPtrSkia::fObj : NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
T* fObj;
|
||||
};
|
||||
|
||||
// End of code imported from Skia.
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* MOZILLA_GFX_REFPTRSKIA_H_ */
|
@ -81,6 +81,7 @@ if CONFIG['MOZ_ENABLE_SKIA']:
|
||||
]
|
||||
EXPORTS.mozilla.gfx += [
|
||||
'HelpersSkia.h',
|
||||
'RefPtrSkia.h',
|
||||
]
|
||||
|
||||
# Are we targeting x86 or x64? If so, build SSE2 files.
|
||||
|
@ -57,9 +57,11 @@ unsigned GLContext::sCurrentGLContextTLS = -1;
|
||||
|
||||
uint32_t GLContext::sDebugMode = 0;
|
||||
|
||||
|
||||
#define MAX_SYMBOL_LENGTH 128
|
||||
#define MAX_SYMBOL_NAMES 5
|
||||
// If adding defines, don't forget to undefine symbols. See #undef block below.
|
||||
#define CORE_SYMBOL(x) { (PRFuncPtr*) &mSymbols.f##x, { #x, nullptr } }
|
||||
#define CORE_EXT_SYMBOL2(x,y,z) { (PRFuncPtr*) &mSymbols.f##x, { #x, #x #y, #x #z, nullptr } }
|
||||
#define EXT_SYMBOL2(x,y,z) { (PRFuncPtr*) &mSymbols.f##x, { #x #y, #x #z, nullptr } }
|
||||
#define EXT_SYMBOL3(x,y,z,w) { (PRFuncPtr*) &mSymbols.f##x, { #x #y, #x #z, #x #w, nullptr } }
|
||||
#define END_SYMBOLS { nullptr, { nullptr } }
|
||||
|
||||
// should match the order of GLExtensions, and be null-terminated.
|
||||
@ -74,6 +76,7 @@ static const char *sExtensionNames[] = {
|
||||
"GL_ANGLE_texture_compression_dxt5",
|
||||
"GL_ANGLE_timer_query",
|
||||
"GL_APPLE_client_storage",
|
||||
"GL_APPLE_framebuffer_multisample",
|
||||
"GL_APPLE_texture_range",
|
||||
"GL_APPLE_vertex_array_object",
|
||||
"GL_ARB_ES2_compatibility",
|
||||
@ -85,8 +88,10 @@ static const char *sExtensionNames[] = {
|
||||
"GL_ARB_draw_instanced",
|
||||
"GL_ARB_framebuffer_object",
|
||||
"GL_ARB_framebuffer_sRGB",
|
||||
"GL_ARB_geometry_shader4",
|
||||
"GL_ARB_half_float_pixel",
|
||||
"GL_ARB_instanced_arrays",
|
||||
"GL_ARB_internalformat_query",
|
||||
"GL_ARB_invalidate_subdata",
|
||||
"GL_ARB_map_buffer_range",
|
||||
"GL_ARB_occlusion_query2",
|
||||
@ -120,6 +125,7 @@ static const char *sExtensionNames[] = {
|
||||
"GL_EXT_framebuffer_object",
|
||||
"GL_EXT_framebuffer_sRGB",
|
||||
"GL_EXT_gpu_shader4",
|
||||
"GL_EXT_multisampled_render_to_texture",
|
||||
"GL_EXT_occlusion_query_boolean",
|
||||
"GL_EXT_packed_depth_stencil",
|
||||
"GL_EXT_read_format_bgra",
|
||||
@ -143,6 +149,8 @@ static const char *sExtensionNames[] = {
|
||||
"GL_KHR_debug",
|
||||
"GL_NV_draw_instanced",
|
||||
"GL_NV_fence",
|
||||
"GL_NV_framebuffer_blit",
|
||||
"GL_NV_geometry_program4",
|
||||
"GL_NV_half_float",
|
||||
"GL_NV_instanced_arrays",
|
||||
"GL_NV_transform_feedback",
|
||||
@ -155,6 +163,7 @@ static const char *sExtensionNames[] = {
|
||||
"GL_OES_depth32",
|
||||
"GL_OES_depth_texture",
|
||||
"GL_OES_element_index_uint",
|
||||
"GL_OES_framebuffer_object",
|
||||
"GL_OES_packed_depth_stencil",
|
||||
"GL_OES_rgb8_rgba8",
|
||||
"GL_OES_standard_derivatives",
|
||||
@ -476,31 +485,16 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
{ (PRFuncPtr*) &mSymbols.fGetShaderSource, { "GetShaderSource", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fShaderSource, { "ShaderSource", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fVertexAttribPointer, { "VertexAttribPointer", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fBindFramebuffer, { "BindFramebuffer", "BindFramebufferEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fBindRenderbuffer, { "BindRenderbuffer", "BindRenderbufferEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fCheckFramebufferStatus, { "CheckFramebufferStatus", "CheckFramebufferStatusEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fFramebufferRenderbuffer, { "FramebufferRenderbuffer", "FramebufferRenderbufferEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fFramebufferTexture2D, { "FramebufferTexture2D", "FramebufferTexture2DEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGenerateMipmap, { "GenerateMipmap", "GenerateMipmapEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetFramebufferAttachmentParameteriv, { "GetFramebufferAttachmentParameteriv", "GetFramebufferAttachmentParameterivEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetRenderbufferParameteriv, { "GetRenderbufferParameteriv", "GetRenderbufferParameterivEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fIsFramebuffer, { "IsFramebuffer", "IsFramebufferEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fIsRenderbuffer, { "IsRenderbuffer", "IsRenderbufferEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fRenderbufferStorage, { "RenderbufferStorage", "RenderbufferStorageEXT", nullptr } },
|
||||
|
||||
{ (PRFuncPtr*) &mSymbols.fGenBuffers, { "GenBuffers", "GenBuffersARB", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGenTextures, { "GenTextures", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fCreateProgram, { "CreateProgram", "CreateProgramARB", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fCreateShader, { "CreateShader", "CreateShaderARB", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGenFramebuffers, { "GenFramebuffers", "GenFramebuffersEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGenRenderbuffers, { "GenRenderbuffers", "GenRenderbuffersEXT", nullptr } },
|
||||
|
||||
{ (PRFuncPtr*) &mSymbols.fDeleteBuffers, { "DeleteBuffers", "DeleteBuffersARB", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fDeleteTextures, { "DeleteTextures", "DeleteTexturesARB", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fDeleteProgram, { "DeleteProgram", "DeleteProgramARB", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fDeleteShader, { "DeleteShader", "DeleteShaderARB", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fDeleteFramebuffers, { "DeleteFramebuffers", "DeleteFramebuffersEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fDeleteRenderbuffers, { "DeleteRenderbuffers", "DeleteRenderbuffersEXT", nullptr } },
|
||||
|
||||
END_SYMBOLS
|
||||
|
||||
@ -751,48 +745,107 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
}
|
||||
}
|
||||
|
||||
// Check for aux symbols based on extensions
|
||||
if (IsSupported(GLFeature::framebuffer_blit))
|
||||
{
|
||||
// Check for ARB_framebuffer_objects
|
||||
if (IsSupported(GLFeature::framebuffer_object)) {
|
||||
// https://www.opengl.org/registry/specs/ARB/framebuffer_object.txt
|
||||
SymLoadStruct coreSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fBlitFramebuffer, { "BlitFramebuffer", nullptr } },
|
||||
CORE_SYMBOL(IsRenderbuffer),
|
||||
CORE_SYMBOL(BindRenderbuffer),
|
||||
CORE_SYMBOL(DeleteRenderbuffers),
|
||||
CORE_SYMBOL(GenRenderbuffers),
|
||||
CORE_SYMBOL(RenderbufferStorage),
|
||||
CORE_SYMBOL(RenderbufferStorageMultisample),
|
||||
CORE_SYMBOL(GetRenderbufferParameteriv),
|
||||
CORE_SYMBOL(IsFramebuffer),
|
||||
CORE_SYMBOL(BindFramebuffer),
|
||||
CORE_SYMBOL(DeleteFramebuffers),
|
||||
CORE_SYMBOL(GenFramebuffers),
|
||||
CORE_SYMBOL(CheckFramebufferStatus),
|
||||
CORE_SYMBOL(FramebufferTexture2D),
|
||||
CORE_SYMBOL(FramebufferTextureLayer),
|
||||
CORE_SYMBOL(FramebufferRenderbuffer),
|
||||
CORE_SYMBOL(GetFramebufferAttachmentParameteriv),
|
||||
CORE_SYMBOL(BlitFramebuffer),
|
||||
CORE_SYMBOL(GenerateMipmap),
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
SymLoadStruct extSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fBlitFramebuffer, { "BlitFramebufferEXT", "BlitFramebufferANGLE", nullptr } },
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::framebuffer_blit);
|
||||
|
||||
if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
|
||||
NS_ERROR("GL supports framebuffer_blit without supplying glBlitFramebuffer");
|
||||
|
||||
MarkUnsupported(GLFeature::framebuffer_blit);
|
||||
ClearSymbols(coreSymbols);
|
||||
if (!LoadSymbols(coreSymbols, trygl, prefix)) {
|
||||
NS_ERROR("GL supports framebuffer_object without supplying its functions.");
|
||||
MarkUnsupported(GLFeature::framebuffer_object);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSupported(GLFeature::framebuffer_multisample))
|
||||
{
|
||||
SymLoadStruct coreSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fRenderbufferStorageMultisample, { "RenderbufferStorageMultisample", nullptr } },
|
||||
END_SYMBOLS
|
||||
};
|
||||
if (!IsSupported(GLFeature::framebuffer_object)) {
|
||||
|
||||
SymLoadStruct extSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fRenderbufferStorageMultisample, { "RenderbufferStorageMultisampleEXT", "RenderbufferStorageMultisampleANGLE", nullptr } },
|
||||
END_SYMBOLS
|
||||
};
|
||||
// Check for aux symbols based on extensions
|
||||
if (IsSupported(GLFeature::framebuffer_object_EXT_OES))
|
||||
{
|
||||
SymLoadStruct extSymbols[] = {
|
||||
CORE_EXT_SYMBOL2(IsRenderbuffer, EXT, OES),
|
||||
CORE_EXT_SYMBOL2(BindRenderbuffer, EXT, OES),
|
||||
CORE_EXT_SYMBOL2(DeleteRenderbuffers, EXT, OES),
|
||||
CORE_EXT_SYMBOL2(GenRenderbuffers, EXT, OES),
|
||||
CORE_EXT_SYMBOL2(RenderbufferStorage, EXT, OES),
|
||||
CORE_EXT_SYMBOL2(GetRenderbufferParameteriv, EXT, OES),
|
||||
CORE_EXT_SYMBOL2(IsFramebuffer, EXT, OES),
|
||||
CORE_EXT_SYMBOL2(BindFramebuffer, EXT, OES),
|
||||
CORE_EXT_SYMBOL2(DeleteFramebuffers, EXT, OES),
|
||||
CORE_EXT_SYMBOL2(GenFramebuffers, EXT, OES),
|
||||
CORE_EXT_SYMBOL2(CheckFramebufferStatus, EXT, OES),
|
||||
CORE_EXT_SYMBOL2(FramebufferTexture2D, EXT, OES),
|
||||
CORE_EXT_SYMBOL2(FramebufferRenderbuffer, EXT, OES),
|
||||
CORE_EXT_SYMBOL2(GetFramebufferAttachmentParameteriv, EXT, OES),
|
||||
CORE_EXT_SYMBOL2(GenerateMipmap, EXT, OES),
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::framebuffer_multisample);
|
||||
if (!LoadSymbols(extSymbols, trygl, prefix)) {
|
||||
NS_ERROR("GL supports framebuffer_object without supplying its functions.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
|
||||
NS_ERROR("GL supports framebuffer_multisample without supplying glRenderbufferStorageMultisample");
|
||||
if (IsExtensionSupported(GLContext::ANGLE_framebuffer_blit) ||
|
||||
IsExtensionSupported(GLContext::EXT_framebuffer_blit) ||
|
||||
IsExtensionSupported(GLContext::NV_framebuffer_blit))
|
||||
|
||||
MarkUnsupported(GLFeature::framebuffer_multisample);
|
||||
ClearSymbols(coreSymbols);
|
||||
{
|
||||
SymLoadStruct extSymbols[] = {
|
||||
EXT_SYMBOL3(BlitFramebuffer, ANGLE, EXT, NV),
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
if (!LoadSymbols(extSymbols, trygl, prefix)) {
|
||||
NS_ERROR("GL supports framebuffer_blit without supplying its functions.");
|
||||
}
|
||||
}
|
||||
|
||||
if (IsExtensionSupported(GLContext::ANGLE_framebuffer_multisample) ||
|
||||
IsExtensionSupported(GLContext::APPLE_framebuffer_multisample) ||
|
||||
IsExtensionSupported(GLContext::EXT_framebuffer_multisample) ||
|
||||
IsExtensionSupported(GLContext::EXT_multisampled_render_to_texture))
|
||||
{
|
||||
SymLoadStruct extSymbols[] = {
|
||||
EXT_SYMBOL3(RenderbufferStorageMultisample, ANGLE, APPLE, EXT),
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
if (!LoadSymbols(extSymbols, trygl, prefix)) {
|
||||
NS_ERROR("GL supports framebuffer_multisample without supplying its functions.");
|
||||
}
|
||||
}
|
||||
|
||||
if (IsExtensionSupported(GLContext::ARB_geometry_shader4) ||
|
||||
IsExtensionSupported(GLContext::NV_geometry_program4))
|
||||
{
|
||||
SymLoadStruct extSymbols[] = {
|
||||
EXT_SYMBOL2(FramebufferTextureLayer, ARB, EXT),
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
if (!LoadSymbols(extSymbols, trygl, prefix)) {
|
||||
NS_ERROR("GL supports geometry_shader4 withot supplying its functions.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1410,6 +1463,20 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSupported(GLFeature::internalformat_query)) {
|
||||
SymLoadStruct coreSymbols[] = {
|
||||
CORE_SYMBOL(GetInternalformativ),
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
if (!LoadSymbols(&coreSymbols[0], trygl, prefix)) {
|
||||
NS_ERROR("GL supports internalformat query without supplying its functions.");
|
||||
|
||||
MarkUnsupported(GLFeature::internalformat_query);
|
||||
ClearSymbols(coreSymbols);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSupported(GLFeature::invalidate_framebuffer)) {
|
||||
SymLoadStruct invSymbols[] = {
|
||||
{ (PRFuncPtr *) &mSymbols.fInvalidateFramebuffer, { "InvalidateFramebuffer", nullptr } },
|
||||
@ -1581,6 +1648,12 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
return mInitialized;
|
||||
}
|
||||
|
||||
#undef CORE_SYMBOL
|
||||
#undef CORE_EXT_SYMBOL2
|
||||
#undef EXT_SYMBOL2
|
||||
#undef EXT_SYMBOL3
|
||||
#undef END_SYMBOLS
|
||||
|
||||
void
|
||||
GLContext::DebugCallback(GLenum source,
|
||||
GLenum type,
|
||||
|
@ -97,6 +97,7 @@ enum class GLFeature {
|
||||
framebuffer_blit,
|
||||
framebuffer_multisample,
|
||||
framebuffer_object,
|
||||
framebuffer_object_EXT_OES,
|
||||
get_integer_indexed,
|
||||
get_integer64_indexed,
|
||||
get_query_object_i64v,
|
||||
@ -105,6 +106,7 @@ enum class GLFeature {
|
||||
gpu_shader4,
|
||||
instanced_arrays,
|
||||
instanced_non_arrays,
|
||||
internalformat_query,
|
||||
invalidate_framebuffer,
|
||||
map_buffer_range,
|
||||
occlusion_query,
|
||||
@ -385,6 +387,7 @@ public:
|
||||
ANGLE_texture_compression_dxt5,
|
||||
ANGLE_timer_query,
|
||||
APPLE_client_storage,
|
||||
APPLE_framebuffer_multisample,
|
||||
APPLE_texture_range,
|
||||
APPLE_vertex_array_object,
|
||||
ARB_ES2_compatibility,
|
||||
@ -396,8 +399,10 @@ public:
|
||||
ARB_draw_instanced,
|
||||
ARB_framebuffer_object,
|
||||
ARB_framebuffer_sRGB,
|
||||
ARB_geometry_shader4,
|
||||
ARB_half_float_pixel,
|
||||
ARB_instanced_arrays,
|
||||
ARB_internalformat_query,
|
||||
ARB_invalidate_subdata,
|
||||
ARB_map_buffer_range,
|
||||
ARB_occlusion_query2,
|
||||
@ -431,6 +436,7 @@ public:
|
||||
EXT_framebuffer_object,
|
||||
EXT_framebuffer_sRGB,
|
||||
EXT_gpu_shader4,
|
||||
EXT_multisampled_render_to_texture,
|
||||
EXT_occlusion_query_boolean,
|
||||
EXT_packed_depth_stencil,
|
||||
EXT_read_format_bgra,
|
||||
@ -454,6 +460,8 @@ public:
|
||||
KHR_debug,
|
||||
NV_draw_instanced,
|
||||
NV_fence,
|
||||
NV_framebuffer_blit,
|
||||
NV_geometry_program4,
|
||||
NV_half_float,
|
||||
NV_instanced_arrays,
|
||||
NV_transform_feedback,
|
||||
@ -466,6 +474,7 @@ public:
|
||||
OES_depth32,
|
||||
OES_depth_texture,
|
||||
OES_element_index_uint,
|
||||
OES_framebuffer_object,
|
||||
OES_packed_depth_stencil,
|
||||
OES_rgb8_rgba8,
|
||||
OES_standard_derivatives,
|
||||
@ -1944,6 +1953,13 @@ public:
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) {
|
||||
BEFORE_GL_CALL;
|
||||
ASSERT_SYMBOL_PRESENT(fFramebufferTextureLayer);
|
||||
mSymbols.fFramebufferTextureLayer(target, attachment, texture, level, layer);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* value) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fGetFramebufferAttachmentParameteriv(target, attachment, pname, value);
|
||||
@ -2518,6 +2534,17 @@ public:
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Feature internalformat_query
|
||||
public:
|
||||
void fGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) {
|
||||
BEFORE_GL_CALL;
|
||||
ASSERT_SYMBOL_PRESENT(fGetInternalformativ);
|
||||
mSymbols.fGetInternalformativ(target, internalformat, pname, bufSize, params);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Package XXX_query_counter
|
||||
/**
|
||||
|
@ -210,34 +210,53 @@ static const FeatureInfo sFeatureInfoArr[] = {
|
||||
}
|
||||
},
|
||||
{
|
||||
// Check for just the blit framebuffer blit part of
|
||||
// ARB_framebuffer_object
|
||||
"framebuffer_blit",
|
||||
GLVersion::GL3,
|
||||
GLESVersion::ES3,
|
||||
GLContext::Extension_None,
|
||||
GLContext::ARB_framebuffer_object,
|
||||
{
|
||||
GLContext::EXT_framebuffer_blit,
|
||||
GLContext::ANGLE_framebuffer_blit,
|
||||
GLContext::EXT_framebuffer_blit,
|
||||
GLContext::NV_framebuffer_blit,
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
// Check for just the multisample renderbuffer part of
|
||||
// ARB_framebuffer_object
|
||||
"framebuffer_multisample",
|
||||
GLVersion::GL3,
|
||||
GLESVersion::ES3,
|
||||
GLContext::Extension_None,
|
||||
GLContext::ARB_framebuffer_object,
|
||||
{
|
||||
GLContext::EXT_framebuffer_multisample,
|
||||
GLContext::ANGLE_framebuffer_multisample,
|
||||
GLContext::APPLE_framebuffer_multisample,
|
||||
GLContext::EXT_framebuffer_multisample,
|
||||
GLContext::EXT_multisampled_render_to_texture,
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
// ARB_framebuffer_object support
|
||||
"framebuffer_object",
|
||||
GLVersion::GL3,
|
||||
GLESVersion::ES2,
|
||||
GLESVersion::ES3,
|
||||
GLContext::ARB_framebuffer_object,
|
||||
{
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
// EXT_framebuffer_object/OES_framebuffer_object support
|
||||
"framebuffer_object_EXT_OES",
|
||||
GLVersion::GL3,
|
||||
GLESVersion::ES2,
|
||||
GLContext::Extension_None,
|
||||
{
|
||||
GLContext::EXT_framebuffer_object,
|
||||
GLContext::OES_framebuffer_object,
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
@ -332,6 +351,15 @@ static const FeatureInfo sFeatureInfoArr[] = {
|
||||
* has no such restriction.
|
||||
*/
|
||||
},
|
||||
{
|
||||
"internalformat_query",
|
||||
GLVersion::GL4_2,
|
||||
GLESVersion::ES3,
|
||||
GLContext::ARB_internalformat_query,
|
||||
{
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
"invalidate_framebuffer",
|
||||
GLVersion::GL4_3,
|
||||
|
@ -329,6 +329,8 @@ struct GLContextSymbols
|
||||
PFNGLFRAMEBUFFERRENDERBUFFER fFramebufferRenderbuffer;
|
||||
typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERTEXTURE2D) (GLenum target, GLenum attachmentPoint, GLenum textureTarget, GLuint texture, GLint level);
|
||||
PFNGLFRAMEBUFFERTEXTURE2D fFramebufferTexture2D;
|
||||
typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
|
||||
PFNGLFRAMEBUFFERTEXTURELAYERPROC fFramebufferTextureLayer;
|
||||
typedef void (GLAPIENTRY * PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIV) (GLenum target, GLenum attachment, GLenum pname, GLint* value);
|
||||
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIV fGetFramebufferAttachmentParameteriv;
|
||||
typedef void (GLAPIENTRY * PFNGLGETRENDERBUFFERPARAMETERIV) (GLenum target, GLenum pname, GLint* value);
|
||||
@ -487,6 +489,10 @@ struct GLContextSymbols
|
||||
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBDIVISOR) (GLuint index, GLuint divisor);
|
||||
PFNGLVERTEXATTRIBDIVISOR fVertexAttribDivisor;
|
||||
|
||||
// ARB_internalformat_query
|
||||
typedef void (GLAPIENTRY * PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params);
|
||||
PFNGLGETINTERNALFORMATIVPROC fGetInternalformativ;
|
||||
|
||||
// ARB_transform_feedback2 / OpenGL 4.0 / OpenGL ES 3.0
|
||||
typedef void (GLAPIENTRY * PFNGLBINDBUFFERBASE) (GLenum target, GLuint index, GLuint buffer);
|
||||
PFNGLBINDBUFFERBASE fBindBufferBase;
|
||||
|
@ -872,7 +872,7 @@ static GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context)
|
||||
i->fFunctions.fDeleteVertexArrays = glDeleteVertexArrays_mozilla;
|
||||
i->fFunctions.fGenVertexArrays = glGenVertexArrays_mozilla;
|
||||
|
||||
// Desktop GL
|
||||
// Desktop GL
|
||||
i->fFunctions.fGetTexLevelParameteriv = glGetTexLevelParameteriv_mozilla;
|
||||
i->fFunctions.fDrawBuffer = glDrawBuffer_mozilla;
|
||||
i->fFunctions.fReadBuffer = glReadBuffer_mozilla;
|
||||
@ -899,3 +899,15 @@ SkiaGLGlue::SkiaGLGlue(GLContext* context)
|
||||
mGrGLInterface->fCallbackData = reinterpret_cast<GrGLInterfaceCallbackData>(this);
|
||||
mGrContext.adopt(GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)mGrGLInterface.get()));
|
||||
}
|
||||
|
||||
SkiaGLGlue::~SkiaGLGlue()
|
||||
{
|
||||
/*
|
||||
* These members have inter-dependencies, but do not keep each other alive, so
|
||||
* destruction order is very important here: mGrContext uses mGrGLInterface, and
|
||||
* through it, uses mGLContext
|
||||
*/
|
||||
mGrContext = nullptr;
|
||||
mGrGLInterface = nullptr;
|
||||
mGLContext = nullptr;
|
||||
}
|
||||
|
@ -3,18 +3,22 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#ifndef SKIA_GL_GLUE_H_
|
||||
#define SKIA_GL_GLUE_H_
|
||||
|
||||
#ifdef USE_SKIA_GPU
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "skia/include/gpu/gl/GrGLInterface.h"
|
||||
#include "skia/include/gpu/GrContext.h"
|
||||
#include "mozilla/gfx/HelpersSkia.h"
|
||||
#include "mozilla/gfx/RefPtrSkia.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
struct GrGLInterface;
|
||||
class GrContext;
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
class GLContext;
|
||||
|
||||
class SkiaGLGlue : public GenericAtomicRefCounted
|
||||
{
|
||||
public:
|
||||
@ -24,27 +28,18 @@ public:
|
||||
GrContext* GetGrContext() const { return mGrContext.get(); }
|
||||
|
||||
protected:
|
||||
virtual ~SkiaGLGlue() {
|
||||
/*
|
||||
* These members have inter-dependencies, but do not keep each other alive, so
|
||||
* destruction order is very important here: mGrContext uses mGrGLInterface, and
|
||||
* through it, uses mGLContext
|
||||
*/
|
||||
mGrContext = nullptr;
|
||||
mGrGLInterface = nullptr;
|
||||
mGLContext = nullptr;
|
||||
}
|
||||
virtual ~SkiaGLGlue();
|
||||
|
||||
private:
|
||||
RefPtr<GLContext> mGLContext;
|
||||
mozilla::gfx::RefPtrSkia<GrGLInterface> mGrGLInterface;
|
||||
mozilla::gfx::RefPtrSkia<GrContext> mGrContext;
|
||||
gfx::RefPtrSkia<GrGLInterface> mGrGLInterface;
|
||||
gfx::RefPtrSkia<GrContext> mGrContext;
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
} // namespace mozilla
|
||||
|
||||
#else
|
||||
#else // USE_SKIA_GPU
|
||||
|
||||
class GrContext;
|
||||
|
||||
@ -60,7 +55,10 @@ public:
|
||||
GLContext* GetGLContext() const { return nullptr; }
|
||||
GrContext* GetGrContext() const { return nullptr; }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // namespace gl
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // USE_SKIA_GPU
|
||||
|
||||
#endif // SKIA_GL_GLUE_H_
|
||||
|
459
gfx/src/DriverCrashGuard.cpp
Normal file
459
gfx/src/DriverCrashGuard.cpp
Normal file
@ -0,0 +1,459 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "DriverCrashGuard.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
#endif
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
static const size_t NUM_CRASH_GUARD_TYPES = size_t(CrashGuardType::NUM_TYPES);
|
||||
static const char* sCrashGuardNames[NUM_CRASH_GUARD_TYPES] = {
|
||||
"d3d11layers",
|
||||
"d3d9video",
|
||||
};
|
||||
|
||||
DriverCrashGuard::DriverCrashGuard(CrashGuardType aType, dom::ContentParent* aContentParent)
|
||||
: mType(aType)
|
||||
, mMode(aContentParent ? Mode::Proxy : Mode::Normal)
|
||||
, mInitialized(false)
|
||||
, mGuardActivated(false)
|
||||
, mCrashDetected(false)
|
||||
{
|
||||
MOZ_ASSERT(mType < CrashGuardType::NUM_TYPES);
|
||||
|
||||
mStatusPref.Assign("gfx.crash-guard.status.");
|
||||
mStatusPref.Append(sCrashGuardNames[size_t(mType)]);
|
||||
}
|
||||
|
||||
void
|
||||
DriverCrashGuard::InitializeIfNeeded()
|
||||
{
|
||||
if (mInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
mInitialized = true;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void
|
||||
DriverCrashGuard::Initialize()
|
||||
{
|
||||
if (XRE_IsContentProcess()) {
|
||||
// Ask the parent whether or not activating the guard is okay. The parent
|
||||
// won't bother if it detected a crash.
|
||||
dom::ContentChild* cc = dom::ContentChild::GetSingleton();
|
||||
cc->SendBeginDriverCrashGuard(uint32_t(mType), &mCrashDetected);
|
||||
if (mCrashDetected) {
|
||||
LogFeatureDisabled();
|
||||
return;
|
||||
}
|
||||
|
||||
ActivateGuard();
|
||||
return;
|
||||
}
|
||||
|
||||
// Always check whether or not the lock file exists. For example, we could
|
||||
// have crashed creating a D3D9 device in the parent process, and on restart
|
||||
// are now requesting one in the child process. We catch everything here.
|
||||
if (RecoverFromCrash()) {
|
||||
mCrashDetected = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// If the environment has changed, we always activate the guard. In the
|
||||
// parent process this performs main-thread disk I/O. Child process guards
|
||||
// only incur an IPC cost, so if we're proxying for a child process, we
|
||||
// play it safe and activate the guard as long as we don't expect it to
|
||||
// crash.
|
||||
if (CheckOrRefreshEnvironment() ||
|
||||
(mMode == Mode::Proxy && GetStatus() != DriverInitStatus::Crashed))
|
||||
{
|
||||
ActivateGuard();
|
||||
return;
|
||||
}
|
||||
|
||||
// If we got here and our status is "crashed", then the environment has not
|
||||
// updated and we do not want to attempt to use the driver again.
|
||||
if (GetStatus() == DriverInitStatus::Crashed) {
|
||||
mCrashDetected = true;
|
||||
LogFeatureDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
DriverCrashGuard::~DriverCrashGuard()
|
||||
{
|
||||
if (!mGuardActivated) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
if (mGuardFile) {
|
||||
mGuardFile->Remove(false);
|
||||
}
|
||||
|
||||
// If during our initialization, no other process encountered a crash, we
|
||||
// proceed to mark the status as okay.
|
||||
if (GetStatus() != DriverInitStatus::Crashed) {
|
||||
SetStatus(DriverInitStatus::Okay);
|
||||
}
|
||||
} else {
|
||||
dom::ContentChild::GetSingleton()->SendEndDriverCrashGuard(uint32_t(mType));
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
// Remove the crash report annotation.
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"),
|
||||
NS_LITERAL_CSTRING(""));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
DriverCrashGuard::Crashed()
|
||||
{
|
||||
InitializeIfNeeded();
|
||||
|
||||
// Note, we read mCrashDetected instead of GetStatus(), since in child
|
||||
// processes we're not guaranteed that the prefs have been synced in
|
||||
// time.
|
||||
return mCrashDetected;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile>
|
||||
DriverCrashGuard::GetGuardFile()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
nsCString filename;
|
||||
filename.Assign(sCrashGuardNames[size_t(mType)]);
|
||||
filename.Append(".guard");
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR, getter_AddRefs(file));
|
||||
if (!file) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!NS_SUCCEEDED(file->AppendNative(filename))) {
|
||||
return nullptr;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
void
|
||||
DriverCrashGuard::ActivateGuard()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
mGuardActivated = true;
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
// Anotate crash reports only if we're a real guard. Otherwise, we could
|
||||
// attribute a random parent process crash to a graphics problem in a child
|
||||
// process.
|
||||
if (mMode != Mode::Proxy) {
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"),
|
||||
NS_LITERAL_CSTRING("1"));
|
||||
}
|
||||
#endif
|
||||
|
||||
// If we're in the content process, the rest of the guarding is handled
|
||||
// in the parent.
|
||||
if (XRE_IsContentProcess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetStatus(DriverInitStatus::Attempting);
|
||||
|
||||
if (mMode != Mode::Proxy) {
|
||||
// In parent process guards, we use two tombstones to detect crashes: a
|
||||
// preferences and a zero-byte file on the filesystem.
|
||||
FlushPreferences();
|
||||
|
||||
// Create a temporary tombstone/lockfile.
|
||||
FILE* fp = nullptr;
|
||||
mGuardFile = GetGuardFile();
|
||||
if (!mGuardFile || !NS_SUCCEEDED(mGuardFile->OpenANSIFileDesc("w", &fp))) {
|
||||
return;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DriverCrashGuard::NotifyCrashed()
|
||||
{
|
||||
CheckOrRefreshEnvironment();
|
||||
SetStatus(DriverInitStatus::Crashed);
|
||||
FlushPreferences();
|
||||
LogCrashRecovery();
|
||||
}
|
||||
|
||||
bool
|
||||
DriverCrashGuard::RecoverFromCrash()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
nsCOMPtr<nsIFile> file = GetGuardFile();
|
||||
bool exists;
|
||||
if ((file &&
|
||||
NS_SUCCEEDED(file->Exists(&exists)) &&
|
||||
exists) ||
|
||||
(GetStatus() == DriverInitStatus::Attempting))
|
||||
{
|
||||
// If we get here, we've just recovered from a crash. Disable acceleration
|
||||
// until the environment changes.
|
||||
if (file) {
|
||||
file->Remove(false);
|
||||
}
|
||||
NotifyCrashed();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if the caller should proceed to guard for crashes. False if
|
||||
// the environment has not changed. We persist the "changed" status across
|
||||
// calls, so that after an environment changes, all guards for the new
|
||||
// session are activated rather than just the first.
|
||||
bool
|
||||
DriverCrashGuard::CheckOrRefreshEnvironment()
|
||||
{
|
||||
// Our result can be cached statically since we don't check live prefs.
|
||||
static bool sBaseInfoChanged = false;
|
||||
static bool sBaseInfoChecked = false;
|
||||
|
||||
if (!sBaseInfoChecked) {
|
||||
// None of the prefs we care about, so we cache the result statically.
|
||||
sBaseInfoChecked = true;
|
||||
sBaseInfoChanged = UpdateBaseEnvironment();
|
||||
}
|
||||
|
||||
// Always update the full environment, even if the base info didn't change.
|
||||
return UpdateEnvironment() ||
|
||||
sBaseInfoChanged ||
|
||||
GetStatus() == DriverInitStatus::Unknown;
|
||||
}
|
||||
|
||||
bool
|
||||
DriverCrashGuard::UpdateBaseEnvironment()
|
||||
{
|
||||
bool changed = false;
|
||||
mGfxInfo = services::GetGfxInfo();
|
||||
if (mGfxInfo) {
|
||||
nsString value;
|
||||
|
||||
// Driver properties.
|
||||
mGfxInfo->GetAdapterDriverVersion(value);
|
||||
changed |= CheckAndUpdatePref("driverVersion", value);
|
||||
mGfxInfo->GetAdapterDeviceID(value);
|
||||
changed |= CheckAndUpdatePref("deviceID", value);
|
||||
}
|
||||
|
||||
// Firefox properties.
|
||||
changed |= CheckAndUpdatePref("appVersion", NS_LITERAL_STRING(MOZ_APP_VERSION));
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool
|
||||
DriverCrashGuard::FeatureEnabled(int aFeature)
|
||||
{
|
||||
int32_t status;
|
||||
if (!NS_SUCCEEDED(mGfxInfo->GetFeatureStatus(aFeature, &status))) {
|
||||
return false;
|
||||
}
|
||||
return status == nsIGfxInfo::FEATURE_STATUS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
DriverCrashGuard::CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue)
|
||||
{
|
||||
std::string pref = GetFullPrefName(aPrefName);
|
||||
|
||||
bool oldValue;
|
||||
if (NS_SUCCEEDED(Preferences::GetBool(pref.c_str(), &oldValue)) &&
|
||||
oldValue == aCurrentValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Preferences::SetBool(pref.c_str(), aCurrentValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DriverCrashGuard::CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue)
|
||||
{
|
||||
std::string pref = GetFullPrefName(aPrefName);
|
||||
|
||||
nsAdoptingString oldValue = Preferences::GetString(pref.c_str());
|
||||
if (oldValue == aCurrentValue) {
|
||||
return false;
|
||||
}
|
||||
Preferences::SetString(pref.c_str(), aCurrentValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string
|
||||
DriverCrashGuard::GetFullPrefName(const char* aPref)
|
||||
{
|
||||
return std::string("gfx.crash-guard.") +
|
||||
std::string(sCrashGuardNames[uint32_t(mType)]) +
|
||||
std::string(".") +
|
||||
std::string(aPref);
|
||||
}
|
||||
|
||||
DriverInitStatus
|
||||
DriverCrashGuard::GetStatus() const
|
||||
{
|
||||
return (DriverInitStatus)Preferences::GetInt(mStatusPref.get(), 0);
|
||||
}
|
||||
|
||||
void
|
||||
DriverCrashGuard::SetStatus(DriverInitStatus aStatus)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
Preferences::SetInt(mStatusPref.get(), int32_t(aStatus));
|
||||
}
|
||||
|
||||
void
|
||||
DriverCrashGuard::FlushPreferences()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
if (nsIPrefService* prefService = Preferences::GetService()) {
|
||||
prefService->SavePrefFile(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
D3D11LayersCrashGuard::D3D11LayersCrashGuard(dom::ContentParent* aContentParent)
|
||||
: DriverCrashGuard(CrashGuardType::D3D11Layers, aContentParent)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
D3D11LayersCrashGuard::Initialize()
|
||||
{
|
||||
if (!XRE_IsParentProcess()) {
|
||||
// We assume the parent process already performed crash detection for
|
||||
// graphics devices.
|
||||
return;
|
||||
}
|
||||
|
||||
DriverCrashGuard::Initialize();
|
||||
|
||||
// If no telemetry states have been recorded, this will set the state to okay.
|
||||
// Otherwise, it will have no effect.
|
||||
RecordTelemetry(TelemetryState::Okay);
|
||||
}
|
||||
|
||||
bool
|
||||
D3D11LayersCrashGuard::UpdateEnvironment()
|
||||
{
|
||||
// Our result can be cached statically since we don't check live prefs.
|
||||
static bool checked = false;
|
||||
static bool changed = false;
|
||||
|
||||
if (checked) {
|
||||
return changed;
|
||||
}
|
||||
|
||||
checked = true;
|
||||
|
||||
if (mGfxInfo) {
|
||||
// Feature status.
|
||||
#if defined(XP_WIN)
|
||||
bool d2dEnabled = gfxPrefs::Direct2DForceEnabled() ||
|
||||
(!gfxPrefs::Direct2DDisabled() && FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT2D));
|
||||
changed |= CheckAndUpdateBoolPref("feature-d2d", d2dEnabled);
|
||||
|
||||
bool d3d11Enabled = !gfxPrefs::LayersPreferD3D9();
|
||||
if (!FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS)) {
|
||||
d3d11Enabled = false;
|
||||
}
|
||||
changed |= CheckAndUpdateBoolPref("feature-d3d11", d3d11Enabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!changed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RecordTelemetry(TelemetryState::EnvironmentChanged);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
D3D11LayersCrashGuard::LogCrashRecovery()
|
||||
{
|
||||
RecordTelemetry(TelemetryState::RecoveredFromCrash);
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "D3D11 layers just crashed; D3D11 will be disabled.";
|
||||
}
|
||||
|
||||
void
|
||||
D3D11LayersCrashGuard::LogFeatureDisabled()
|
||||
{
|
||||
RecordTelemetry(TelemetryState::FeatureDisabled);
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "D3D11 layers disabled due to a prior crash.";
|
||||
}
|
||||
|
||||
void
|
||||
D3D11LayersCrashGuard::RecordTelemetry(TelemetryState aState)
|
||||
{
|
||||
// D3D11LayersCrashGuard is a no-op in the child process.
|
||||
if (!XRE_IsParentProcess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Since we instantiate this class more than once, make sure we only record
|
||||
// the first state (since that is really all we care about).
|
||||
static bool sTelemetryStateRecorded = false;
|
||||
if (sTelemetryStateRecorded) {
|
||||
return;
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::GRAPHICS_DRIVER_STARTUP_TEST, int32_t(aState));
|
||||
sTelemetryStateRecorded = true;
|
||||
}
|
||||
|
||||
D3D9VideoCrashGuard::D3D9VideoCrashGuard(dom::ContentParent* aContentParent)
|
||||
: DriverCrashGuard(CrashGuardType::D3D9Video, aContentParent)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
D3D9VideoCrashGuard::UpdateEnvironment()
|
||||
{
|
||||
// We don't care about any extra preferences here.
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
D3D9VideoCrashGuard::LogCrashRecovery()
|
||||
{
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "DXVA2D3D9 just crashed; hardware video will be disabled.";
|
||||
}
|
||||
|
||||
void
|
||||
D3D9VideoCrashGuard::LogFeatureDisabled()
|
||||
{
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "DXVA2D3D9 video decoding is disabled due to a previous crash.";
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
149
gfx/src/DriverCrashGuard.h
Normal file
149
gfx/src/DriverCrashGuard.h
Normal file
@ -0,0 +1,149 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef gfx_src_DriverCrashGuard_h__
|
||||
#define gfx_src_DriverCrashGuard_h__
|
||||
|
||||
#include "gfxCore.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIGfxInfo.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsString.h"
|
||||
#include <string>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class ContentParent;
|
||||
} // namespace dom
|
||||
|
||||
namespace gfx {
|
||||
|
||||
enum class DriverInitStatus
|
||||
{
|
||||
// Drivers have not been initialized yet.
|
||||
Unknown,
|
||||
|
||||
// We're attempting to initialize drivers.
|
||||
Attempting,
|
||||
|
||||
// Drivers were successfully initialized last run.
|
||||
Okay,
|
||||
|
||||
// We crashed during driver initialization, and have restarted.
|
||||
Crashed
|
||||
};
|
||||
|
||||
enum class CrashGuardType : uint32_t
|
||||
{
|
||||
D3D11Layers,
|
||||
D3D9Video,
|
||||
NUM_TYPES
|
||||
};
|
||||
|
||||
// DriverCrashGuard is used to detect crashes at graphics driver callsites.
|
||||
//
|
||||
// If the graphics environment is unrecognized or has changed since the last
|
||||
// session, the crash guard will activate and will detect any crashes within
|
||||
// the scope of the guard object.
|
||||
//
|
||||
// If a callsite has a previously encountered crash, and the environment has
|
||||
// not changed since the last session, then the guard will set a status flag
|
||||
// indicating that the driver should not be used.
|
||||
class DriverCrashGuard
|
||||
{
|
||||
public:
|
||||
DriverCrashGuard(CrashGuardType aType, dom::ContentParent* aContentParent);
|
||||
virtual ~DriverCrashGuard();
|
||||
|
||||
bool Crashed();
|
||||
void NotifyCrashed();
|
||||
|
||||
// These are the values reported to Telemetry (GRAPHICS_DRIVER_STARTUP_TEST).
|
||||
// Values should not change; add new values to the end.
|
||||
enum class TelemetryState {
|
||||
Okay = 0,
|
||||
EnvironmentChanged = 1,
|
||||
RecoveredFromCrash = 2,
|
||||
FeatureDisabled = 3
|
||||
};
|
||||
|
||||
enum class Mode {
|
||||
// Normal operation.
|
||||
Normal,
|
||||
|
||||
// Acting as a proxy between the parent and child process.
|
||||
Proxy
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual void Initialize();
|
||||
virtual bool UpdateEnvironment() = 0;
|
||||
virtual void LogCrashRecovery() = 0;
|
||||
virtual void LogFeatureDisabled() = 0;
|
||||
|
||||
// Helper functions.
|
||||
bool FeatureEnabled(int aFeature);
|
||||
bool CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue);
|
||||
bool CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue);
|
||||
std::string GetFullPrefName(const char* aPref);
|
||||
|
||||
private:
|
||||
// Either process.
|
||||
void InitializeIfNeeded();
|
||||
bool CheckOrRefreshEnvironment();
|
||||
bool UpdateBaseEnvironment();
|
||||
DriverInitStatus GetStatus() const;
|
||||
|
||||
// Parent process only.
|
||||
nsCOMPtr<nsIFile> GetGuardFile();
|
||||
bool RecoverFromCrash();
|
||||
void ActivateGuard();
|
||||
void FlushPreferences();
|
||||
void SetStatus(DriverInitStatus aStatus);
|
||||
|
||||
private:
|
||||
CrashGuardType mType;
|
||||
Mode mMode;
|
||||
bool mInitialized;
|
||||
bool mGuardActivated;
|
||||
bool mCrashDetected;
|
||||
nsCOMPtr<nsIFile> mGuardFile;
|
||||
|
||||
protected:
|
||||
nsCString mStatusPref;
|
||||
nsCOMPtr<nsIGfxInfo> mGfxInfo;
|
||||
};
|
||||
|
||||
class D3D11LayersCrashGuard final : public DriverCrashGuard
|
||||
{
|
||||
public:
|
||||
explicit D3D11LayersCrashGuard(dom::ContentParent* aContentParent = nullptr);
|
||||
|
||||
protected:
|
||||
void Initialize() override;
|
||||
bool UpdateEnvironment() override;
|
||||
void LogCrashRecovery() override;
|
||||
void LogFeatureDisabled() override;
|
||||
|
||||
private:
|
||||
void RecordTelemetry(TelemetryState aState);
|
||||
};
|
||||
|
||||
class D3D9VideoCrashGuard final : public DriverCrashGuard
|
||||
{
|
||||
public:
|
||||
explicit D3D9VideoCrashGuard(dom::ContentParent* aContentParent = nullptr);
|
||||
|
||||
protected:
|
||||
bool UpdateEnvironment() override;
|
||||
void LogCrashRecovery() override;
|
||||
void LogFeatureDisabled() override;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // gfx_src_DriverCrashGuard_h__
|
||||
|
@ -1,253 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "DriverInitCrashDetection.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
#endif
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
bool DriverInitCrashDetection::sDisableAcceleration = false;
|
||||
bool DriverInitCrashDetection::sEnvironmentHasBeenUpdated = false;
|
||||
|
||||
DriverInitCrashDetection::DriverInitCrashDetection()
|
||||
: mIsChromeProcess(XRE_GetProcessType() == GeckoProcessType_Default)
|
||||
{
|
||||
if (sDisableAcceleration) {
|
||||
// We already disabled acceleration earlier.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mIsChromeProcess) {
|
||||
// In child processes we only need to check the pref state set by the
|
||||
// parent process.
|
||||
sDisableAcceleration = (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Recovered));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!InitLockFilePath()) {
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Failed to create the graphics startup lockfile.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (RecoverFromDriverInitCrash()) {
|
||||
// This is the first time we're checking for a crash recovery, so print
|
||||
// a message and disable acceleration for anyone who asks for it.
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Recovered from graphics driver startup crash; acceleration disabled.";
|
||||
sDisableAcceleration = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (UpdateEnvironment() || sEnvironmentHasBeenUpdated) {
|
||||
// Something in the environment changed, *or* a previous instance of this
|
||||
// class already updated the environment. Allow a fresh attempt at driver
|
||||
// acceleration. This doesn't mean the previous attempt failed, it just
|
||||
// means we want to detect whether the new environment crashes.
|
||||
AllowDriverInitAttempt();
|
||||
sEnvironmentHasBeenUpdated = true;
|
||||
return;
|
||||
}
|
||||
|
||||
RecordTelemetry(TelemetryState::Okay);
|
||||
}
|
||||
|
||||
DriverInitCrashDetection::~DriverInitCrashDetection()
|
||||
{
|
||||
if (mLockFile) {
|
||||
mLockFile->Remove(false);
|
||||
}
|
||||
|
||||
if (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Attempting)) {
|
||||
// If we attempted to initialize the driver, and got this far without
|
||||
// crashing, assume everything is okay.
|
||||
gfxPrefs::SetDriverInitStatus(int32_t(DriverInitStatus::Okay));
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
// Remove the crash report annotation.
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"),
|
||||
NS_LITERAL_CSTRING(""));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
DriverInitCrashDetection::InitLockFilePath()
|
||||
{
|
||||
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR, getter_AddRefs(mLockFile));
|
||||
if (!mLockFile) {
|
||||
return false;
|
||||
}
|
||||
if (!NS_SUCCEEDED(mLockFile->AppendNative(NS_LITERAL_CSTRING("gfxinit.lock")))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DriverInitCrashDetection::AllowDriverInitAttempt()
|
||||
{
|
||||
// Create a temporary tombstone/lockfile.
|
||||
FILE* fp;
|
||||
if (!NS_SUCCEEDED(mLockFile->OpenANSIFileDesc("w", &fp))) {
|
||||
return;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
gfxPrefs::SetDriverInitStatus(int32_t(DriverInitStatus::Attempting));
|
||||
|
||||
// Flush preferences, so if we crash, we don't think the environment has changed again.
|
||||
FlushPreferences();
|
||||
|
||||
// If we crash, we'll just lose this. Not a big deal, next startup we'll
|
||||
// record the failure.
|
||||
RecordTelemetry(TelemetryState::EnvironmentChanged);
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"),
|
||||
NS_LITERAL_CSTRING("1"));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
DriverInitCrashDetection::RecoverFromDriverInitCrash()
|
||||
{
|
||||
bool exists;
|
||||
if (mLockFile &&
|
||||
NS_SUCCEEDED(mLockFile->Exists(&exists)) &&
|
||||
exists)
|
||||
{
|
||||
// If we get here, we've just recovered from a crash. Disable acceleration
|
||||
// until the environment changes. Since we may have crashed before
|
||||
// preferences we're flushed, we cache the environment again, then flush
|
||||
// preferences so child processes can start right away.
|
||||
gfxPrefs::SetDriverInitStatus(int32_t(DriverInitStatus::Recovered));
|
||||
UpdateEnvironment();
|
||||
FlushPreferences();
|
||||
RecordTelemetry(TelemetryState::RecoveredFromCrash);
|
||||
return true;
|
||||
}
|
||||
if (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Recovered)) {
|
||||
// If we get here, we crashed in the current environment and have already
|
||||
// disabled acceleration.
|
||||
RecordTelemetry(TelemetryState::AccelerationDisabled);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
DriverInitCrashDetection::UpdateEnvironment()
|
||||
{
|
||||
mGfxInfo = services::GetGfxInfo();
|
||||
|
||||
bool changed = false;
|
||||
if (mGfxInfo) {
|
||||
nsString value;
|
||||
|
||||
// Driver properties.
|
||||
mGfxInfo->GetAdapterDriverVersion(value);
|
||||
changed |= CheckAndUpdatePref("gfx.driver-init.driverVersion", value);
|
||||
mGfxInfo->GetAdapterDeviceID(value);
|
||||
changed |= CheckAndUpdatePref("gfx.driver-init.deviceID", value);
|
||||
|
||||
// Feature status.
|
||||
#if defined(XP_WIN)
|
||||
bool d2dEnabled = gfxPrefs::Direct2DForceEnabled() ||
|
||||
(!gfxPrefs::Direct2DDisabled() && FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT2D));
|
||||
changed |= CheckAndUpdateBoolPref("gfx.driver-init.feature-d2d", d2dEnabled);
|
||||
|
||||
bool d3d11Enabled = !gfxPrefs::LayersPreferD3D9();
|
||||
if (!FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS)) {
|
||||
d3d11Enabled = false;
|
||||
}
|
||||
changed |= CheckAndUpdateBoolPref("gfx.driver-init.feature-d3d11", d3d11Enabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Firefox properties.
|
||||
changed |= CheckAndUpdatePref("gfx.driver-init.appVersion", NS_LITERAL_STRING(MOZ_APP_VERSION));
|
||||
|
||||
// Finally, mark as changed if the status has been reset by the user.
|
||||
changed |= (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::None));
|
||||
|
||||
mGfxInfo = nullptr;
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool
|
||||
DriverInitCrashDetection::FeatureEnabled(int aFeature)
|
||||
{
|
||||
int32_t status;
|
||||
if (!NS_SUCCEEDED(mGfxInfo->GetFeatureStatus(aFeature, &status))) {
|
||||
return false;
|
||||
}
|
||||
return status == nsIGfxInfo::FEATURE_STATUS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
DriverInitCrashDetection::CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue)
|
||||
{
|
||||
bool oldValue;
|
||||
if (NS_SUCCEEDED(Preferences::GetBool(aPrefName, &oldValue)) &&
|
||||
oldValue == aCurrentValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Preferences::SetBool(aPrefName, aCurrentValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DriverInitCrashDetection::CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue)
|
||||
{
|
||||
nsAdoptingString oldValue = Preferences::GetString(aPrefName);
|
||||
if (oldValue == aCurrentValue) {
|
||||
return false;
|
||||
}
|
||||
Preferences::SetString(aPrefName, aCurrentValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DriverInitCrashDetection::FlushPreferences()
|
||||
{
|
||||
if (nsIPrefService* prefService = Preferences::GetService()) {
|
||||
prefService->SavePrefFile(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DriverInitCrashDetection::RecordTelemetry(TelemetryState aState)
|
||||
{
|
||||
// Since we run this in each child process, we only want the initial results
|
||||
// from the chrome process.
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Since we instantiate this class more than once, make sure we only record
|
||||
// the first state (since that is really all we care about).
|
||||
static bool sTelemetryStateRecorded = false;
|
||||
if (sTelemetryStateRecorded) {
|
||||
return;
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::GRAPHICS_DRIVER_STARTUP_TEST, int32_t(aState));
|
||||
sTelemetryStateRecorded = true;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
@ -1,76 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef gfx_src_DriverInitCrashDetection_h__
|
||||
#define gfx_src_DriverInitCrashDetection_h__
|
||||
|
||||
#include "gfxCore.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIGfxInfo.h"
|
||||
#include "nsIFile.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
enum class DriverInitStatus
|
||||
{
|
||||
// Drivers have not been initialized yet.
|
||||
None,
|
||||
|
||||
// We're attempting to initialize drivers.
|
||||
Attempting,
|
||||
|
||||
// Drivers were successfully initialized last run.
|
||||
Okay,
|
||||
|
||||
// We crashed during driver initialization, and have restarted.
|
||||
Recovered
|
||||
};
|
||||
|
||||
class DriverInitCrashDetection
|
||||
{
|
||||
public:
|
||||
DriverInitCrashDetection();
|
||||
~DriverInitCrashDetection();
|
||||
|
||||
bool DisableAcceleration() const {
|
||||
return sDisableAcceleration;
|
||||
}
|
||||
|
||||
// These are the values reported to Telemetry (GRAPHICS_DRIVER_STARTUP_TEST).
|
||||
// Values should not change; add new values to the end.
|
||||
enum class TelemetryState {
|
||||
Okay = 0,
|
||||
EnvironmentChanged = 1,
|
||||
RecoveredFromCrash = 2,
|
||||
AccelerationDisabled = 3
|
||||
};
|
||||
|
||||
private:
|
||||
bool InitLockFilePath();
|
||||
bool UpdateEnvironment();
|
||||
bool CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue);
|
||||
bool CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue);
|
||||
bool FeatureEnabled(int aFeature);
|
||||
void AllowDriverInitAttempt();
|
||||
bool RecoverFromDriverInitCrash();
|
||||
void FlushPreferences();
|
||||
|
||||
void RecordTelemetry(TelemetryState aState);
|
||||
|
||||
private:
|
||||
static bool sDisableAcceleration;
|
||||
static bool sEnvironmentHasBeenUpdated;
|
||||
|
||||
private:
|
||||
bool mIsChromeProcess;
|
||||
nsCOMPtr<nsIGfxInfo> mGfxInfo;
|
||||
nsCOMPtr<nsIFile> mLockFile;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // gfx_src_DriverInitCrashDetection_h__
|
||||
|
@ -14,7 +14,7 @@ XPIDL_MODULE = 'gfx'
|
||||
DEFINES['MOZ_APP_VERSION'] = '"%s"' % CONFIG['MOZ_APP_VERSION']
|
||||
|
||||
EXPORTS += [
|
||||
'DriverInitCrashDetection.h',
|
||||
'DriverCrashGuard.h',
|
||||
'FilterSupport.h',
|
||||
'gfxCore.h',
|
||||
'gfxCrashReporterUtils.h',
|
||||
@ -54,7 +54,7 @@ if CONFIG['MOZ_X11']:
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'DriverInitCrashDetection.cpp',
|
||||
'DriverCrashGuard.cpp',
|
||||
'FilterSupport.cpp',
|
||||
'gfxCrashReporterUtils.cpp',
|
||||
'gfxTelemetry.cpp',
|
||||
@ -77,6 +77,12 @@ SOURCES += [
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/ipc', # for ContentChild.h
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
|
||||
|
@ -93,6 +93,8 @@
|
||||
#ifdef USE_SKIA
|
||||
#include "skia/include/core/SkGraphics.h"
|
||||
# ifdef USE_SKIA_GPU
|
||||
# include "skia/include/gpu/GrContext.h"
|
||||
# include "skia/include/gpu/gl/GrGLInterface.h"
|
||||
# include "SkiaGLGlue.h"
|
||||
# endif
|
||||
#endif
|
||||
|
@ -232,9 +232,6 @@ private:
|
||||
DECL_GFX_PREF(Once, "gfx.direct2d.force-enabled", Direct2DForceEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.direct2d.use1_1", Direct2DUse1_1, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.draw-color-bars", CompositorDrawColorBars, bool, false);
|
||||
// This should be set to values in the DriverInitStatus enumeration found in
|
||||
// DriverInitCrashDetection.h.
|
||||
DECL_GFX_PREF(Live, "gfx.driver-init.status", DriverInitStatus, int32_t, 0);
|
||||
DECL_GFX_PREF(Once, "gfx.font_rendering.directwrite.enabled", DirectWriteFontRenderingEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.gralloc.fence-with-readpixels", GrallocFenceWithReadPixels, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.layerscope.enabled", LayerScopeEnabled, bool, false);
|
||||
|
@ -73,7 +73,7 @@
|
||||
#include "gfxPrefs.h"
|
||||
|
||||
#include "VsyncSource.h"
|
||||
#include "DriverInitCrashDetection.h"
|
||||
#include "DriverCrashGuard.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -2183,8 +2183,8 @@ gfxWindowsPlatform::InitializeDevices()
|
||||
// If we previously crashed initializing devices, bail out now. This is
|
||||
// effectively a parent-process only check, since the content process
|
||||
// cannot create a lock file.
|
||||
DriverInitCrashDetection detectCrashes;
|
||||
if (detectCrashes.DisableAcceleration()) {
|
||||
D3D11LayersCrashGuard detectCrashes;
|
||||
if (detectCrashes.Crashed()) {
|
||||
mAcceleration = FeatureStatus::Blocked;
|
||||
return;
|
||||
}
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <stdint.h>
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Tuple.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/gfx/Scale.h"
|
||||
|
||||
@ -744,17 +745,20 @@ RasterImage::GetCurrentImage(ImageContainer* aContainer, uint32_t aFlags)
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aContainer);
|
||||
|
||||
auto result = GetFrameInternal(FRAME_CURRENT, aFlags | FLAG_ASYNC_NOTIFY);
|
||||
if (!result.second()) {
|
||||
DrawResult drawResult;
|
||||
RefPtr<SourceSurface> surface;
|
||||
Tie(drawResult, surface) =
|
||||
GetFrameInternal(FRAME_CURRENT, aFlags | FLAG_ASYNC_NOTIFY);
|
||||
if (!surface) {
|
||||
// The OS threw out some or all of our buffer. We'll need to wait for the
|
||||
// redecode (which was automatically triggered by GetFrame) to complete.
|
||||
return MakePair(result.first(), nsRefPtr<layers::Image>());
|
||||
return MakePair(drawResult, nsRefPtr<layers::Image>());
|
||||
}
|
||||
|
||||
CairoImage::Data cairoData;
|
||||
GetWidth(&cairoData.mSize.width);
|
||||
GetHeight(&cairoData.mSize.height);
|
||||
cairoData.mSourceSurface = result.second();
|
||||
cairoData.mSourceSurface = surface;
|
||||
|
||||
nsRefPtr<layers::Image> image =
|
||||
aContainer->CreateImage(ImageFormat::CAIRO_SURFACE);
|
||||
@ -762,7 +766,7 @@ RasterImage::GetCurrentImage(ImageContainer* aContainer, uint32_t aFlags)
|
||||
|
||||
static_cast<CairoImage*>(image.get())->SetData(cairoData);
|
||||
|
||||
return MakePair(result.first(), Move(image));
|
||||
return MakePair(drawResult, Move(image));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
@ -814,18 +818,19 @@ RasterImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
|
||||
// We need a new ImageContainer, so create one.
|
||||
container = LayerManager::CreateImageContainer();
|
||||
|
||||
auto result = GetCurrentImage(container, aFlags);
|
||||
if (!result.second()) {
|
||||
// We couldn't get an Image.
|
||||
DrawResult drawResult;
|
||||
nsRefPtr<layers::Image> image;
|
||||
Tie(drawResult, image) = GetCurrentImage(container, aFlags);
|
||||
if (!image) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// |result.second()| holds a reference to a SourceSurface which in turn holds
|
||||
// a lock on the current frame's VolatileBuffer, ensuring that it doesn't get
|
||||
// freed as long as the layer system keeps this ImageContainer alive.
|
||||
container->SetCurrentImageInTransaction(result.second());
|
||||
// |image| holds a reference to a SourceSurface which in turn holds a lock on
|
||||
// the current frame's VolatileBuffer, ensuring that it doesn't get freed as
|
||||
// long as the layer system keeps this ImageContainer alive.
|
||||
container->SetCurrentImageInTransaction(image);
|
||||
|
||||
mLastImageContainerDrawResult = result.first();
|
||||
mLastImageContainerDrawResult = drawResult;
|
||||
mImageContainer = container;
|
||||
|
||||
return container.forget();
|
||||
@ -841,16 +846,16 @@ RasterImage::UpdateImageContainer()
|
||||
return;
|
||||
}
|
||||
|
||||
auto result = GetCurrentImage(container, FLAG_NONE);
|
||||
if (!result.second()) {
|
||||
// We couldn't get an Image.
|
||||
DrawResult drawResult;
|
||||
nsRefPtr<layers::Image> image;
|
||||
Tie(drawResult, image) = GetCurrentImage(container, FLAG_NONE);
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
mLastImageContainerDrawResult = result.first();
|
||||
nsAutoTArray<ImageContainer::NonOwningImage,1> imageList;
|
||||
imageList.AppendElement(
|
||||
ImageContainer::NonOwningImage(result.second()));
|
||||
mLastImageContainerDrawResult = drawResult;
|
||||
nsAutoTArray<ImageContainer::NonOwningImage, 1> imageList;
|
||||
imageList.AppendElement(ImageContainer::NonOwningImage(image));
|
||||
container->SetCurrentImages(imageList);
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "mozilla/Pair.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/Tuple.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxPattern.h" // Workaround for flaw in bug 921753 part 2.
|
||||
@ -661,11 +662,8 @@ public:
|
||||
DrawableFrameRef ref;
|
||||
MatchType matchType = MatchType::NOT_FOUND;
|
||||
while (true) {
|
||||
// XXX(seth): This code is begging for std::tie. See bug 1184385.
|
||||
Pair<already_AddRefed<CachedSurface>, MatchType> lookupResult =
|
||||
Tie(surface, matchType) =
|
||||
cache->LookupBestMatch(aSurfaceKey, aAlternateFlags);
|
||||
surface = lookupResult.first();
|
||||
matchType = lookupResult.second();
|
||||
|
||||
if (!surface) {
|
||||
return LookupResult(matchType); // Lookup in the per-image cache missed.
|
||||
|
@ -729,8 +729,8 @@ JavaScriptShared::Wrap(JSContext* cx, HandleObject aObj, InfallibleTArray<CpowEn
|
||||
if (!aObj)
|
||||
return true;
|
||||
|
||||
AutoIdArray ids(cx, JS_Enumerate(cx, aObj));
|
||||
if (!ids)
|
||||
Rooted<IdVector> ids(cx, IdVector(cx));
|
||||
if (!JS_Enumerate(cx, aObj, &ids))
|
||||
return false;
|
||||
|
||||
RootedId id(cx);
|
||||
|
@ -259,31 +259,6 @@ JSTracer::asCallbackTracer()
|
||||
return static_cast<JS::CallbackTracer*>(this);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
// Automates static dispatch for tracing for TraceableContainers.
|
||||
template <typename, typename=void> struct DefaultTracer;
|
||||
|
||||
// The default for POD, non-pointer types is to do nothing.
|
||||
template <typename T>
|
||||
struct DefaultTracer<T, typename mozilla::EnableIf<!mozilla::IsPointer<T>::value &&
|
||||
mozilla::IsPod<T>::value>::Type> {
|
||||
static void trace(JSTracer* trc, T* t, const char* name) {
|
||||
MOZ_ASSERT(mozilla::IsPod<T>::value);
|
||||
MOZ_ASSERT(!mozilla::IsPointer<T>::value);
|
||||
}
|
||||
};
|
||||
|
||||
// The default for non-pod (e.g. struct) types is to call the trace method.
|
||||
template <typename T>
|
||||
struct DefaultTracer<T, typename mozilla::EnableIf<!mozilla::IsPod<T>::value>::Type> {
|
||||
static void trace(JSTracer* trc, T* t, const char* name) {
|
||||
t->trace(trc);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
// The JS_Call*Tracer family of functions traces the given GC thing reference.
|
||||
// This performs the tracing action configured on the given JSTracer:
|
||||
// typically calling the JSTracer::callback or marking the thing as live.
|
||||
@ -366,4 +341,37 @@ extern JS_PUBLIC_API(void)
|
||||
JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc,
|
||||
void* thing, JS::TraceKind kind, bool includeDetails);
|
||||
|
||||
namespace js {
|
||||
|
||||
// Automates static dispatch for tracing for TraceableContainers.
|
||||
template <typename, typename=void> struct DefaultTracer;
|
||||
|
||||
// The default for POD, non-pointer types is to do nothing.
|
||||
template <typename T>
|
||||
struct DefaultTracer<T, typename mozilla::EnableIf<!mozilla::IsPointer<T>::value &&
|
||||
mozilla::IsPod<T>::value>::Type> {
|
||||
static void trace(JSTracer* trc, T* t, const char* name) {
|
||||
MOZ_ASSERT(mozilla::IsPod<T>::value);
|
||||
MOZ_ASSERT(!mozilla::IsPointer<T>::value);
|
||||
}
|
||||
};
|
||||
|
||||
// The default for non-pod (e.g. struct) types is to call the trace method.
|
||||
template <typename T>
|
||||
struct DefaultTracer<T, typename mozilla::EnableIf<!mozilla::IsPod<T>::value>::Type> {
|
||||
static void trace(JSTracer* trc, T* t, const char* name) {
|
||||
t->trace(trc);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DefaultTracer<jsid>
|
||||
{
|
||||
static void trace(JSTracer* trc, jsid* id, const char* name) {
|
||||
JS_CallUnbarrieredIdTracer(trc, id, name);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* js_TracingAPI_h */
|
||||
|
@ -13,6 +13,7 @@
|
||||
// These includes are needed these for some typedefs (e.g. HandleValue) and
|
||||
// functions (e.g. NullValue())...
|
||||
#include "js/CallNonGenericMethod.h"
|
||||
#include "js/TraceableVector.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Value.h"
|
||||
|
||||
@ -33,15 +34,15 @@ class AutoVectorRooter;
|
||||
typedef AutoVectorRooter<Value> AutoValueVector;
|
||||
typedef AutoVectorRooter<jsid> AutoIdVector;
|
||||
typedef AutoVectorRooter<JSObject*> AutoObjectVector;
|
||||
typedef AutoVectorRooter<JSFunction*> AutoFunctionVector;
|
||||
typedef AutoVectorRooter<JSScript*> AutoVector;
|
||||
|
||||
class AutoIdArray;
|
||||
using ValueVector = js::TraceableVector<JS::Value>;
|
||||
using IdVector = js::TraceableVector<jsid>;
|
||||
using ScriptVector = js::TraceableVector<JSScript*>;
|
||||
|
||||
template <typename T> class AutoVectorRooter;
|
||||
template<typename K, typename V> class AutoHashMapRooter;
|
||||
template<typename T> class AutoHashSetRooter;
|
||||
template<typename T> class RootedGeneric;
|
||||
|
||||
class MOZ_STACK_CLASS SourceBufferHolder;
|
||||
|
||||
@ -81,14 +82,14 @@ using JS::AutoVectorRooter;
|
||||
typedef AutoVectorRooter<Value> AutoValueVector;
|
||||
typedef AutoVectorRooter<jsid> AutoIdVector;
|
||||
typedef AutoVectorRooter<JSObject*> AutoObjectVector;
|
||||
typedef AutoVectorRooter<JSFunction*> AutoFunctionVector;
|
||||
typedef AutoVectorRooter<JSScript*> AutoScriptVector;
|
||||
|
||||
using JS::AutoIdArray;
|
||||
using JS::ValueVector;
|
||||
using JS::IdVector;
|
||||
using JS::ScriptVector;
|
||||
|
||||
using JS::AutoHashMapRooter;
|
||||
using JS::AutoHashSetRooter;
|
||||
using JS::RootedGeneric;
|
||||
|
||||
using JS::CallArgs;
|
||||
using JS::CallNonGenericMethod;
|
||||
|
@ -846,7 +846,7 @@ HandleDynamicLinkFailure(JSContext* cx, CallArgs args, AsmJSModule& module, Hand
|
||||
if (!fun)
|
||||
return false;
|
||||
|
||||
AutoNameVector formals(cx);
|
||||
Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
|
||||
if (!formals.reserve(3))
|
||||
return false;
|
||||
|
||||
|
@ -3261,8 +3261,8 @@ ImplicitConvert(JSContext* cx,
|
||||
if (val.isObject() && !sourceData) {
|
||||
// Enumerate the properties of the object; if they match the struct
|
||||
// specification, convert the fields.
|
||||
AutoIdArray props(cx, JS_Enumerate(cx, valObj));
|
||||
if (!props)
|
||||
Rooted<IdVector> props(cx, IdVector(cx));
|
||||
if (!JS_Enumerate(cx, valObj, &props))
|
||||
return false;
|
||||
|
||||
// Convert into an intermediate, in case of failure.
|
||||
@ -5343,8 +5343,8 @@ ExtractStructField(JSContext* cx, Value val, MutableHandleObject typeObj)
|
||||
}
|
||||
|
||||
RootedObject obj(cx, &val.toObject());
|
||||
AutoIdArray props(cx, JS_Enumerate(cx, obj));
|
||||
if (!props)
|
||||
Rooted<IdVector> props(cx, IdVector(cx));
|
||||
if (!JS_Enumerate(cx, obj, &props))
|
||||
return nullptr;
|
||||
|
||||
// make sure we have one, and only one, property
|
||||
|
@ -57,7 +57,7 @@ class MOZ_STACK_CLASS BytecodeCompiler
|
||||
void setSourceArgumentsNotIncluded();
|
||||
|
||||
JSScript* compileScript(HandleObject scopeChain, HandleScript evalCaller);
|
||||
bool compileFunctionBody(MutableHandleFunction fun, const AutoNameVector& formals,
|
||||
bool compileFunctionBody(MutableHandleFunction fun, Handle<PropertyNameVector> formals,
|
||||
GeneratorKind generatorKind);
|
||||
|
||||
private:
|
||||
@ -644,7 +644,8 @@ BytecodeCompiler::compileScript(HandleObject scopeChain, HandleScript evalCaller
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun, const AutoNameVector& formals,
|
||||
BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
|
||||
Handle<PropertyNameVector> formals,
|
||||
GeneratorKind generatorKind)
|
||||
{
|
||||
MOZ_ASSERT(fun);
|
||||
@ -824,7 +825,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
|
||||
// handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
|
||||
static bool
|
||||
CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options,
|
||||
const AutoNameVector& formals, SourceBufferHolder& srcBuf,
|
||||
Handle<PropertyNameVector> formals, SourceBufferHolder& srcBuf,
|
||||
Handle<ScopeObject*> enclosingStaticScope, GeneratorKind generatorKind)
|
||||
{
|
||||
MOZ_ASSERT(!options.isRunOnce);
|
||||
@ -841,7 +842,7 @@ CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyComp
|
||||
bool
|
||||
frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
const AutoNameVector& formals, JS::SourceBufferHolder& srcBuf,
|
||||
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
|
||||
Handle<ScopeObject*> enclosingStaticScope)
|
||||
{
|
||||
return CompileFunctionBody(cx, fun, options, formals, srcBuf,
|
||||
@ -850,7 +851,8 @@ frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
|
||||
|
||||
bool
|
||||
frontend::CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options, const AutoNameVector& formals,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
Handle<PropertyNameVector> formals,
|
||||
JS::SourceBufferHolder& srcBuf)
|
||||
{
|
||||
return CompileFunctionBody(cx, fun, options, formals, srcBuf, nullptr, StarGenerator);
|
||||
|
@ -9,11 +9,12 @@
|
||||
|
||||
#include "NamespaceImports.h"
|
||||
|
||||
#include "vm/String.h"
|
||||
|
||||
class JSLinearString;
|
||||
|
||||
namespace js {
|
||||
|
||||
class AutoNameVector;
|
||||
class LazyScript;
|
||||
class LifoAlloc;
|
||||
class ScriptSourceObject;
|
||||
@ -39,12 +40,12 @@ CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* cha
|
||||
bool
|
||||
CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
const AutoNameVector& formals, JS::SourceBufferHolder& srcBuf,
|
||||
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
|
||||
Handle<ScopeObject*> enclosingStaticScope);
|
||||
bool
|
||||
CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
const AutoNameVector& formals, JS::SourceBufferHolder& srcBuf);
|
||||
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
|
||||
|
||||
ScriptSourceObject*
|
||||
CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options);
|
||||
|
@ -345,12 +345,10 @@ BytecodeEmitter::emitCall(JSOp op, uint16_t argc, ParseNode* pn)
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitDupAt(unsigned slot)
|
||||
BytecodeEmitter::emitDupAt(unsigned slotFromTop)
|
||||
{
|
||||
MOZ_ASSERT(slot < unsigned(stackDepth));
|
||||
MOZ_ASSERT(slotFromTop < unsigned(stackDepth));
|
||||
|
||||
// The slot's position on the operand stack, measured from the top.
|
||||
unsigned slotFromTop = stackDepth - 1 - slot;
|
||||
if (slotFromTop >= JS_BIT(24)) {
|
||||
reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
|
||||
return false;
|
||||
@ -2787,7 +2785,7 @@ BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts)
|
||||
return false;
|
||||
|
||||
// We need another |this| on top, also
|
||||
if (!emitDupAt(this->stackDepth - 1 - 1))
|
||||
if (!emitDupAt(1))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2898,11 +2896,11 @@ BytecodeEmitter::emitSuperElemIncDec(ParseNode* pn)
|
||||
|
||||
// There's no such thing as JSOP_DUP3, so we have to be creative.
|
||||
// Note that pushing things again is no fewer JSOps.
|
||||
if (!emitDupAt(this->stackDepth - 1 - 2)) // KEY THIS OBJ KEY
|
||||
if (!emitDupAt(2)) // KEY THIS OBJ KEY
|
||||
return false;
|
||||
if (!emitDupAt(this->stackDepth - 1 - 2)) // KEY THIS OBJ KEY THIS
|
||||
if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS
|
||||
return false;
|
||||
if (!emitDupAt(this->stackDepth - 1 - 2)) // KEY THIS OBJ KEY THIS OBJ
|
||||
if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS OBJ
|
||||
return false;
|
||||
if (!emitElemOpBase(JSOP_GETELEM_SUPER)) // KEY THIS OBJ V
|
||||
return false;
|
||||
@ -4465,11 +4463,11 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs)
|
||||
return false;
|
||||
break;
|
||||
case PNK_SUPERELEM:
|
||||
if (!emitDupAt(this->stackDepth - 1 - 2))
|
||||
if (!emitDupAt(2))
|
||||
return false;
|
||||
if (!emitDupAt(this->stackDepth - 1 - 2))
|
||||
if (!emitDupAt(2))
|
||||
return false;
|
||||
if (!emitDupAt(this->stackDepth - 1 - 2))
|
||||
if (!emitDupAt(2))
|
||||
return false;
|
||||
if (!emitElemOpBase(JSOP_GETELEM_SUPER))
|
||||
return false;
|
||||
@ -5370,7 +5368,7 @@ BytecodeEmitter::emitForOf(StmtType type, ParseNode* pn, ptrdiff_t top)
|
||||
if (!emit1(JSOP_DUP)) // ITER ITER
|
||||
return false;
|
||||
} else {
|
||||
if (!emitDupAt(this->stackDepth - 1 - 2)) // ITER ARR I ITER
|
||||
if (!emitDupAt(2)) // ITER ARR I ITER
|
||||
return false;
|
||||
}
|
||||
if (!emitIteratorNext(forHead)) // ... RESULT
|
||||
@ -6720,7 +6718,7 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
|
||||
|
||||
if (isNewOp) {
|
||||
// Repush the callee as new.target
|
||||
if (!emitDupAt(this->stackDepth - 1 - (argc + 1)))
|
||||
if (!emitDupAt(argc + 1))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@ -6728,7 +6726,7 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
|
||||
return false;
|
||||
|
||||
if (isNewOp) {
|
||||
if (!emitDupAt(this->stackDepth - 1 - 2))
|
||||
if (!emitDupAt(2))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -7869,7 +7867,7 @@ BytecodeEmitter::emitTree(ParseNode* pn)
|
||||
*/
|
||||
if (!emitTree(pn->pn_kid))
|
||||
return false;
|
||||
if (!emitDupAt(arrayCompDepth))
|
||||
if (!emitDupAt(this->stackDepth - 1 - arrayCompDepth))
|
||||
return false;
|
||||
if (!emit1(JSOP_ARRAYPUSH))
|
||||
return false;
|
||||
|
@ -373,17 +373,9 @@ struct BytecodeEmitter
|
||||
// Emit three bytecodes, an opcode with two bytes of immediate operands.
|
||||
bool emit3(JSOp op, jsbytecode op1, jsbytecode op2);
|
||||
|
||||
// Dup the var in operand stack slot "slot". The first item on the operand
|
||||
// stack is one slot past the last fixed slot. The last (most recent) item is
|
||||
// slot bce->stackDepth - 1.
|
||||
//
|
||||
// The instruction that is written (JSOP_DUPAT) switches the depth around so
|
||||
// that it is addressed from the sp instead of from the fp. This is useful when
|
||||
// you don't know the size of the fixed stack segment (nfixed), as is the case
|
||||
// when compiling scripts (because each statement is parsed and compiled
|
||||
// separately, but they all together form one script with one fixed stack
|
||||
// frame).
|
||||
bool emitDupAt(unsigned slot);
|
||||
// Helper to emit JSOP_DUPAT. The argument is the value's depth on the
|
||||
// JS stack, as measured from the top.
|
||||
bool emitDupAt(unsigned slotFromTop);
|
||||
|
||||
// Emit a bytecode followed by an uint16 immediate operand stored in
|
||||
// big-endian order.
|
||||
|
@ -799,7 +799,8 @@ Parser<ParseHandler>::checkStrictBinding(PropertyName* name, Node pn)
|
||||
|
||||
template <>
|
||||
ParseNode*
|
||||
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoNameVector& formals,
|
||||
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
|
||||
Handle<PropertyNameVector> formals,
|
||||
GeneratorKind generatorKind,
|
||||
Directives inheritedDirectives,
|
||||
Directives* newDirectives,
|
||||
|
@ -227,7 +227,7 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext
|
||||
the same name. */
|
||||
|
||||
// All inner functions in this context. Only filled in when parsing syntax.
|
||||
AutoFunctionVector innerFunctions;
|
||||
Rooted<TraceableVector<JSFunction*>> innerFunctions;
|
||||
|
||||
// In a function context, points to a Directive struct that can be updated
|
||||
// to reflect new directives encountered in the Directive Prologue that
|
||||
@ -265,7 +265,7 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext
|
||||
oldpc(prs->pc),
|
||||
lexdeps(prs->context),
|
||||
funcStmts(nullptr),
|
||||
innerFunctions(prs->context),
|
||||
innerFunctions(prs->context, TraceableVector<JSFunction*>(prs->context)),
|
||||
newDirectives(newDirectives),
|
||||
inDeclDestructuring(false)
|
||||
{
|
||||
@ -544,7 +544,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||
|
||||
// Parse a function, given only its body. Used for the Function and
|
||||
// Generator constructors.
|
||||
Node standaloneFunctionBody(HandleFunction fun, const AutoNameVector& formals,
|
||||
Node standaloneFunctionBody(HandleFunction fun, Handle<PropertyNameVector> formals,
|
||||
GeneratorKind generatorKind,
|
||||
Directives inheritedDirectives, Directives* newDirectives,
|
||||
HandleObject enclosingStaticScope);
|
||||
|
@ -82,13 +82,6 @@ MarkExactStackRoots(JSRuntime* rt, JSTracer* trc)
|
||||
MarkExactStackRootsAcrossTypes<PerThreadData*>(&rt->mainThread, trc);
|
||||
}
|
||||
|
||||
void
|
||||
JS::AutoIdArray::trace(JSTracer* trc)
|
||||
{
|
||||
MOZ_ASSERT(tag_ == IDARRAY);
|
||||
TraceRange(trc, idArray->length, idArray->begin(), "JSAutoIdArray.idArray");
|
||||
}
|
||||
|
||||
inline void
|
||||
AutoGCRooter::trace(JSTracer* trc)
|
||||
{
|
||||
@ -97,12 +90,6 @@ AutoGCRooter::trace(JSTracer* trc)
|
||||
frontend::MarkParser(trc, this);
|
||||
return;
|
||||
|
||||
case IDARRAY: {
|
||||
JSIdArray* ida = static_cast<AutoIdArray*>(this)->idArray;
|
||||
TraceRange(trc, ida->length, ida->begin(), "JS::AutoIdArray.idArray");
|
||||
return;
|
||||
}
|
||||
|
||||
case VALVECTOR: {
|
||||
AutoValueVector::VectorImpl& vector = static_cast<AutoValueVector*>(this)->vector;
|
||||
TraceRootRange(trc, vector.length(), vector.begin(), "JS::AutoValueVector.vector");
|
||||
@ -121,12 +108,6 @@ AutoGCRooter::trace(JSTracer* trc)
|
||||
return;
|
||||
}
|
||||
|
||||
case NAMEVECTOR: {
|
||||
AutoNameVector::VectorImpl& vector = static_cast<AutoNameVector*>(this)->vector;
|
||||
TraceRootRange(trc, vector.length(), vector.begin(), "js::AutoNameVector.vector");
|
||||
return;
|
||||
}
|
||||
|
||||
case VALARRAY: {
|
||||
/*
|
||||
* We don't know the template size parameter, but we can safely treat it
|
||||
|
@ -1765,25 +1765,6 @@ JS_SetNativeStackQuota(JSRuntime* rt, size_t systemCodeStackSize, size_t trusted
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
JS_PUBLIC_API(int)
|
||||
JS_IdArrayLength(JSContext* cx, JSIdArray* ida)
|
||||
{
|
||||
return ida->length;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(jsid)
|
||||
JS_IdArrayGet(JSContext* cx, JSIdArray* ida, unsigned index)
|
||||
{
|
||||
MOZ_ASSERT(index < unsigned(ida->length));
|
||||
return ida->vector[index];
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_DestroyIdArray(JSContext* cx, JSIdArray* ida)
|
||||
{
|
||||
cx->runtime()->defaultFreeOp()->free_(ida);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ValueToId(JSContext* cx, HandleValue value, MutableHandleId idp)
|
||||
{
|
||||
@ -3166,18 +3147,19 @@ JS_SetAllNonReservedSlotsToUndefined(JSContext* cx, JSObject* objArg)
|
||||
obj->as<NativeObject>().setSlot(i, UndefinedValue());
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSIdArray*)
|
||||
JS_Enumerate(JSContext* cx, HandleObject obj)
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_Enumerate(JSContext* cx, HandleObject obj, JS::MutableHandle<IdVector> props)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj);
|
||||
MOZ_ASSERT(props.empty());
|
||||
|
||||
AutoIdVector props(cx);
|
||||
JSIdArray* ida;
|
||||
if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &props) || !VectorToIdArray(cx, props, &ida))
|
||||
return nullptr;
|
||||
return ida;
|
||||
AutoIdVector ids(cx);
|
||||
if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &ids))
|
||||
return false;
|
||||
|
||||
return props.append(ids.begin(), ids.end());
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(Value)
|
||||
@ -4252,7 +4234,7 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoNameVector formals(cx);
|
||||
Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
|
||||
for (unsigned i = 0; i < nargs; i++) {
|
||||
RootedAtom argAtom(cx, Atomize(cx, argnames[i], strlen(argnames[i])));
|
||||
if (!argAtom || !formals.append(argAtom->asPropertyName()))
|
||||
|
105
js/src/jsapi.h
105
js/src/jsapi.h
@ -29,6 +29,7 @@
|
||||
#include "js/Id.h"
|
||||
#include "js/Principals.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/TraceableVector.h"
|
||||
#include "js/TracingAPI.h"
|
||||
#include "js/Utility.h"
|
||||
#include "js/Value.h"
|
||||
@ -215,9 +216,12 @@ class MOZ_STACK_CLASS AutoVectorRooter : public AutoVectorRooterBase<T>
|
||||
typedef AutoVectorRooter<Value> AutoValueVector;
|
||||
typedef AutoVectorRooter<jsid> AutoIdVector;
|
||||
typedef AutoVectorRooter<JSObject*> AutoObjectVector;
|
||||
typedef AutoVectorRooter<JSFunction*> AutoFunctionVector;
|
||||
typedef AutoVectorRooter<JSScript*> AutoScriptVector;
|
||||
|
||||
using ValueVector = js::TraceableVector<JS::Value>;
|
||||
using IdVector = js::TraceableVector<jsid>;
|
||||
using ScriptVector = js::TraceableVector<JSScript*>;
|
||||
|
||||
template<class Key, class Value>
|
||||
class AutoHashMapRooter : protected AutoGCRooter
|
||||
{
|
||||
@ -474,43 +478,6 @@ class JS_PUBLIC_API(CustomAutoRooter) : private AutoGCRooter
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
/*
|
||||
* RootedGeneric<T> allows a class to instantiate its own Rooted type by
|
||||
* including the method:
|
||||
*
|
||||
* void trace(JSTracer* trc);
|
||||
*
|
||||
* The trace() method must trace all of the class's fields.
|
||||
*/
|
||||
template <class T>
|
||||
class RootedGeneric : private CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
template <typename CX>
|
||||
explicit RootedGeneric(CX* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: CustomAutoRooter(cx)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
template <typename CX>
|
||||
explicit RootedGeneric(CX* cx, const T& initial MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: CustomAutoRooter(cx), value(initial)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
operator const T&() const { return value; }
|
||||
T operator->() const { return value; }
|
||||
|
||||
private:
|
||||
virtual void trace(JSTracer* trc) { value->trace(trc); }
|
||||
|
||||
T value;
|
||||
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
/* A handle to an array of rooted values. */
|
||||
class HandleValueArray
|
||||
{
|
||||
@ -1900,64 +1867,6 @@ JS_SetNativeStackQuota(JSRuntime* cx, size_t systemCodeStackSize,
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
extern JS_PUBLIC_API(int)
|
||||
JS_IdArrayLength(JSContext* cx, JSIdArray* ida);
|
||||
|
||||
extern JS_PUBLIC_API(jsid)
|
||||
JS_IdArrayGet(JSContext* cx, JSIdArray* ida, unsigned index);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_DestroyIdArray(JSContext* cx, JSIdArray* ida);
|
||||
|
||||
namespace JS {
|
||||
|
||||
class AutoIdArray : private AutoGCRooter
|
||||
{
|
||||
public:
|
||||
AutoIdArray(JSContext* cx, JSIdArray* ida
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: AutoGCRooter(cx, IDARRAY), context(cx), idArray(ida)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
~AutoIdArray() {
|
||||
if (idArray)
|
||||
JS_DestroyIdArray(context, idArray);
|
||||
}
|
||||
bool operator!() const {
|
||||
return !idArray;
|
||||
}
|
||||
jsid operator[](size_t i) const {
|
||||
MOZ_ASSERT(idArray);
|
||||
return JS_IdArrayGet(context, idArray, unsigned(i));
|
||||
}
|
||||
size_t length() const {
|
||||
return JS_IdArrayLength(context, idArray);
|
||||
}
|
||||
|
||||
friend void AutoGCRooter::trace(JSTracer* trc);
|
||||
|
||||
JSIdArray* steal() {
|
||||
JSIdArray* copy = idArray;
|
||||
idArray = nullptr;
|
||||
return copy;
|
||||
}
|
||||
|
||||
protected:
|
||||
inline void trace(JSTracer* trc);
|
||||
|
||||
private:
|
||||
JSContext* context;
|
||||
JSIdArray* idArray;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
/* No copy or assignment semantics. */
|
||||
AutoIdArray(AutoIdArray& ida) = delete;
|
||||
void operator=(AutoIdArray& ida) = delete;
|
||||
};
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_ValueToId(JSContext* cx, JS::HandleValue v, JS::MutableHandleId idp);
|
||||
|
||||
@ -3184,8 +3093,8 @@ JS_CreateMappedArrayBufferContents(int fd, size_t offset, size_t length);
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_ReleaseMappedArrayBufferContents(void* contents, size_t length);
|
||||
|
||||
extern JS_PUBLIC_API(JSIdArray*)
|
||||
JS_Enumerate(JSContext* cx, JS::HandleObject obj);
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_Enumerate(JSContext* cx, JS::HandleObject obj, JS::MutableHandle<JS::IdVector> props);
|
||||
|
||||
extern JS_PUBLIC_API(JS::Value)
|
||||
JS_GetReservedSlot(JSObject* obj, uint32_t index);
|
||||
|
@ -19,16 +19,6 @@
|
||||
class JSAtom;
|
||||
class JSAutoByteString;
|
||||
|
||||
struct JSIdArray {
|
||||
int length;
|
||||
js::HeapId vector[1]; /* actually, length jsid words */
|
||||
|
||||
js::HeapId* begin() { return vector; }
|
||||
const js::HeapId* begin() const { return vector; }
|
||||
js::HeapId* end() { return vector + length; }
|
||||
const js::HeapId* end() const { return vector + length; }
|
||||
};
|
||||
|
||||
namespace js {
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
|
||||
|
@ -1704,7 +1704,7 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
|
||||
}
|
||||
|
||||
AutoKeepAtoms keepAtoms(cx->perThreadData);
|
||||
AutoNameVector formals(cx);
|
||||
Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
|
||||
|
||||
bool hasRest = false;
|
||||
|
||||
|
@ -395,25 +395,6 @@ Snapshot(JSContext* cx, HandleObject pobj_, unsigned flags, AutoIdVector* props)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::VectorToIdArray(JSContext* cx, AutoIdVector& props, JSIdArray** idap)
|
||||
{
|
||||
JS_STATIC_ASSERT(sizeof(JSIdArray) > sizeof(jsid));
|
||||
size_t len = props.length();
|
||||
size_t idsz = len * sizeof(jsid);
|
||||
size_t sz = (sizeof(JSIdArray) - sizeof(jsid)) + idsz;
|
||||
JSIdArray* ida = reinterpret_cast<JSIdArray*>(cx->zone()->pod_malloc<uint8_t>(sz));
|
||||
if (!ida)
|
||||
return false;
|
||||
|
||||
ida->length = static_cast<int>(len);
|
||||
jsid* v = props.begin();
|
||||
for (int i = 0; i < ida->length; i++)
|
||||
ida->vector[i].init(v[i]);
|
||||
*idap = ida;
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
js::GetPropertyKeys(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVector* props)
|
||||
{
|
||||
|
@ -146,9 +146,6 @@ class StringIteratorObject : public JSObject
|
||||
static const Class class_;
|
||||
};
|
||||
|
||||
bool
|
||||
VectorToIdArray(JSContext* cx, AutoIdVector& props, JSIdArray** idap);
|
||||
|
||||
bool
|
||||
GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleObject objp);
|
||||
|
||||
|
@ -528,14 +528,13 @@ js::SetIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level)
|
||||
Reverse(shapes.begin(), shapes.end());
|
||||
|
||||
for (Shape* shape : shapes) {
|
||||
StackShape unrootedChild(shape);
|
||||
RootedGeneric<StackShape*> child(cx, &unrootedChild);
|
||||
child->attrs |= GetSealedOrFrozenAttributes(child->attrs, level);
|
||||
Rooted<StackShape> child(cx, StackShape(shape));
|
||||
child.setAttrs(child.attrs() | GetSealedOrFrozenAttributes(child.attrs(), level));
|
||||
|
||||
if (!JSID_IS_EMPTY(child->propid) && level == IntegrityLevel::Frozen)
|
||||
MarkTypePropertyNonWritable(cx, nobj, child->propid);
|
||||
if (!JSID_IS_EMPTY(child.get().propid) && level == IntegrityLevel::Frozen)
|
||||
MarkTypePropertyNonWritable(cx, nobj, child.get().propid);
|
||||
|
||||
last = cx->compartment()->propertyTree.getChild(cx, last, *child);
|
||||
last = cx->compartment()->propertyTree.getChild(cx, last, child);
|
||||
if (!last)
|
||||
return false;
|
||||
}
|
||||
@ -1360,9 +1359,8 @@ InitializePropertiesFromCompatibleNativeObject(JSContext* cx,
|
||||
Reverse(shapes.begin(), shapes.end());
|
||||
|
||||
for (Shape* shape : shapes) {
|
||||
StackShape unrootedChild(shape);
|
||||
RootedGeneric<StackShape*> child(cx, &unrootedChild);
|
||||
shape = cx->compartment()->propertyTree.getChild(cx, shape, *child);
|
||||
Rooted<StackShape> child(cx, StackShape(shape));
|
||||
shape = cx->compartment()->propertyTree.getChild(cx, shape, child);
|
||||
if (!shape)
|
||||
return false;
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ Shape::removeChild(Shape* child)
|
||||
}
|
||||
|
||||
Shape*
|
||||
PropertyTree::getChild(ExclusiveContext* cx, Shape* parentArg, StackShape& unrootedChild)
|
||||
PropertyTree::getChild(ExclusiveContext* cx, Shape* parentArg, Handle<StackShape> child)
|
||||
{
|
||||
RootedShape parent(cx, parentArg);
|
||||
MOZ_ASSERT(parent);
|
||||
@ -144,10 +144,10 @@ PropertyTree::getChild(ExclusiveContext* cx, Shape* parentArg, StackShape& unroo
|
||||
KidsPointer* kidp = &parent->kids;
|
||||
if (kidp->isShape()) {
|
||||
Shape* kid = kidp->toShape();
|
||||
if (kid->matches(unrootedChild))
|
||||
if (kid->matches(child))
|
||||
existingShape = kid;
|
||||
} else if (kidp->isHash()) {
|
||||
if (KidsHash::Ptr p = kidp->toHash()->lookup(unrootedChild))
|
||||
if (KidsHash::Ptr p = kidp->toHash()->lookup(child))
|
||||
existingShape = *p;
|
||||
} else {
|
||||
/* If kidp->isNull(), we always insert. */
|
||||
@ -181,7 +181,7 @@ PropertyTree::getChild(ExclusiveContext* cx, Shape* parentArg, StackShape& unroo
|
||||
if (existingShape)
|
||||
return existingShape;
|
||||
|
||||
Shape* shape = Shape::new_(cx, unrootedChild, parent->numFixedSlots());
|
||||
Shape* shape = Shape::new_(cx, child, parent->numFixedSlots());
|
||||
if (!shape)
|
||||
return nullptr;
|
||||
|
||||
|
@ -96,7 +96,7 @@ class PropertyTree
|
||||
|
||||
JSCompartment* compartment() { return compartment_; }
|
||||
|
||||
Shape* getChild(ExclusiveContext* cx, Shape* parent, StackShape& child);
|
||||
Shape* getChild(ExclusiveContext* cx, Shape* parent, Handle<StackShape> child);
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
@ -93,7 +93,6 @@ struct JSCrossCompartmentCall;
|
||||
class JSErrorReport;
|
||||
struct JSExceptionState;
|
||||
struct JSFunctionSpec;
|
||||
struct JSIdArray;
|
||||
struct JSLocaleCallbacks;
|
||||
struct JSObjectMap;
|
||||
struct JSPrincipals;
|
||||
@ -218,12 +217,10 @@ class JS_PUBLIC_API(AutoGCRooter)
|
||||
enum {
|
||||
VALARRAY = -2, /* js::AutoValueArray */
|
||||
PARSER = -3, /* js::frontend::Parser */
|
||||
IDARRAY = -6, /* js::AutoIdArray */
|
||||
VALVECTOR = -10, /* js::AutoValueVector */
|
||||
IDVECTOR = -11, /* js::AutoIdVector */
|
||||
OBJVECTOR = -14, /* js::AutoObjectVector */
|
||||
SCRIPTVECTOR =-16, /* js::AutoScriptVector */
|
||||
NAMEVECTOR = -17, /* js::AutoNameVector */
|
||||
IONMASM = -19, /* js::jit::MacroAssembler */
|
||||
WRAPVECTOR = -20, /* js::AutoWrapperVector */
|
||||
WRAPPER = -21, /* js::AutoWrapperRooter */
|
||||
|
@ -179,7 +179,7 @@ Bindings::initWithTemporaryStorage(ExclusiveContext* cx, MutableHandle<Bindings>
|
||||
unsigned attrs = JSPROP_PERMANENT |
|
||||
JSPROP_ENUMERATE |
|
||||
(bi->kind() == Binding::CONSTANT ? JSPROP_READONLY : 0);
|
||||
StackShape child(base, NameToId(bi->name()), slot, attrs, 0);
|
||||
Rooted<StackShape> child(cx, StackShape(base, NameToId(bi->name()), slot, attrs, 0));
|
||||
|
||||
shape = cx->compartment()->propertyTree.getChild(cx, shape, child);
|
||||
if (!shape)
|
||||
|
@ -4954,8 +4954,8 @@ Help(JSContext* cx, unsigned argc, Value* vp)
|
||||
RootedObject obj(cx);
|
||||
if (args.length() == 0) {
|
||||
RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
|
||||
AutoIdArray ida(cx, JS_Enumerate(cx, global));
|
||||
if (!ida)
|
||||
Rooted<IdVector> ida(cx, IdVector(cx));
|
||||
if (!JS_Enumerate(cx, global, &ida))
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < ida.length(); i++) {
|
||||
|
@ -669,7 +669,7 @@ GlobalObject::addIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
|
||||
Rooted<UnownedBaseShape*> base(cx, last->base()->unowned());
|
||||
|
||||
RootedId id(cx, NameToId(name));
|
||||
StackShape child(base, id, slot, 0, 0);
|
||||
Rooted<StackShape> child(cx, StackShape(base, id, slot, 0, 0));
|
||||
Shape* shape = cx->compartment()->propertyTree.getChild(cx, last, child);
|
||||
if (!shape)
|
||||
return false;
|
||||
|
@ -660,9 +660,9 @@ class NativeObject : public JSObject
|
||||
|
||||
private:
|
||||
static Shape* getChildPropertyOnDictionary(ExclusiveContext* cx, HandleNativeObject obj,
|
||||
HandleShape parent, StackShape& child);
|
||||
HandleShape parent, MutableHandle<StackShape> child);
|
||||
static Shape* getChildProperty(ExclusiveContext* cx, HandleNativeObject obj,
|
||||
HandleShape parent, StackShape& child);
|
||||
HandleShape parent, MutableHandle<StackShape> child);
|
||||
|
||||
public:
|
||||
/* Add a property whose id is not yet in this scope. */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user